feat: 头像上传(uuid重命名/魔数校验/2MB/配置版本管线)与三级解析链
- POST /api/platform/tenants/{slug}/brand/avatar(require_tenant):
multipart 收文件,魔数判定类型(\x89PNG/\xff\xd8\xff/RIFF....WEBP,
优先于扩展名——改后缀骗不过,存盘扩展名取自内容)、≤2MB(413,
upload.size 预检免拷贝)、服务端 uuid4 重命名(原始文件名不参与
路径),落 data/uploads/<slug>/(目录懒建,gitignore 已忽略)
- 走 Task 6 配置版本管线(复用 config_routes 内部 helper):读当前
快照 → brand 组只替换 avatar 字段 → validate_group →
write_config_version(comment=头像上传) → registry_reload 热生效
- /api/public/avatar 三级解析链:uploads → seed 资产 → 静态兜底;
Phase 1 文件名穿越防线(拒 / \ . ..)扩到 uploads 段
- registry.uploads_root:自 data_dir.parent 派生(生产=<repo>/data/
uploads;测试注入 tmp data_dir 时自动落 tmp 内,隔离免污染)
- 新依赖 python-multipart(multipart 表单解析)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -86,6 +86,7 @@ from app.platform.routes.config_routes import (
|
||||
settings_router as platform_settings_router,
|
||||
)
|
||||
from app.platform.routes.tenant_routes import router as platform_tenant_router
|
||||
from app.platform.routes.upload_routes import router as platform_upload_router
|
||||
app.include_router(chat_router)
|
||||
app.include_router(chat_rest_router)
|
||||
app.include_router(public_router)
|
||||
@@ -97,6 +98,9 @@ app.include_router(platform_tenant_router)
|
||||
# 前缀的 Host 豁免由 Task 3 的中间件规则统一覆盖。
|
||||
app.include_router(platform_config_router)
|
||||
app.include_router(platform_settings_router)
|
||||
# 头像上传(Task 7):multipart 魔数校验 + uuid 重命名 + 配置版本管线
|
||||
# (require_tenant);/api/public/avatar 的三级解析链消费上传产物。
|
||||
app.include_router(platform_upload_router)
|
||||
# 平台认证路由(Task 2):本任务即挂——已知租户 Host(如 jiancai)下
|
||||
# /api/platform/auth/* 经 Host 中间件直达,TDD 循环闭环。Task 3 将为
|
||||
# /api/platform/ 前缀加中间件豁免(平台后台不依赖租户域名解析);
|
||||
|
||||
Reference in New Issue
Block a user