UNPKG

@appwarden/middleware

Version:

Instantly disable all user interaction with your app deployed on Cloudflare or Vercel

182 lines (178 loc) 5.48 kB
import { applyContentSecurityPolicyToResponse, isResponseLike } from "../chunk-NWGDCGLB.js"; import "../chunk-CRDJAOJ7.js"; import { getNowMs, logElapsed } from "../chunk-G6BMPIYD.js"; import { checkLockStatus } from "../chunk-SFJU4R6J.js"; import { buildLockPageUrl, createHeartbeatConfigError, createRedirect, debug, handleHeartbeatRequest, isHTMLRequest, isHeartbeatRequest, isOnLockPage, parseMergedConfig, printMessage, sanitizeConfigErrors } from "../chunk-Q7ZBW3WZ.js"; import { AppwardenApiHostnameSchema, AppwardenApiTokenSchema, BooleanSchema, HEARTBEAT_SERVICES, UseCSPInputSchema, ValidLockPageSlugSchema } from "../chunk-3OXAKJPA.js"; // src/adapters/react-router-cloudflare.ts import { waitUntil } from "cloudflare:workers"; import { ZodError } from "zod"; // src/schemas/react-router-cloudflare.ts import { z } from "zod"; var ReactRouterCloudflareConfigSchema = z.object({ /** The slug/path of the lock page to redirect to when the site is locked */ lockPageSlug: ValidLockPageSlugSchema, /** The Appwarden API token for authentication */ appwardenApiToken: AppwardenApiTokenSchema, /** Optional custom API hostname (defaults to https://api.appwarden.io) */ appwardenApiHostname: AppwardenApiHostnameSchema.optional(), /** Enable debug logging */ debug: BooleanSchema.default(false), /** Optional Content Security Policy configuration */ contentSecurityPolicy: z.lazy(() => UseCSPInputSchema).optional() }); // src/adapters/react-router-cloudflare.ts function getAppwardenConfiguration(generatedConfig, config) { return parseMergedConfig( generatedConfig, config, ReactRouterCloudflareConfigSchema.parse ); } var createConfigEvaluationHeartbeatResponse = (request, configErrors = [ createHeartbeatConfigError( ["config"], "custom", "Appwarden config evaluation failed" ) ]) => { return handleHeartbeatRequest( request, HEARTBEAT_SERVICES.CLOUDFLARE_REACT_ROUTER, configErrors ); }; var handleReactRouterHeartbeatRequest = (request, configFn) => { try { const validationResult = ReactRouterCloudflareConfigSchema.safeParse(configFn()); return handleHeartbeatRequest( request, HEARTBEAT_SERVICES.CLOUDFLARE_REACT_ROUTER, validationResult.success ? [] : sanitizeConfigErrors(validationResult.error) ); } catch (error) { return createConfigEvaluationHeartbeatResponse( request, error instanceof ZodError ? sanitizeConfigErrors(error) : void 0 ); } }; function createAppwardenMiddleware(configFn) { return async (args, next) => { const startTime = getNowMs(); const { request } = args; let config; let debugFn; const requestUrl = new URL(request.url); const applyCspToResponse = async (response2) => { if (!config.contentSecurityPolicy || !isResponseLike(response2)) { return response2; } try { return await applyContentSecurityPolicyToResponse({ request, response: response2, hostname: requestUrl.hostname, waitUntil, debug: debugFn, contentSecurityPolicy: config.contentSecurityPolicy }); } catch (error) { console.error( printMessage( `Failed to apply content security policy: ${error instanceof Error ? error.message : String(error)}` ) ); return response2; } }; if (isHeartbeatRequest(request, requestUrl)) { return handleReactRouterHeartbeatRequest(request, configFn); } try { const configInput = configFn(); const validationResult = ReactRouterCloudflareConfigSchema.safeParse(configInput); if (!validationResult.success) { console.error( printMessage( `Config validation failed: ${validationResult.error.message}` ) ); return next(); } config = validationResult.data; debugFn = debug(config.debug); const isHTML = isHTMLRequest(request); debugFn( `Appwarden middleware invoked for ${requestUrl.pathname}`, `isHTML: ${isHTML}` ); if (!isHTML) { return next(); } if (isOnLockPage(config.lockPageSlug, request.url)) { debugFn("Already on lock page - skipping lock status check"); } else { const result = await checkLockStatus({ request, appwardenApiToken: config.appwardenApiToken, appwardenApiHostname: config.appwardenApiHostname, debug: config.debug, lockPageSlug: config.lockPageSlug, waitUntil }); if (result.isLocked) { const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url); debugFn(`Website is locked - redirecting to ${lockPageUrl.pathname}`); throw createRedirect(lockPageUrl); } debugFn("Website is unlocked"); } } catch (error) { if (isResponseLike(error)) { throw error; } console.error( printMessage( `Unhandled error: ${error instanceof Error ? error.message : String(error)}` ) ); return next(); } const response = await next(); const finalResponse = isResponseLike(response) ? await applyCspToResponse(response) : response; logElapsed(debugFn, startTime); return finalResponse; }; } export { createAppwardenMiddleware, getAppwardenConfiguration };