/** * Shared MFA constants/helpers used by both server and client code. * * The WebAuthn Relying Party ID is fixed to the registrable suffix * `linumiq.net` so the same passkey works across `app-dev.linumiq.net` and * `app.linumiq.net`. The RP origin is derived from NEXT_PUBLIC_APP_URL so each * environment supplies its own concrete origin at challenge time. */ export const MFA_RP_ID = 'linumiq.net'; /** Origin (scheme + host) of this environment's app, from NEXT_PUBLIC_APP_URL. */ export function getAppOrigin(): string { const raw = process.env.NEXT_PUBLIC_APP_URL; if (raw) { try { return new URL(raw).origin; } catch { // fall through to the localhost default } } return 'http://localhost:3000'; } /** * Whitelist a `next` redirect target to same-origin relative paths only * (open-redirect guard). Anything else falls back to /dashboard. */ export function safeNextPath(raw: string | null | undefined): string { if (!raw || !raw.startsWith('/') || raw.startsWith('//')) { return '/dashboard'; } return raw; }