UNPKG

wcz-layout

Version:

73 lines (72 loc) 3.43 kB
import { n as serverEnv } from "./env-Bm6rrgwT.mjs"; import { n as getSessionUser } from "./user-BQiWoQk1.mjs"; import { i as buildUser, o as hasPermission } from "./utils-DpcYsXTK.mjs"; import { t as apiMiddleware } from "./apiMiddleware-DRhawg5S.mjs"; import { z } from "zod"; import { createCsrfMiddleware, createMiddleware } from "@tanstack/react-start"; import * as jose from "jose"; //#region src/middleware/authMiddleware.ts async function resolveUser(request) { const authHeader = request.headers.get("Authorization"); if (authHeader?.startsWith("Bearer ")) { let payload; try { payload = await verifyToken(authHeader.substring(7)); } catch (error) { throw Response.json({ message: error instanceof Error ? error.message : "Unauthorized: Invalid access token" }, { status: 401 }); } return buildUser(payload); } return getSessionUser(); } const requiredAuthenticationMiddleware = createMiddleware().server(async ({ next, request }) => { const user = await resolveUser(request); if (!user) throw Response.json({ message: "Unauthorized: User not signed in" }, { status: 401 }); return next({ context: { user } }); }); const publicAuthenticationMiddleware = createMiddleware().server(async ({ next, request }) => { return next({ context: { user: await resolveUser(request) } }); }); function authenticationMiddleware(options) { return options?.optional ? publicAuthenticationMiddleware : requiredAuthenticationMiddleware; } const authorizationMiddleware = (permissionKey) => createMiddleware().middleware([authenticationMiddleware()]).server(async ({ next, context }) => { if (hasPermission(context.user, permissionKey)) return next(); throw Response.json({ message: `Forbidden: User ${context.user.name} is not authorized to access this resource` }, { status: 403 }); }); async function verifyToken(token) { const { payload } = await jose.jwtVerify(token, getJWKS(), { issuer: `https://login.microsoftonline.com/${serverEnv.ENTRA_TENANT_ID}/v2.0`, audience: serverEnv.ENTRA_CLIENT_ID }); return payload; } let jwksCache = null; function getJWKS() { jwksCache ??= jose.createRemoteJWKSet(new URL(`https://login.microsoftonline.com/${serverEnv.ENTRA_TENANT_ID}/discovery/v2.0/keys`)); return jwksCache; } //#endregion //#region src/middleware/validationMiddleware.ts const validationMiddleware = (schema) => createMiddleware().server(async ({ next, request }) => { const json = await request.json(); const result = schema.safeParse(json); if (!result.success) { const { fieldErrors } = z.flattenError(result.error); const firstFieldName = Object.keys(fieldErrors)[0]; const firstErrorMessage = fieldErrors[firstFieldName]?.[0]; if (firstFieldName && firstErrorMessage) { const name = firstFieldName.charAt(0).toUpperCase() + firstFieldName.slice(1); const message = firstErrorMessage.replace(/^Invalid input:\s*/i, "").toLowerCase(); return Response.json({ message: `${name} - ${message}` }, { status: 400 }); } return Response.json({ message: "Validation failed" }, { status: 400 }); } return await next({ context: { data: result.data } }); }); //#endregion //#region src/middleware/csrfMiddleware.ts const csrfMiddleware = createCsrfMiddleware({ filter: (ctx) => ctx.handlerType === "serverFn" }); //#endregion export { apiMiddleware, authenticationMiddleware, authorizationMiddleware, csrfMiddleware, validationMiddleware }; //# sourceMappingURL=middleware.mjs.map