openclaw/src/gateway/server/plugins-http/path-context.ts

61 lines
1.7 KiB
TypeScript

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,
};
}