diff --git a/server.ts b/server.ts index 9550bb5..56448c0 100644 --- a/server.ts +++ b/server.ts @@ -19,13 +19,25 @@ type AuthCtx = { response: { status: number; body: unknown }; }; +let authenticator: typeof authenticateRequest = authenticateRequest; + +export const _setAuthenticatorForTest = ( + fn: typeof authenticateRequest, +): void => { + authenticator = fn; +}; + +export const _resetAuthenticatorForTest = (): void => { + authenticator = authenticateRequest; +}; + const requireDidOwnership = async ( ctx: AuthCtx, did: string, ): Promise => { let verifiedDid: string; try { - verifiedDid = await authenticateRequest( + verifiedDid = await authenticator( ctx.request.headers.get("Authorization"), ); } catch { @@ -41,17 +53,18 @@ const requireDidOwnership = async ( return true; }; -const ADMIN_DIDS = new Set( - (Deno.env.get("ADMIN_DIDS") ?? "") - .split(",") - .map((d) => d.trim()) - .filter(Boolean), -); +const adminDids = (): Set => + new Set( + (Deno.env.get("ADMIN_DIDS") ?? "") + .split(",") + .map((d) => d.trim()) + .filter(Boolean), + ); const requireAdmin = async (ctx: AuthCtx): Promise => { let verifiedDid: string; try { - verifiedDid = await authenticateRequest( + verifiedDid = await authenticator( ctx.request.headers.get("Authorization"), ); } catch { @@ -59,7 +72,7 @@ const requireAdmin = async (ctx: AuthCtx): Promise => { ctx.response.body = { error: "Unauthorized" }; return false; } - if (!ADMIN_DIDS.has(verifiedDid)) { + if (!adminDids().has(verifiedDid)) { ctx.response.status = 403; ctx.response.body = { error: "Admin only" }; return false; @@ -260,27 +273,34 @@ router.delete("/:did/webhooks/:id", async (ctx) => { // ctx.response.status = 204; // }) -const app = new Application(); +export const createApp = (): Application => { + const app = new Application(); -app.use(async (ctx, next) => { - ctx.response.headers.set("Access-Control-Allow-Origin", "*"); - ctx.response.headers.set( - "Access-Control-Allow-Methods", - "GET, POST, PUT, DELETE, OPTIONS", - ); - ctx.response.headers.set( - "Access-Control-Allow-Headers", - "Content-Type, Authorization", - ); - if (ctx.request.method === "OPTIONS") { - ctx.response.status = 204; - return; - } - await next(); -}); + app.use(async (ctx, next) => { + ctx.response.headers.set("Access-Control-Allow-Origin", "*"); + ctx.response.headers.set( + "Access-Control-Allow-Methods", + "GET, POST, PUT, DELETE, OPTIONS", + ); + ctx.response.headers.set( + "Access-Control-Allow-Headers", + "Content-Type, Authorization", + ); + if (ctx.request.method === "OPTIONS") { + ctx.response.status = 204; + return; + } + await next(); + }); -app.use(router.routes()); -app.use(router.allowedMethods()); + app.use(router.routes()); + app.use(router.allowedMethods()); -log("[server] listening on port 8080"); -app.listen({ port: 8080 }); + return app; +}; + +if (import.meta.main) { + const app = createApp(); + log("[server] listening on port 8080"); + app.listen({ port: 8080 }); +}