import type { SelfHostedIdentityConfig } from "./config.ts"; export type IdentityRequestHandler = ( request: Request, ) => Response | Promise; export interface IdentityAuthHandlers { GET: IdentityRequestHandler; POST: IdentityRequestHandler; } export function normalizeIdentityHost(value: string | null): string | null { if (!value || value !== value.trim() || /[\s,@/\\]/.test(value)) return null; try { const url = new URL(`https://${value}`); if ( url.username || url.password || url.pathname !== "/" || url.search || url.hash ) { return null; } return url.host.toLowerCase(); } catch { return null; } } export function resolveIdentitySurface( hostHeader: string | null, config: SelfHostedIdentityConfig, ): "user" | "admin" | null { const host = normalizeIdentityHost(hostHeader); if (!host) return null; if (host === new URL(config.userOrigin).host.toLowerCase()) return "user"; if (host === new URL(config.adminOrigin).host.toLowerCase()) return "admin"; return null; } function isAdminEndpoint(request: Request): boolean { try { const path = decodeURIComponent(new URL(request.url).pathname); return /^\/api\/auth\/+admin(?:\/|$)/i.test(path); } catch { return true; } } export function createHostIsolatedAuthHandlers( config: SelfHostedIdentityConfig, handlers: { user: IdentityAuthHandlers }, ): IdentityAuthHandlers { const dispatch = (method: keyof IdentityAuthHandlers): IdentityRequestHandler => async (request) => { const surface = resolveIdentitySurface(request.headers.get("host"), config); if (!surface) { return new Response("Unrecognized identity host", { status: 421 }); } if (surface === "user" && isAdminEndpoint(request)) { return new Response("Not found", { status: 404 }); } return handlers.user[method](request); }; return { GET: dispatch("GET"), POST: dispatch("POST") }; }