nexstream-api / backend /src /utils /network /secrets.util.ts
nexstream-deploy
deploy: nexstream backend (experiment)
2276d59
Raw
History Blame Contribute Delete
1.7 kB
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
// per-boot secret unless pinned for restarts
const ENV_SECRET = process.env.PROXY_SIGNING_SECRET;
if (!ENV_SECRET && process.env.NODE_ENV !== 'test') {
// random secret invalidates signed urls on restart
console.warn(
'[Secrets] PROXY_SIGNING_SECRET unset; signed URLs will break on restart.'
);
}
const SECRET = ENV_SECRET || randomBytes(32).toString('hex');
// cdn links die ~6h; match that
const TTL_MS = (Number(process.env.PROXY_URL_TTL_SECONDS) || 21600) * 1000;
interface ProxyParams {
targetUrl?: string;
rawUrl?: string;
formatId?: string;
}
function canonical(params: ProxyParams, exp: number): string {
return [
params.targetUrl || '',
params.rawUrl || '',
params.formatId || '',
exp,
].join('\n');
}
export function signProxyParams(params: ProxyParams): {
exp: number;
sig: string;
} {
const exp = Date.now() + TTL_MS;
const sig = createHmac('sha256', SECRET)
.update(canonical(params, exp))
.digest('base64url');
return { exp, sig };
}
export function verifyProxyParams(
params: ProxyParams & { exp: number; sig: string | undefined }
): boolean {
if (!params.sig || !Number.isFinite(params.exp)) return false;
// reject stale links
if (Date.now() > params.exp) return false;
const expected = createHmac('sha256', SECRET)
.update(canonical(params, params.exp))
.digest('base64url');
const expectedBuf = Buffer.from(expected);
const providedBuf = Buffer.from(params.sig);
// length guard before timing-safe compare
if (expectedBuf.length !== providedBuf.length) return false;
return timingSafeEqual(expectedBuf, providedBuf);
}