Skip to content

Commit 4508c2d

Browse files
committed
feat: 创建sanitizer.ts内有2种模式的文件名处理函数
1 parent d8ac95b commit 4508c2d

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

lib/sanitizer.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// 允许显式的控制字符范围,以便上传/路径能可靠地去除它们。
2+
// eslint-disable-next-line no-control-regex
3+
const CONTROL_CHARS = /[\x00-\x1f\x7f]/g;
4+
5+
/**
6+
* 用于用户上传资源键(图片、附件等)的严格清理函数。
7+
* 仅保留 ASCII 字符并保留扩展名,同时去除路径遍历尝试。
8+
*/
9+
export function sanitizeResourceKey(input: string, fallbackBase = "file") {
10+
const trimmedInput = (input ?? "").trim();
11+
const safeFallbackBase =
12+
fallbackBase
13+
.trim()
14+
.toLowerCase()
15+
.replace(/[^a-z0-9_-]+/g, "-") || "file";
16+
const fallbackName = `${safeFallbackBase}-${Date.now()}`;
17+
18+
if (!trimmedInput) return fallbackName;
19+
20+
const lastSegment =
21+
trimmedInput.split(/[\\/]/).filter(Boolean).pop() ?? trimmedInput;
22+
const lower = lastSegment.toLowerCase();
23+
24+
const lastDotIndex = lower.lastIndexOf(".");
25+
const basePart = lastDotIndex > 0 ? lower.slice(0, lastDotIndex) : lower;
26+
const rawExtPart = lastDotIndex > 0 ? lower.slice(lastDotIndex) : "";
27+
28+
const cleanedBase = basePart
29+
.replace(CONTROL_CHARS, "")
30+
.replace(/\s+/g, "-")
31+
.replace(/[^a-z0-9._-]+/g, "-")
32+
.replace(/\.{2,}/g, ".")
33+
.replace(/-+/g, "-")
34+
.replace(/^[._-]+|[-_.]+$/g, "");
35+
36+
const cleanedExt = rawExtPart
37+
.replace(CONTROL_CHARS, "")
38+
.replace(/[^a-z0-9.]+/g, "")
39+
.replace(/\.{2,}/g, ".");
40+
41+
const finalBase = cleanedBase || fallbackName;
42+
let finalExt = "";
43+
if (cleanedExt) {
44+
finalExt = cleanedExt.startsWith(".") ? cleanedExt : `.${cleanedExt}`;
45+
}
46+
47+
return `${finalBase}${finalExt}`;
48+
}
49+
50+
/**
51+
* 用于文档 slug/路径的宽松清理函数。
52+
* 保留 Unicode 字母/数字,扁平化遍历标记,并规范化分隔符。
53+
*/
54+
export function sanitizeDocumentSlug(input: string, fallback = "untitled") {
55+
const trimmedInput = (input ?? "").trim();
56+
if (!trimmedInput) return fallback;
57+
58+
const lowered = trimmedInput.toLowerCase();
59+
60+
const cleaned = lowered
61+
.replace(CONTROL_CHARS, "")
62+
.replace(/(\.\.?[/\\])+/g, "-")
63+
.replace(/[\\/]+/g, "-")
64+
.replace(/[:*?"<>|]+/g, "-")
65+
.replace(/\s+/g, "-");
66+
67+
const normalized = cleaned
68+
.replace(/[^-\p{L}\p{N}_]+/gu, "-")
69+
.replace(/-+/g, "-")
70+
.replace(/^[-_]+|[-_]+$/g, "");
71+
72+
return normalized || fallback;
73+
}

0 commit comments

Comments
 (0)