import { createHmac, timingSafeEqual } from 'node:crypto' import { config } from '../config.js' /** * Signierte Datei-Links fuer das Ticketsystem (Spec 2026-10-01, Abschnitt 4 "Dateien ohne Header"): , * und Downloads koennen keinen Authorization-Header tragen. Der Link gilt 15 Minuten und nur fuer genau diese * Datei dieses Kunden; signiert mit dem Sitzungs-Geheimnis des Portals. */ export const FILE_LINK_TTL_MS = 15 * 60 * 1000 const digest = (kind, customerId, id, exp) => createHmac('sha256', config.sessionSecret).update(`${kind}:${customerId}:${id}:${exp}`).digest('hex') export function signFileLink({ kind, customerId, id, now = Date.now() }) { const exp = now + FILE_LINK_TTL_MS return { exp, sig: digest(kind, customerId, id, exp) } } /** exp kommt aus der Adresse (Text oder Zahl); falsch bei Ablauf, fremder Datei oder kaputter Signatur. */ export function verifyFileLink({ kind, customerId, id, exp, sig, now = Date.now() }) { const expiry = typeof exp === 'number' ? exp : /^\d+$/.test(String(exp ?? '')) ? Number(exp) : NaN if (!Number.isFinite(expiry) || now >= expiry) return false if (typeof sig !== 'string' || !/^[0-9a-f]{64}$/.test(sig)) return false const expected = Buffer.from(digest(kind, customerId, id, expiry), 'hex') const given = Buffer.from(sig, 'hex') return given.length === expected.length && timingSafeEqual(given, expected) }