mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(producer): isPathInside accepts children whose names start with two dots (#5834)
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { resolve } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { isPathInside } from "./assetPaths.js";
|
||||
|
||||
describe("isPathInside", () => {
|
||||
it("accepts the parent itself and nested children", () => {
|
||||
expect(isPathInside(resolve("/project"), resolve("/project"))).toBe(true);
|
||||
expect(isPathInside(resolve("/project/assets/logo.png"), resolve("/project"))).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects paths above the parent and siblings sharing its prefix", () => {
|
||||
expect(isPathInside(resolve("/project/../secret.txt"), resolve("/project"))).toBe(false);
|
||||
expect(isPathInside(resolve("/"), resolve("/project"))).toBe(false);
|
||||
expect(isPathInside(resolve("/project-other/logo.png"), resolve("/project"))).toBe(false);
|
||||
});
|
||||
|
||||
it("accepts a child whose name starts with two dots", () => {
|
||||
// `..assets` is an ordinary directory name, not a parent-dir segment.
|
||||
expect(isPathInside(resolve("/project/..assets/logo.png"), resolve("/project"))).toBe(true);
|
||||
expect(isPathInside(resolve("/project/..intro.mp4"), resolve("/project"))).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -36,12 +36,14 @@ export function isNonRelativeUrl(val: string): boolean {
|
||||
* Cross-platform containment check: is `childPath` inside `parentPath`?
|
||||
* Equality counts as "inside".
|
||||
*/
|
||||
const LEADING_PARENT_SEGMENT_RE = /^\.\.(?:[\\/]|$)/;
|
||||
|
||||
export function isPathInside(childPath: string, parentPath: string): boolean {
|
||||
const absChild = resolve(childPath);
|
||||
const absParent = resolve(parentPath);
|
||||
if (absChild === absParent) return true;
|
||||
const rel = relative(absParent, absChild);
|
||||
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
||||
return rel !== "" && !LEADING_PARENT_SEGMENT_RE.test(rel) && !isAbsolute(rel);
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -49,6 +49,29 @@ describe("isPathInside", () => {
|
||||
expect(isPathInside(resolve("/foo/bar/../../etc/passwd"), resolve("/foo/bar"))).toBe(false);
|
||||
});
|
||||
|
||||
it("returns true for a child whose name starts with two dots", () => {
|
||||
// `..assets` is an ordinary directory name, not a parent-dir segment.
|
||||
expect(isPathInside(resolve("/foo/bar/..assets/logo.png"), resolve("/foo/bar"))).toBe(true);
|
||||
expect(isPathInside(resolve("/foo/bar/..intro.mp4"), resolve("/foo/bar"))).toBe(true);
|
||||
expect(
|
||||
isPathInside(
|
||||
win32.resolve("C:\\project\\..fonts\\Inter.woff2"),
|
||||
win32.resolve("C:\\project"),
|
||||
{
|
||||
pathModule: win32,
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("still rejects a Windows child above the parent", () => {
|
||||
expect(
|
||||
isPathInside(win32.resolve("C:\\project\\..\\secret.txt"), win32.resolve("C:\\project"), {
|
||||
pathModule: win32,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("normalises trailing slashes on parent", () => {
|
||||
expect(isPathInside(resolve("/foo/bar/baz"), resolve("/foo/bar/"))).toBe(true);
|
||||
});
|
||||
|
||||
@@ -28,6 +28,8 @@ type PathModuleLike = {
|
||||
isAbsolute: (path: string) => boolean;
|
||||
};
|
||||
|
||||
const LEADING_PARENT_SEGMENT_RE = /^\.\.(?:[\\/]|$)/;
|
||||
|
||||
type IsPathInsideOptions = {
|
||||
pathModule?: PathModuleLike;
|
||||
};
|
||||
@@ -59,7 +61,7 @@ export function isPathInside(
|
||||
// `relative()` returns "" when paths are equal, ".." or "..\\foo" when child
|
||||
// is above the parent, and an absolute path when they live on different
|
||||
// drives/volumes (Windows) — none of which count as "inside".
|
||||
return rel !== "" && !rel.startsWith("..") && !isPathAbsolute(rel);
|
||||
return rel !== "" && !LEADING_PARENT_SEGMENT_RE.test(rel) && !isPathAbsolute(rel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user