@@ -4,12 +4,14 @@ import { createPublicKey, timingSafeEqual, verify } from "node:crypto";
44
55import { env } from "~/env" ;
66
7- // Signature validity window.
7+ // Signature validity window, evaluated lazily so tests can override env via
8+ // `vi.doMock('~/env')` without depending on module-load timing.
89// Dev: 30 days — allows reusing a generated signature across a working session
910// without constantly re-signing while debugging locally.
1011// Preprod / prod: 30 seconds — tight anti-replay window.
11- const SIGNATURE_WINDOW_SECONDS =
12- env . NEXT_PUBLIC_EGAPRO_ENV === "dev" ? 30 * 24 * 60 * 60 : 30 ;
12+ function getSignatureWindowSeconds ( ) : number {
13+ return env . NEXT_PUBLIC_EGAPRO_ENV === "dev" ? 30 * 24 * 60 * 60 : 30 ;
14+ }
1315
1416// Cache the public key at module level — parsed once, reused on every request.
1517const suitPublicKey = ( ( ) => {
@@ -65,8 +67,8 @@ export function verifySuitApiKey(request: Request): true | Response {
6567 * SUIT signs `{timestamp}|{METHOD}|{pathname}` with its RSA private key.
6668 * The app verifies:
6769 * 1. The signature matches using SUIT's public key (EGAPRO_SUIT_PUBLIC_KEY_PEM)
68- * 2. The timestamp is within `SIGNATURE_WINDOW_SECONDS` (anti-replay — 30s
69- * in preprod/prod, 30d in dev)
70+ * 2. The timestamp is within the signature window (anti-replay — 30s in
71+ * preprod/prod, 30d in dev, cf. `getSignatureWindowSeconds` )
7072 *
7173 * Only active when `EGAPRO_SUIT_PUBLIC_KEY_PEM` is set. When absent, signature
7274 * verification is skipped (dev / environments without keys).
@@ -87,7 +89,7 @@ export function verifySuitSignature(request: Request): true | Response {
8789 }
8890
8991 const now = Math . floor ( Date . now ( ) / 1000 ) ;
90- if ( Math . abs ( now - ts ) > SIGNATURE_WINDOW_SECONDS ) {
92+ if ( Math . abs ( now - ts ) > getSignatureWindowSeconds ( ) ) {
9193 return forbiddenResponse ( ) ;
9294 }
9395
0 commit comments