mirror of
https://github.com/2234839/web-font.git
synced 2026-06-30 20:58:34 +08:00
- 修复 HTTP header 大小写不敏感匹配,解决浏览器上传请求体为空的问题
- 重写 createStreamAfterTarget,修复大文件上传时 body stream 数据流断裂
- 添加 chunked transfer encoding 解码支持
- 读取完 body 后 cancel stream,防止后台循环抛异常炸进程
- 修复 parseHttpRequest 中 split(":") 对含冒号 header value 的错误拆分
- 临时上传同名文件直接覆盖,不再加时间戳前缀
- 移除 tjs (txiki.js) 运行时支持及相关代码
- 安装并配置 vite-plugin-pilot 浏览器测试工具
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
86 lines
2.6 KiB
TypeScript
86 lines
2.6 KiB
TypeScript
import { writeFile, unlink, readdir, path_join } from "./interface";
|
|
import { enableTempUpload, adminApiKey, tempMaxFiles } from "./config";
|
|
|
|
/** 允许的字体文件扩展名 */
|
|
const ALLOWED_EXTENSIONS = [".ttf", ".otf", ".woff", ".woff2"];
|
|
|
|
function isAllowedFontFile(filename: string): boolean {
|
|
const lower = filename.toLowerCase();
|
|
return ALLOWED_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
}
|
|
|
|
/** 清理文件名,移除路径分隔符和危险字符 */
|
|
function sanitizeFilename(filename: string): string {
|
|
return filename.replace(/[/\\]/g, "").replace(/[\x00-\x1f]/g, "");
|
|
}
|
|
|
|
/** 确保目录存在,不存在则创建 */
|
|
async function ensureDir(dir: string) {
|
|
const { stat, mkdir } = await import("./interface");
|
|
try {
|
|
await stat(dir);
|
|
} catch {
|
|
await mkdir(dir);
|
|
}
|
|
}
|
|
|
|
export interface UploadResult {
|
|
success: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
export async function handleTempUpload(fileData: { data: Uint8Array; filename: string }): Promise<UploadResult> {
|
|
if (!enableTempUpload) {
|
|
return { success: false, error: "临时上传功能未启用" };
|
|
}
|
|
|
|
if (!isAllowedFontFile(fileData.filename)) {
|
|
return { success: false, error: "不支持的字体文件格式,仅支持 ttf/otf/woff/woff2" };
|
|
}
|
|
|
|
await ensureDir("font/temp");
|
|
|
|
const filename = sanitizeFilename(fileData.filename);
|
|
const filePath = path_join("font/temp", filename);
|
|
|
|
/** 同名文件直接覆盖,否则检查文件数量上限 */
|
|
try {
|
|
await (await import("./interface")).stat(filePath);
|
|
} catch {
|
|
const entries = await readdir("font/temp");
|
|
const count = entries.filter((e) => e.isFile() && isAllowedFontFile(e.name)).length;
|
|
if (count >= tempMaxFiles) {
|
|
const toDelete = entries.find((e) => e.isFile() && isAllowedFontFile(e.name));
|
|
if (toDelete) {
|
|
try { await unlink(path_join("font/temp", toDelete.name)); } catch { /* 删除失败不影响上传 */ }
|
|
}
|
|
}
|
|
}
|
|
|
|
await writeFile(filePath, fileData.data);
|
|
return { success: true };
|
|
}
|
|
|
|
export async function handleAdminUpload(
|
|
fileData: { data: Uint8Array; filename: string },
|
|
apiKey: string,
|
|
): Promise<UploadResult> {
|
|
if (!adminApiKey) {
|
|
return { success: false, error: "管理员上传功能未启用" };
|
|
}
|
|
|
|
if (apiKey !== adminApiKey) {
|
|
return { success: false, error: "API Key 无效" };
|
|
}
|
|
|
|
if (!isAllowedFontFile(fileData.filename)) {
|
|
return { success: false, error: "不支持的字体文件格式,仅支持 ttf/otf/woff/woff2" };
|
|
}
|
|
|
|
await ensureDir("font/admin");
|
|
|
|
const filename = sanitizeFilename(fileData.filename);
|
|
await writeFile(path_join("font/admin", filename), fileData.data);
|
|
return { success: true };
|
|
}
|