import { MeResponseSchema, PatCreateResponseSchema } from "@/worker/openapi/schemas"; import { completeOidcLogin } from "@tests/worker/helpers/auth"; import { controlRequest, fetchWorker, subjectRequest } from "@tests/worker/helpers/http"; export interface DavFixture { subjectId: string; hostLabel: string; token: string; authHeader: string; } export function basicPat(token: string): string { return `Basic ${btoa(`dav:${token}`)}`; } export async function createDavFixture(scopes: string[] = ["files.full"]): Promise { const login = await completeOidcLogin(); const meResponse = await fetchWorker(controlRequest("/api/v1/me", { headers: { cookie: login.sessionCookie } })); const me = MeResponseSchema.parse(await meResponse.json()); const patResponse = await fetchWorker( controlRequest("/api/v1/pats", { method: "POST", headers: { cookie: login.sessionCookie, origin: "https://dav.example.com", "content-type": "application/json", }, body: JSON.stringify({ name: "dav fixture", scopes }), }), ); const pat = PatCreateResponseSchema.parse(await patResponse.json()); return { subjectId: me.subject_id, hostLabel: me.host_label, token: pat.token, authHeader: basicPat(pat.token) }; } export function davRequest(fixture: DavFixture, path: string, init: RequestInit = {}): Request { const headers = new Headers(init.headers); headers.set("authorization", fixture.authHeader); // PUTs against CalDAV/CardDAV object URIs need an explicit media type; real // clients always send one. Default it here so individual tests don't have to. if ((init.method ?? "GET").toUpperCase() === "PUT" && !headers.has("content-type")) { if (path.startsWith("/calendars/") && /\.ics$/.test(path)) { headers.set("content-type", "text/calendar; charset=utf-8"); } else if (path.startsWith("/addressbooks/") && /\.vcf$/.test(path)) { headers.set("content-type", "text/vcard; charset=utf-8"); } } return subjectRequest(fixture.hostLabel, path, { ...init, headers }); }