File size: 1,750 Bytes
2276d59
62527b4
2276d59
 
 
 
 
62527b4
2276d59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
import { logger } from '../infra/logger.util.js';

// 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
  logger.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);
}