import type { Context, CookieOptions } from "@wrnexus/core"; import { SecurityError } from "./errors.ts"; export interface SecureCookieOptions extends CookieOptions { hostOnly?: boolean; } export function secureCookieOptions( ctx: Pick, options: SecureCookieOptions = {}, ): CookieOptions { const secure = options.secure ?? ctx.url.protocol === "https:"; const sameSite = options.sameSite ?? "Lax"; if (sameSite.toString().toLowerCase() === "none" && !secure) { throw new SecurityError( "WRN-SEC-COOKIE-SAMESITE", "SameSite=None cookies must also use Secure.", ); } if (options.hostOnly && options.domain) { throw new SecurityError("WRN-SEC-COOKIE-HOST", "Host-only cookies cannot set Domain."); } return { path: options.path ?? "/", ...options, domain: options.hostOnly ? undefined : options.domain, httpOnly: options.httpOnly ?? true, secure, sameSite, }; } export function setSecureCookie( ctx: Pick, name: string, value: string, options: SecureCookieOptions = {}, ): void { if (name.startsWith("__Host-") && (options.domain || (options.path && options.path !== "/"))) { throw new SecurityError( "WRN-SEC-COOKIE-HOST-PREFIX", "__Host- cookies require Path=/ and must not set Domain.", ); } ctx.cookies.set( name, value, secureCookieOptions(ctx, { ...options, hostOnly: name.startsWith("__Host-") || options.hostOnly, path: name.startsWith("__Host-") ? "/" : options.path, secure: name.startsWith("__Host-") ? true : options.secure, }), ); }