← back to NationalPaperHangers

lib/booking-token.js

34 lines

// HMAC-signed booking-view token. Embedded in confirmation-email URLs so that
// the booking detail page (/bookings/:uuid?t=...) cannot be enumerated by
// guessing UUIDs. The signing key is BOOKING_SIGNING_SECRET, falling back to
// SESSION_SECRET (which throws in production if unset).

const crypto = require('crypto');

function getKey() {
  const k = process.env.BOOKING_SIGNING_SECRET || process.env.SESSION_SECRET;
  if (!k || k === 'dev-secret-change-me') {
    if (process.env.NODE_ENV === 'production') {
      throw new Error('BOOKING_SIGNING_SECRET (or SESSION_SECRET) must be set in production');
    }
  }
  return k || 'dev-only-not-for-prod';
}

function sign(uuid) {
  return crypto.createHmac('sha256', getKey()).update(String(uuid)).digest('base64url').slice(0, 24);
}

function verify(uuid, supplied) {
  if (!uuid || !supplied) return false;
  const expected = sign(uuid);
  if (expected.length !== supplied.length) return false;
  try {
    return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(supplied));
  } catch {
    return false;
  }
}

module.exports = { sign, verify };