26.9(安全审计修复版)

Go 1.27.1 (Gin+GORM) + Vue 3 文件快传服务:

- 安全审计全部修复(docs/security-audit-2026-09-05.md):
  bcrypt 密码哈希与自动升级、presign 直传服务端大小/内容校验、
  全局请求体上限、依赖升级(govulncheck 0 命中)、janitor 后台清理、
  管理端审计动作落库、/admin CORS 收紧、通知内容白名单净化、
  会话默认 7 天、限流缓存故障降级、robots.txt 端点等
- 前端:取件链接复制修复(不再重复拼接提取码)、markdown 净化器加固
- Redis 支持库号(FCB_REDIS_DB / redis://…/db URL)
- 文档:docs/api/* 与 openapi.yaml 同步最新行为(robots.txt、
  提码 5 位起、chunk 32MiB 上限、admin 审计动作等)

验证:gofmt/go vet/go test 全绿;二进制端到端冒烟通过
This commit is contained in:
2026-09-05 04:22:41 +08:00
commit 7f060dd0e4
173 changed files with 32455 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
# 文件快传 前端(web/
Vue 3 + Vite + TypeScript 单页应用:分享 / 取件 / 管理后台(文件管理、审计日志、系统设置)/ 站内文档。
v2(任务 t3):液态玻璃主题(亮/暗/跟随系统)、中英双语(vue-i18n)、本地 Logo/favicon 打包资源、
背景图 / 页脚自定义 / 系统通知(读 `GET /api/v1/config` 下发的 v2 字段)、上传页策略动态渲染、
管理设置页全量策略表单(PATCH `/admin/config/update`)。
## 页面
| 路由 | 说明 |
|---|---|
| `/` | 首页:文本/文件分享 Tab + 快速取件(有效期选项/大小/类型过滤按 config 动态渲染) |
| `/s/:code` | 取件页:文本展示 / 文件下载(带进度) |
| `/admin/login` | 管理员登录 |
| `/admin/files` | 文件管理:列表/搜索/编辑/删除/批量删除 |
| `/admin/audit` | 审计日志:动作/结果/IP/时间范围过滤 |
| `/admin/settings` | 系统设置:站点名称、Logo/favicon、背景图、页脚、通知、保存/存储策略、上传频率、管理员密码 |
| `/docs` | 站内 API 文档(渲染 `docs/api/*.md`,构建时内嵌 + 运行时回退) |
| `/openapi` | Swagger UI(渲染 `docs/openapi.yaml` |
## 主题与语言
- 主题三态(导航栏切换 + `localStorage``fcb_theme_mode`):浅色 / 深色 / 跟随系统(默认,`prefers-color-scheme`)。
实际主题写入 `<html data-theme>`Naive UI 组件接收 `darkTheme``index.html` 内联脚本做首帧防闪烁。
- 语言(导航栏切换 + `localStorage``fcb_locale`):默认 `navigator.language`(zh 开头 → zh-CN,其余 → en-US)。
文案在 `src/locales/`,新增文案先加 zh-CN 再同步 en-US。
## v2 配置字段(消费 `GET /api/v1/config`,管理端经 `PATCH /admin/config/update` 写回)
`background_url``footer_text``footer_beian``notify_enabled/notify_title/notify_content`
`max_file_size``max_save_seconds``max_save_count``allowedFileTypes``expireStyle`
`uploadSize``uploadCount/uploadMinute``site_name/logo_url/favicon_url`
策略最终由服务端强制(403/400 中文错误);前端只做体验层提示与动态选项渲染。
## 命令
```bash
npm ci # 安装依赖
npm run dev # 开发服务器(默认代理 /api /share /chunk /presign /admin 到 http://127.0.0.1:8466
npm run build # 类型检查 + 产出 dist/(后端 embed 用)
npm run preview # 预览构建产物
```
## 环境变量(.env.local
| 变量 | 说明 |
|---|---|
| `VITE_API_BASE` | 后端 API 根地址;默认空 = 同源(embed 部署)。如 `http://127.0.0.1:8466` |
| `VITE_MOCK` | 置 `1` 启用内置 mock(无需后端) |
| `VITE_ROUTER_MODE` | `history`(默认,后端 NoRoute 已做 SPA 回退)/ `hash`(后端无回退时) |
## API 契约(最终版,经队长终审裁定)
**业务 API 挂根路径;公共端点 `/api/v1/health`、`/api/v1/config` 例外。** 权威依据:`docs/api/*.md`tech-writer 13 篇,概述 00-overview.md)与 `docs/openapi.yaml`,本节与其 100% 对齐;变更须同步文档并知会 go-api + tech-writer。
- 统一响应 `{"code":200,"msg":"ok","data":...}`HTTP 状态 = code401 未登录(连续失败 423)、423 限流、428 未初始化。
- 取件:`GET /share/metadata?code=` 不消耗次数;`GET /share/select?code=` 会**消耗**取件次数(文本 text/plain,文件流 200/206 支持 Range),文件名读 Content-Disposition。前端只在真正取件时调用 select。
- 分片:`POST /chunk/upload/init`JSON)→ `POST /chunk/upload/{uploadID}/{chunkIndex}`multipart 仅 chunk 字段)→ `GET /chunk/upload/status/{uploadID}``POST /chunk/upload/complete/{uploadID}`;取消 `DELETE /chunk/upload/{uploadID}`
- 管理端:`POST /admin/login``GET /admin/verify``DELETE /admin/file/delete``POST /admin/file/batch-delete``PATCH /admin/file/update``PATCH|POST /admin/config/update``GET /admin/audit/list`(参数 page/size/action/result/ip/start_time/end_timeISO 8601)、`PATCH /admin/settings/password`
## 嵌入约定(go:embed
- 构建产物输出到 `web/dist/`(入口 `web/dist/index.html`)。**注意**`web/` 在 Go moduleserver/)之外,go:embed 无法直接引用 —— go-api 需在构建脚本中拷贝(如 `cp -a web/dist server/web/dist`)或以 `os.DirFS` 方式挂载;`base: '/'` + history 路由配合其 NoRoute SPA 回退(静态资源优先、GET+text/html 回 index.html、/api/* JSON 404)。
- 如需改输出目录,调整 `vite.config.ts``build.outDir`
## Logo 自定义(v2:本地资源兜底)
- 默认导航 Logo`src/assets/brand/logo.svg`(构建内嵌;`DEFAULT_LOGO_URL`
- 默认 favicon`src/assets/brand/favicon.png``index.html` + `DEFAULT_FAVICON_URL`
- 运行时优先读取公共配置 `logo_url` / `favicon_url` / `site_name`(管理端「系统设置」保存后立即全站生效),空值回退本地默认;不再依赖远程 URL。
## API 客户端
统一封装见 `src/api/paths.ts`(全部路径一处可改)与 `src/api/http.ts``{code,msg,data}` 解包、Bearer 认证、超时、401/428 处理)。
## 文档页约定(与 tech-writer
- `docs/api/*.md`:每个文件一个章节,**一级标题(`# 标题`)即侧边栏章节名**;文件名(去掉 .md)作为路由 slug。构建时通过 `import.meta.glob` 内嵌原文,后端如挂载 `/docs/api/index.json``[{slug,title}]`)可补充远端章节。
- `docs/openapi.yaml`:构建时内嵌给 Swagger UI;后端也可直接静态托管 `/docs/openapi.yaml`