UNPKG

trello-node-api

Version:
109 lines (85 loc) 3.01 kB
var crypto = require('crypto'); var utils = require('./utils'); var Error = require('./Error'); var Webhook = { DEFAULT_TOLERANCE: 300, constructEvent: function (payload, header, secret, tolerance) { var jsonPayload = JSON.parse(payload); this.signature.verifyHeader(payload, header, secret, tolerance || Webhook.DEFAULT_TOLERANCE); return jsonPayload; } }; var signature = { EXPECTED_SCHEME: 'v1', _computeSignature: function (payload, secret) { return crypto.createHmac('sha256', secret) .update(payload, 'utf8') .digest('hex'); }, verifyHeader: function (payload, header, secret, tolerance) { var details = parseHeader(header, this.EXPECTED_SCHEME); if (!details || details.timestamp === -1) { throw new Error.TrelloSignatureVerificationError({ message: 'Unable to extract timestamp and signatures from header', detail: { header: header, payload: payload } }); } if (!details.signatures.length) { throw new Error.TrelloSignatureVerificationError({ message: 'No signatures found with expected scheme', detail: { header: header, payload: payload } }); } var expectedSignature = this._computeSignature(details.timestamp + '.' + payload, secret); var signatureFound = !!details.signatures .filter(utils.secureCompare.bind(utils, expectedSignature)) .length; if (!signatureFound) { throw new Error.TrelloSignatureVerificationError({ message: 'No signatures found matching the expected signature for payload.' + ' Are you passing the raw request body you received from Trello?', detail: { header: header, payload: payload } }); } var timestampAge = Math.floor(Date.now() / 1000) - details.timestamp; if (tolerance > 0 && timestampAge > tolerance) { throw new Error.TrelloSignatureVerificationError({ message: 'Timestamp outside the tolerance zone', detail: { header: header, payload: payload } }); } return true; } }; function parseHeader(header, scheme) { if (typeof header !== 'string') { return null; } return header.split(',').reduce(function (accum, item) { var kv = item.split('='); if (kv[0] === 't') { accum.timestamp = kv[1]; } if (kv[0] === scheme) { accum.signatures.push(kv[1]); } return accum; }, { timestamp: -1, signatures: [] }); } Webhook.signature = signature; module.exports = Webhook;