PayPal Webhook集成(PAYMENT.SALE.COMPLETED)与Node Express

时间:2019-02-10 19:07:30

标签: node.js express paypal paypal-sandbox

这与以下问题类似:Verify Paypal Restful Webhook Signature in Java,但是在Node中而不是Java中。

我无法获得经过计算的签名,以匹配PayPal通过webhook回调发送给我的信息。我意识到有一个带有getAndVerify函数的PayPal Node SDK,但是我正在尝试编写自己的。到目前为止,这是我的代码。

/* 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 = {};

除签名不匹配外,一切检查正常

0 个答案:

没有答案