cleanup for readability

This commit is contained in:
Dave Horton
2023-04-16 18:33:25 -04:00
parent 04380bf82f
commit 859a8bb317
2 changed files with 25 additions and 49 deletions

View File

@@ -18,39 +18,23 @@ function secureCompare(a, b) {
return false;
}
// use crypto.timingSafeEqual if available (since Node.js v6.6.0),
// otherwise use our own scmp-internal function.
if (crypto.timingSafeEqual) {
return crypto.timingSafeEqual(a, b);
}
const len = a.length;
let result = 0;
for (let i = 0; i < len; ++i) {
result |= a[i] ^ b[i];
}
return result === 0;
}
function parseHeader(header, scheme) {
if (typeof header !== 'string') {
return null;
}
const keyActions = {
t: (accum, value) => (accum.timestamp = value, accum),
[scheme]: (accum, value) => (accum.signatures.push(value), accum)
};
return header.split(',').reduce(
(accum, item) => {
const kv = item.split('=');
if (kv[0] === 't') {
accum.timestamp = kv[1];
}
if (kv[0] === scheme) {
accum.signatures.push(kv[1]);
}
return accum;
const [key, value] = item.split('=');
return keyActions[key] ? keyActions[key](accum, value) : accum;
},
{
timestamp: -1,
@@ -93,7 +77,7 @@ class WebhookResponse {
static verifyJambonzSignature(secret) {
return (req, res, next) => {
const header = req.get('Jambonz-Signature');
if (!header) throw new Error(`missing Jambonz-Signature in ${req.url}`);
if (!header) throw new Error(`Missing Jambonz-Signature in ${req.url}`);
const details = parseHeader(header, EXPECTED_SCHEME);
if (!details || details.timestamp === -1) {
throw new Error('unable to extract timestamp and signatures from header');
@@ -105,9 +89,7 @@ class WebhookResponse {
let signatureFound = false;
for (const secret of secrets) {
const expectedSignature = computeSignature(req.body, details.timestamp, secret);
signatureFound = details.signatures.filter(
secureCompare.bind(null, expectedSignature)
).length > 0;
signatureFound = details.signatures.some((sig) => secureCompare(expectedSignature, sig));
if (signatureFound) break;
}
if (!signatureFound) {

View File

@@ -1,6 +1,19 @@
const assert = require('assert');
const parseurl = require('parseurl');
function matchesPath(match, path) {
if ('*' === match) return true;
const urlChunks = path.split('/').filter((c) => c.length);
const matchChunks = match.split('/').filter((c) => c.length);
if (urlChunks.length >= matchChunks.length) {
return matchChunks.every((chunk, idx) => chunk === urlChunks[idx]);
}
return false;
}
class WsRouter {
constructor() {
this.routes = [];
@@ -13,6 +26,7 @@ class WsRouter {
}
assert.ok(typeof callback === 'function' || callback instanceof WsRouter,
'WsRouter.use - callback must be a function or a WsRouter instance');
assert.ok(typeof match === 'string', 'WsRouter.use - match must be a string');
this.routes.push({match, callback});
}
@@ -22,27 +36,7 @@ class WsRouter {
const path = parsed.pathname;
const route = this.routes.find(({match}) => {
/* wildcard */
if ('*' === match) return true;
/* try matching by path */
const urlChunks = path.split('/').filter((c) => c.length);
const matchChunks = match.split('/').filter((c) => c.length);
if (urlChunks.length >= matchChunks.length) {
let idx = 0;
do {
if (urlChunks[idx] !== matchChunks[idx]) break;
idx++;
} while (idx < matchChunks.length);
if (idx > 0) {
req.url = urlChunks.slice(idx).join('/') + '/' + (parsed.search || '');
return true;
}
}
/* TODO: try matching by param */
/* TODO : try matching by query args */
return matchesPath(match, path);
});
if (!route) return false;