Files
outline/server/utils/csrf.ts
Tom Moor 0a9bd39aac Add CSRF middleware (#10051)
ref OUT-Q325-03
2025-08-31 06:35:35 -04:00

56 lines
1.6 KiB
TypeScript

import { randomBytes, createHmac } from "crypto";
import { safeEqual } from "./crypto";
/**
* Generates cryptographically secure random bytes
*
* @param size The number of bytes to generate
* @returns A buffer containing random bytes
*/
export const generateRawToken = (size: number): Buffer => randomBytes(size);
/**
* Creates an HMAC-SHA256 signature for a token
*
* @param token The token to sign
* @param secret The secret key for signing
* @returns The HMAC signature as a hex string
*/
export const signToken = (token: Buffer, secret: string): string =>
createHmac("sha256", secret).update(token).digest("hex");
/**
* Bundles a token with its HMAC signature
*
* @param token The raw token
* @param secret The secret key for signing
* @returns A string containing the token and signature separated by a dot
*/
export const bundleToken = (token: Buffer, secret: string): string => {
const sig = signToken(token, secret);
return `${token.toString("hex")}.${sig}`;
};
/**
* Unbundles and verifies a token with its HMAC signature
*
* @param bundled The bundled token string
* @param secret The secret key for verification
* @returns An object indicating validity and the raw token if valid
*/
export const unbundleToken = (
bundled: string,
secret: string
): { valid: boolean; raw?: Buffer } => {
const [hex, sig] = bundled.split(".");
if (!hex || !sig) {
return { valid: false };
}
const token = Buffer.from(hex, "hex");
const expected = signToken(token, secret);
const valid = safeEqual(sig, expected);
return { valid, raw: valid ? token : undefined };
};