Интеграция PayPal с веб-крючком (PAYMENT.SALE.COMPLETED) с помощью экспресс-узла - PullRequest
0 голосов
/ 10 февраля 2019

Этот вопрос похож на: Проверка подписи Paypal Restful Webhook на Java , но на узле вместо Java.

Я не могу получить вычисленную подпись, совпадающую с PayPalотправив меня через обратный звонок через webhook.Я понимаю, что есть PayPal Node SDK с функцией getAndVerify, но я пытаюсь написать свой собственный.Вот мой код.

/* Paypal webhook callback */
app.post('/api/v1/paypal/payment/complete', async (req, res) => {

  // Express parses headers into lower case
  var transmissionId = req.headers['paypal-transmission-id'];
  var transmissionSig = req.headers['paypal-transmission-sig'];
  var authAlgo = req.headers['paypal-auth-algo'];
  var certUrl = req.headers['paypal-cert-url'];
  var timeStamp = req.headers['paypal-transmission-time'];

  // Also tried the string version: crc32.str(req.rawBody);
  var crcDigest = crc32.buf(req.rawBodyBuffer);

  // Defined by PayPal when I configured the webhook. I double checked it's right.
  var webHookId = process.env.WEBHOOK_ID;

  try {
    var parsedCertUrl = url.parse(certUrl);
  } catch ( error ) {
    res.status(401).send("UNAUTHORIZED");
    return;
  }

  if(!parsedCertUrl.hostname || parsedCertUrl.hostname.slice(-10) !== "paypal.com") {
    res.status(401).send("UNAUTHORIZED");
    return;
  }

  if(req.body.event_type !== "PAYMENT.SALE.COMPLETED") {
    res.status(401).send("UNAUTHORIZED");
    return;
  }

  if(authAlgo !== "SHA256withRSA") {
    res.status(401).send("UNAUTHORIZED");
    return;
  }

  var checksumInput = `${transmissionId}|${timeStamp}|${webHookId}|${crcDigest}`;

  if(!paypalCerts[certUrl]) {
    try {
      const response = await fetch(certUrl);
      paypalCerts[certUrl] = await response.text();
    } catch(error) {
      console.log("CertUrl was unreachable!", certUrl, error);
    }
  }

  var checksumInputBuffer = Buffer.from(checksumInput, 'utf8');
  var encrypted = crypto.publicEncrypt(paypalCerts[certUrl], checksumInputBuffer);
  var checksum = encrypted.toString("base64");

  if(checksum !== transmissionSig) {
    console.log("Signatures do not match!", checksum, transmissionSig);
    res.status(401).send("UNAUTHORIZED");
    return;
  }

  console.log("Paypal trasmission successfully verified!");

  res.send("OK");
});

Наверху, просто чтобы прояснить:

const url = require('url');
const crc32 = require('crc-32');
const fetch = require('node-fetch');
var crypto = require("crypto");

/* Save the raw body */
var rawBodySaver = function (req, res, buf, encoding) {
  if (buf && buf.length) {
    req.rawBody = buf.toString(encoding || 'utf8');
    req.rawBodyBuffer = buf;
  }
}

app.use(bodyParser.json({ verify: rawBodySaver }));
app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' }));

var paypalCerts = {};

Все в порядке, кроме подписей, не совпадающих

...