Por alguna razón me sale
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined de ambos argumentos a crypto.timingSafeEqual(a, b) .
yo tambien he probado
const a = Buffer.from(signature, 'utf8').toString('base64'); const b = Buffer.from(expectedSignature, 'utf8').toString('base64');y me sale el mismo error.
Pregunta
¿Alguien puede averiguar por qué los argumentos no son Buffers?
const express = require("express"); const bodyParser = require("body-parser"); const crypto = require('crypto'); const secret = "x"; const app = express(); const PORT = 8080; app.use(bodyParser.json()); function isSigOk(request, secret) { // calculate the signature const expectedSignature = "sha256=" + crypto.createHmac("sha256", secret) .update(JSON.stringify(request.body)) .digest("hex"); // compare the signature against the one in the request const signature = request.headers["X-Hub-Signature-256"]; const a = Buffer.from(signature); const b = Buffer.from(expectedSignature); return crypto.timingSafeEqual(a, b); }; app.post("/", (req, res) => { if (isSigOk(req, secret)) { // Do stuff here } else { console.log('Error: Signatures does not match. Return res.status(401)'); }; res.status(200).end(); }); // Start express on the defined port app.listen(PORT, () => console.log(`Github wekhook listening on port ${PORT}`));Veo dos problemas:
La primera y principal es que isSigOk asume que habrá un valor para el encabezado "X-Hub-Signature-256" :
const signature = request.headers["X-Hub-Signature-256"]; const a = Buffer.from(signature); Esa llamada Buffer.from arrojará el error que ha citado si signature no está undefined porque el encabezado no está allí. Probablemente desee devolver false en ese caso (y probablemente omita la sobrecarga de calcular la firma esperada reordenando un poco las cosas), consulte los comentarios *** y las líneas asociadas:
function isSigOk(request, secret) { // *** get the signature on this message, if any const signature = request.headers["X-Hub-Signature-256"]; if (!signature) { // *** none return false; } // calculate the signature const expectedSignature = "sha256=" + crypto.createHmac("sha256", secret) .update(JSON.stringify(request.body)) .digest("hex"); // compare the signature against the one in the request const a = Buffer.from(signature); const b = Buffer.from(expectedSignature); return crypto.timingSafeEqual(a, b); }; La capitalización importa. De acuerdo con la documentación de Node.js (el objeto Requset de Express se hereda del IncomingMessage de Node.js), los nombres de los encabezados en los headers están en minúsculas. Entonces request.headers["X-Hub-Signature-256"] debería ser request.headers["x-hub-signature-256"] . (En un comentario, dice que estaba obteniendo un valor, pero el comentario usaba todo en minúsculas, mientras que el código usa mayúsculas y minúsculas). Entonces:
function isSigOk(request, secret) { // *** get the signature on this message, if any const signature = request.headers["x-hub-signature-256"]; // *** Lowercase if (!signature) { // *** none return false; } // calculate the signature const expectedSignature = "sha256=" + crypto.createHmac("sha256", secret) .update(JSON.stringify(request.body)) .digest("hex"); // compare the signature against the one in the request const a = Buffer.from(signature); const b = Buffer.from(expectedSignature); return a.length === b.length && crypto.timingSafeEqual(a, b); }; Tenga en cuenta la a.length === b.length && de eso. timingSafeEqual arrojará un error si los búferes no tienen la misma longitud, pero queremos devolver falso en esa situación.