Como validar uma assinatura de webhook do PayPal para o Google Script?

Oct 10 2020

Depois que um pedido do PayPal é concluído, ele envia um webhook para um URL de script do Google. Antes de a informação ser enviada, ela deve validar a assinatura. Abaixo está um link para um exemplo de Java.

https://developer.paypal.com/docs/api-basics/notifications/webhooks/notification-messages/#

Como validar uma assinatura de webhook do PayPal para o Google Script?

Procurei uma solução no google-apps-script e nas tags do PayPal, mas ele fornece apenas soluções IPN. Pelo que entendi, esse é um método mais antigo. Talvez seja a única maneira. Não sei. Eu sou novo no manuseio de API, então posso estar formulando o problema incorretamente.

EDIT: Fiz mais algumas pesquisas e foi capaz de receber e processar um webhook paypal.

function doPost(e) {
    var params = JSON.stringify(e.postData.contents);
    params = JSON.parse(params);
    var myData = JSON.parse(e.postData.contents);

    SpreadsheetApp.flush();
    return HtmlService.createHtmlOutput("post request received");
}

O próximo problema é configurar o botão PayPal Smart para enviar o webhook correto. O evento de webhook correto seria "Pedido de checkout concluído" (testado por meio do simulador de Webhooks do PayPal). Este webhook contém as informações do pedido. Os exemplos na Demonstração do botão inteligente do PayPal chama onAuthorize como um webhook. Este webhook não contém as informações que desejo. Vou fazer uma postagem separada sobre isso.

onAuthorize: function(data, actions) {
        return actions.payment.execute().then(function() {
            window.alert('Payment Complete!');
        });
    }

Portanto, acho que nenhuma validação é necessária para webhooks, talvez.

Respostas

PrestonPHX Oct 10 2020 at 23:31

IPN é uma solução muito mais antiga separada dos webhooks.

Com relação à verificação de webhook, você vinculou a uma página de verificação DIY, onde você calcula se a assinatura corresponde. O exemplo está em Java, mas pode ser adaptado para qualquer linguagem (com algum trabalho considerável)

A forma alternativa de verificar um webhook é por meio da API de webhooks, postando a mensagem de volta usando esta chamada de API: https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature

Evite usar os SDKs do PayPal - * -, uma vez que essa documentação foi escrita antes de esses SDKs serem preteridos

JulianMains Oct 12 2020 at 22:42

Depois de muita tentativa e erro, obtive um sistema semifuncional.

function doPost(e) {
    SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Debug').getRange('A1').setValue("Recieved doPostCommand");

    var myData = JSON.parse(e.postData.contents);

    try {
        if (myData.event_type == 'PAYMENTS.PAYMENT.CREATED') {
            var email = myData.resource.payer.payer_info.email
            var name = myData.resource.payer.payer_info.first_name + " " + myData.resource.payer.payer_info.last_name
            var payID = myData.resource.id
  
            SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Debug').getRange('A3').setValue(email);
            SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Debug').getRange('A4').setValue(name);
            SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Debug').getRange('A5').setValue(payID);
        } else if (myData.event_type == 'PAYMENT.SALE.COMPLETED'){
            var payID = myData.resource.parent_payment

            SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Debug').getRange('A7').setValue(payID);
        } 
    } catch (e) {
        SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Debug').getRange('E1').setValue("Error: " + e);
    }

  SpreadsheetApp.flush();
  return HtmlService.createHtmlOutput("post request received");
}

Descobri que os webhooks funcionam algumas vezes. Às vezes eles falharam, enquanto outras vezes são recebidos. Quando são recebidos, os webhooks não chegam necessariamente em uma ordem específica.

Portanto, para confirmar a conclusão do pagamento, anexe os detalhes do cliente (incluindo ID do PayPal) a uma folha de "cliente". Em uma folha separada de "ID de pagamento confirmado", anexe os IDs do PayPal. A partir daí, adicione um ouvinte para quando um webhook PAYMENTS.PAYMENT.CREATED ou PAYMENT.SALE.COMPLETED for recebido, verifique se há IDs do PayPal correspondentes. A folha de "identificação de pagamento confirmada" funcionará como um buffer. A partir daí, defina a coluna de pagamento concluído como verdadeiro para o cliente correto e exclua o ID do PayPal da planilha intermediária.

É assim que eu faria, mas os webhooks parecem ser um lixo eletrônico. Vou ter que recorrer a algum serviço de comércio eletrônico. Espero que alguém ache isso útil. Saúde