import { createHmac } from 'node:crypto'; const RELAY_TOKEN_CONTEXT = 'officer-browser-relay-v1'; const { JWT_SECRET } = process.env; if (!JWT_SECRET) { throw new Error('JWT_SECRET is required for browser relay auth'); } export function deriveRelayToken(userId: number, port: number, salt: string): string { return createHmac('sha256', JWT_SECRET!) .update(`${RELAY_TOKEN_CONTEXT}:${port}:${userId}:${salt}`) .digest('hex'); } const tokenToUser = new Map(); export function registerUserToken(userId: number, port: number, salt: string): string { const token = deriveRelayToken(userId, port, salt); tokenToUser.set(token, userId); return token; } export function unregisterUserToken(token: string): void { tokenToUser.delete(token); } export function restoreUserTokens(entries: Array<{ userId: number; salt: string }>, port: number): void { for (const { userId, salt } of entries) { const token = deriveRelayToken(userId, port, salt); tokenToUser.set(token, userId); } } export function resolveUserFromToken(token: string): number | null { return tokenToUser.get(token) ?? null; } export function getRelayAuthHeader(): string { return 'x-officer-relay-token'; }