Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Readme

Middleware to ensure the signed request is valid.

export default chain() .then(add(requireValidHmacSignature({ // The secret value shared between you and the originating party signingKey: "my_super_secret_key", // The name of the header containing the signature to compare with our value signatureHeaderName: "x-signature", }))) .then(send())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import { HttpMiddleware } from "https://esm.town/v/emarref/HttpMiddleware";
import { forbidden } from "https://esm.town/v/emarref/HttpResponse";
import { Buffer } from "node:buffer";
import { createHmac, timingSafeEqual } from "node:crypto";
type HmacFactory = typeof createHmac;
type Hmac = ReturnType<HmacFactory>;
type DigestFunction = Hmac["digest"];
type Algorithm = Parameters<HmacFactory>[0];
type Encoding = Parameters<DigestFunction>[0];
type Options = {
signingKey: string;
signatureHeaderName: string;
algorithm?: Algorithm;
encoding?: Encoding;
};
export function requireValidHmacSignature({
algorithm = "sha256",
encoding = "base64",
signatureHeaderName,
signingKey,
}: Options): HttpMiddleware {
return function(next) {
return async function(request) {
const providedSignature = request.headers.get(signatureHeaderName) ?? "";
const body = await request.text();
const calculatedSignature = createHmac(algorithm, signingKey).update(body).digest(encoding);
if (!timingSafeEqual(Buffer.from(providedSignature), Buffer.from(calculatedSignature))) {
console.warn("Signatures do not match.");
throw forbidden();
}
console.debug("Signature is valid.");
return next(request);
};
};
}
June 14, 2024