mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-23 18:58:51 +02:00
Merge pull request #3738 from breken-ai/fix/path-rule-percent-encoding
▚▚ fix(rules): decode percent-encoded PATH rule patterns before matching
This commit is contained in:
@@ -20,6 +20,11 @@ function getSegmentRegex(patternPart: string): RegExp {
|
|||||||
// resolves `.` / `..` segments, so a request like `/public%2F..%2Fadmin/`
|
// resolves `.` / `..` segments, so a request like `/public%2F..%2Fadmin/`
|
||||||
// or `/public/../admin/` is matched as `/admin/`, not as a literal segment
|
// or `/public/../admin/` is matched as `/admin/`, not as a literal segment
|
||||||
// or a wildcard-swallowed sequence under `/public/*`.
|
// or a wildcard-swallowed sequence under `/public/*`.
|
||||||
|
//
|
||||||
|
// Applied to both the request path and the rule pattern: the pattern
|
||||||
|
// validator only accepts spaces / non-ASCII in percent-encoded form, so a
|
||||||
|
// rule like `/my%20docs/*` must be compared against the decoded segment
|
||||||
|
// `my docs`, not the literal text `my%20docs`.
|
||||||
function decodeAndResolvePath(p: string): string[] {
|
function decodeAndResolvePath(p: string): string[] {
|
||||||
const rawParts = p.split("/").filter(Boolean);
|
const rawParts = p.split("/").filter(Boolean);
|
||||||
|
|
||||||
@@ -48,7 +53,7 @@ function decodeAndResolvePath(p: string): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isPathAllowed(pattern: string, path: string): boolean {
|
export function isPathAllowed(pattern: string, path: string): boolean {
|
||||||
const patternParts = pattern.split("/").filter(Boolean);
|
const patternParts = decodeAndResolvePath(pattern);
|
||||||
const pathParts = decodeAndResolvePath(path);
|
const pathParts = decodeAndResolvePath(path);
|
||||||
|
|
||||||
function matchSegments(
|
function matchSegments(
|
||||||
|
|||||||
@@ -386,6 +386,38 @@ function runSpecialCharacterTests() {
|
|||||||
console.log("All special character tests passed!");
|
console.log("All special character tests passed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runEncodedPatternTests() {
|
||||||
|
console.log("\nRunning percent-encoded pattern tests...");
|
||||||
|
|
||||||
|
// isValidUrlGlobPattern accepts percent-encoded sequences and rejects
|
||||||
|
// raw spaces / non-ASCII, so `%20` and `%C3%A9` are the only way to write
|
||||||
|
// a PATH rule for such a path. Badger sends the request path already
|
||||||
|
// decoded (Go's req.URL.Path), and isPathAllowed decodes it again, so the
|
||||||
|
// rule pattern must be decoded the same way or it can never match.
|
||||||
|
assertEquals(
|
||||||
|
isPathAllowed("/my%20docs/*", "/my docs/report.pdf"),
|
||||||
|
true,
|
||||||
|
"Percent-encoded space in pattern should match decoded request path"
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
isPathAllowed("/my%20docs/*", "/my%20docs/report.pdf"),
|
||||||
|
true,
|
||||||
|
"Percent-encoded space in pattern should match raw-encoded request path"
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
isPathAllowed("/caf%C3%A9", "/café"),
|
||||||
|
true,
|
||||||
|
"Percent-encoded UTF-8 in pattern should match decoded request path"
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
isPathAllowed("/my%20docs/*", "/my-docs/report.pdf"),
|
||||||
|
false,
|
||||||
|
"Decoded pattern must still reject a different path"
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("All percent-encoded pattern tests passed!");
|
||||||
|
}
|
||||||
|
|
||||||
function runRegionTests() {
|
function runRegionTests() {
|
||||||
console.log("\nRunning isIpInRegion tests...");
|
console.log("\nRunning isIpInRegion tests...");
|
||||||
|
|
||||||
@@ -446,6 +478,7 @@ function runRegionTests() {
|
|||||||
try {
|
try {
|
||||||
runTests();
|
runTests();
|
||||||
runSpecialCharacterTests();
|
runSpecialCharacterTests();
|
||||||
|
runEncodedPatternTests();
|
||||||
runRegionTests();
|
runRegionTests();
|
||||||
console.log("\n✅ All tests passed!");
|
console.log("\n✅ All tests passed!");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user