/**
 * HMAC-signed URLs for the local driver.
 *
 * Both upload and download are gated by a signature the server issued, so an
 * upload endpoint is never openly writable and a file key is never guessable
 * into a download. Signatures are bound to method + key + expiry.
 */
import { createHmac, timingSafeEqual } from 'node:crypto';
import { env } from '../config/env.js';
import { forbidden } from '../utils/errors.js';

type Method = 'GET' | 'PUT';

function digest(method: Method, key: string, exp: number): string {
  return createHmac('sha256', env.FILE_SIGNING_SECRET)
    .update(`${method}\n${key}\n${exp}`)
    .digest('base64url');
}

export function signFileUrl(method: Method, key: string, ttlSeconds: number) {
  const exp = Math.floor(Date.now() / 1000) + ttlSeconds;
  return { exp, sig: digest(method, key, exp) };
}

/** Throws unless the signature is valid and unexpired. */
export function verifyFileSignature(method: Method, key: string, exp: number, sig: string): void {
  if (!Number.isFinite(exp) || exp < Math.floor(Date.now() / 1000)) {
    throw forbidden('This link has expired');
  }
  const expected = Buffer.from(digest(method, key, exp));
  const provided = Buffer.from(String(sig));
  if (expected.length !== provided.length || !timingSafeEqual(expected, provided)) {
    throw forbidden('Invalid file signature');
  }
}
