import { error } from '@sveltejs/kit'; // The site has exactly one owner: Stan's account (prod auth.user id tfn6OZDOpiQvMARIH65HQ2XJuaVvmGEe). // Owner-only data, such as the health tracker, is gated on that account's email, not on // a role, so other users (now or later, e.g. on a public tracking project) never see it. // Override with OWNER_EMAIL if the address ever changes. const OWNER_EMAIL = (process.env.OWNER_EMAIL || 'stan@stanrunge.dev').trim().toLowerCase(); type OwnerEvent = { locals: App.Locals }; export function isOwner(event: OwnerEvent): boolean { return event.locals.user?.email?.trim().toLowerCase() === OWNER_EMAIL; } /** Owner-only routes answer 404 to everyone else, so they don't reveal that they exist. */ export function requireOwner(event: OwnerEvent) { if (!isOwner(event)) error(404, 'Not Found'); return event.locals.user!; } /** Paths that only the owner may see (checked in hooks.server.ts before any route runs). */ export const ownerOnlyPrefixes = [ '/trackers/health', '/trackers/tasks', '/trackers/books/files', '/lists/db' ] as const; /** * Owner-only paths inside otherwise public areas: the book reader and its progress/notes * APIs. /trackers/books and /trackers/books/ themselves are public catalogue pages. */ export const ownerOnlyPatterns = [/^\/trackers\/books\/\d+\/(read|progress|notes)(\/|$)/] as const; /** * Areas where only the owner may write: any non-GET request from anyone else is refused * (404) in hooks.server.ts, which also covers form actions on the public book pages. */ export const ownerWritePrefixes = [ '/trackers/health', '/trackers/tasks', '/trackers/books' ] as const; const normalise = (pathname: string) => pathname.toLowerCase().replace(/\/+$/, ''); const under = (path: string, prefix: string) => path === prefix || path.startsWith(`${prefix}/`); export function isOwnerOnlyPath(pathname: string): boolean { const path = normalise(pathname); return ( ownerOnlyPrefixes.some((prefix) => under(path, prefix)) || ownerOnlyPatterns.some((pattern) => pattern.test(path)) ); } export function isOwnerWritePath(pathname: string): boolean { const path = normalise(pathname); return ownerWritePrefixes.some((prefix) => under(path, prefix)); }