这与以下问题类似: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 = {};
除签名不匹配外,一切检查正常