Files
HealthLog/src/lib/auth/hmac.ts
T
Marc-André Bombeck d7bf0df10b chore(ci): pin the supply chain and surface build provenance
Every workflow action is pinned to a commit SHA, dependabot auto-merge
is limited to patch and minor updates behind the now-required status
checks on main, and the audit, Trivy and ESLint gates block instead of
warning. The published image finally carries its build SHA and build
timestamp so the version endpoint can prove which commit is running.
The API-token HMAC key fails closed under 32 characters, compose pins
the database minor and denies privilege escalation, and the changelog
drops working-note references in favour of neutral wording.
2026-06-10 15:05:05 +02:00

51 lines
1.5 KiB
TypeScript

import { createHmac, timingSafeEqual } from "node:crypto";
/**
* Verify HMAC-SHA256 signature for external ingest.
* Signature format: "sha256=<hex>"
* The signature is computed over the raw request body using the API token as the key.
*/
export function verifyHmacSignature(
body: string,
signature: string,
secret: string,
): boolean {
const prefix = "sha256=";
if (!signature.startsWith(prefix)) return false;
const receivedHex = signature.slice(prefix.length);
const expectedHex = createHmac("sha256", secret).update(body).digest("hex");
try {
return timingSafeEqual(
Buffer.from(receivedHex, "hex"),
Buffer.from(expectedHex, "hex"),
);
} catch {
return false;
}
}
/**
* Hash an API token for storage (SHA-256).
* Requires API_TOKEN_HMAC_KEY env var to be set and at least 32
* characters long. Fail-closed like the encryption-key loader in
* `src/lib/crypto.ts`: a weak key throws instead of silently keying
* every Bearer-token hash off guessable material.
*/
const MIN_HMAC_KEY_LENGTH = 32;
export function hashToken(token: string): string {
const key = process.env.API_TOKEN_HMAC_KEY;
if (!key) {
throw new Error("API_TOKEN_HMAC_KEY env var must be set");
}
if (key.length < MIN_HMAC_KEY_LENGTH) {
throw new Error(
`API_TOKEN_HMAC_KEY must be at least ${MIN_HMAC_KEY_LENGTH} characters, got ${key.length}. ` +
"Generate a strong key with `openssl rand -hex 32` and update the environment before restarting.",
);
}
return createHmac("sha256", key).update(token).digest("hex");
}