Files
curriculum-project-hub/hub/test/unit/filelib-filepath.test.ts
T

41 lines
2.0 KiB
TypeScript

/**
* 文件路径安全单测(Metis 安全红线:穿越/.git/分隔符/深度)。
*/
import { describe, expect, it } from "vitest";
import { validateFilePath, FILE_PATH_MAX_DEPTH, FILE_PATH_MAX_LENGTH } from "../../src/database/filelib/fileService.js";
import { FileLibError } from "../../src/database/filelib/model.js";
describe("validateFilePath · 路径安全", () => {
it("正常相对路径通过(含 CJK 与多级)", () => {
expect(validateFilePath("a.md")).toBe("a.md");
expect(validateFilePath("docs/讲义/第一课.md")).toBe("docs/讲义/第一课.md");
expect(validateFilePath("a/b/c/d.txt")).toBe("a/b/c/d.txt");
});
it("拒绝穿越:.. 段、绝对路径", () => {
expect(() => validateFilePath("../x")).toThrowError(FileLibError);
expect(() => validateFilePath("a/../../x")).toThrowError(FileLibError);
expect(() => validateFilePath("/etc/passwd")).toThrowError(FileLibError);
});
it("拒绝 .git 段与点段", () => {
expect(() => validateFilePath(".git")).toThrowError(FileLibError);
expect(() => validateFilePath("a/.git/config")).toThrowError(FileLibError);
expect(() => validateFilePath("./a.md")).toThrowError(FileLibError);
});
it("拒绝反斜杠、控制字符、空段(双斜杠/尾斜杠)", () => {
expect(() => validateFilePath("a\\b.md")).toThrowError(FileLibError);
expect(() => validateFilePath("a\nb.md")).toThrowError(FileLibError);
expect(() => validateFilePath("a//b.md")).toThrowError(FileLibError);
expect(() => validateFilePath("a/b/")).toThrowError(FileLibError);
});
it("拒绝空路径、超长、超深", () => {
expect(() => validateFilePath("")).toThrowError(FileLibError);
expect(() => validateFilePath("a".repeat(FILE_PATH_MAX_LENGTH + 1))).toThrowError(FileLibError);
expect(() => validateFilePath(Array(FILE_PATH_MAX_DEPTH + 1).fill("d").join("/"))).toThrowError(FileLibError);
expect(validateFilePath(Array(FILE_PATH_MAX_DEPTH).fill("d").join("/"))).toContain("d/");
});
});