| import { |
| PROTECTED_PLUGIN_ROUTE_PREFIXES, |
| canonicalizePathForSecurity, |
| } from "../../security-path.js"; |
|
|
| export type PluginRoutePathContext = { |
| pathname: string; |
| canonicalPath: string; |
| candidates: string[]; |
| malformedEncoding: boolean; |
| decodePassLimitReached: boolean; |
| rawNormalizedPath: string; |
| }; |
|
|
| function normalizeProtectedPrefix(prefix: string): string { |
| const collapsed = prefix.toLowerCase().replace(/\/{2,}/g, "/"); |
| if (collapsed.length <= 1) { |
| return collapsed || "/"; |
| } |
| return collapsed.replace(/\/+$/, ""); |
| } |
|
|
| export function prefixMatchPath(pathname: string, prefix: string): boolean { |
| return ( |
| pathname === prefix || pathname.startsWith(`${prefix}/`) || pathname.startsWith(`${prefix}%`) |
| ); |
| } |
|
|
| const NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES = |
| PROTECTED_PLUGIN_ROUTE_PREFIXES.map(normalizeProtectedPrefix); |
|
|
| export function isProtectedPluginRoutePathFromContext(context: PluginRoutePathContext): boolean { |
| if ( |
| context.candidates.some((candidate) => |
| NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES.some((prefix) => |
| prefixMatchPath(candidate, prefix), |
| ), |
| ) |
| ) { |
| return true; |
| } |
| if (!context.malformedEncoding) { |
| return false; |
| } |
| return NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES.some((prefix) => |
| prefixMatchPath(context.rawNormalizedPath, prefix), |
| ); |
| } |
|
|
| export function resolvePluginRoutePathContext(pathname: string): PluginRoutePathContext { |
| const canonical = canonicalizePathForSecurity(pathname); |
| return { |
| pathname, |
| canonicalPath: canonical.canonicalPath, |
| candidates: canonical.candidates, |
| malformedEncoding: canonical.malformedEncoding, |
| decodePassLimitReached: canonical.decodePassLimitReached, |
| rawNormalizedPath: canonical.rawNormalizedPath, |
| }; |
| } |
|
|