26.9:直链下载 + 过期回收 + SHA512 去重 + 防盗链 + 媒体预览 + 文件夹上传提示
CI 测试 / go vet + go test (push) Failing after 5s

- 对象存储直链:S3 引擎 302 到限时预签名 URL(有效期钳位分享剩余时效),失败自动回落代理
- 过期回收:janitor 定时扫描 + 取件惰性回收 + 管理端手动触发(POST /admin/recycle/run),
  retention_days 最长存储时长;删除走引用计数(去重对象安全)
- SHA512 内容去重:三条上传链路落库后计算哈希,命中即复用旧对象并删除本次副本
- 下载防盗链:Referer 白名单(同源/空 Referer/通配域名放行),挂 /share/download
- 取件页图片/音频内联预览(下载地址直连,加载失败回退下载按钮)
- 文件夹上传:拖拽目录明确提示"建议压缩后上传"(webkitGetAsEntry 探测)
- 管理端设置卡「回收与下载安全」8 个新配置键(KVSchema + configKeys + UI + i18n)
- 前端产物重建并同步 server/web/dist 与 web-embed
- 文档:10-config 配置表、03-file-share 直链/防盗链/文件夹章节、07-admin 回收端点、openapi
This commit is contained in:
2026-09-08 04:54:05 +08:00
parent 84df9996cb
commit 7a9015aad0
25 changed files with 1259 additions and 15 deletions
+28
View File
@@ -101,3 +101,31 @@ curl -s -H 'Range: bytes=0-1023' -o part.bin \
```json
{ "code": 416, "msg": "请求范围超出文件大小" }
```
## 直链下载(26.9
存储引擎为对象存储(S3)且 `direct_download=1` 时,`GET /share/select`
`GET /share/download` 不再代理文件流,而是 `302` 重定向到限时预签名 URL——
文件字节不经过本服务器,带宽成本转嫁对象存储。
- 签名有效期 = `direct_link_expire`(默认 900 秒)与分享剩余时效的较小值;
- 引擎不支持直链(如 local/WebDAV)时自动回落代理下载,取件不中断;
- 审计照常记录(`transferred_bytes` 记为文件大小)。
## 下载防盗链(26.9
`hotlink_enabled=1` 时,`/share/download` 校验 `Referer`
| Referer | 行为 |
|---|---|
| 空(直接访问 / curl / 地址栏) | 放行 |
| 与请求 Host 同源 | 放行 |
| 命中 `hotlink_whitelist`(逗号分隔域名,支持 `*.example.com` 通配) | 放行 |
| 其余 | `403`JSON 错误体) |
白名单为空时仅同源放行。开关与白名单均为管理端 KV,修改后立即生效。
## 文件夹上传(26.9
不支持文件夹上传(前端已移除目录选择;拖拽目录会提示"建议压缩后上传")。
后端 `SanitizeFileName` 会剥离文件名中的路径分隔符,多级路径无法成体保存。
+17
View File
@@ -432,3 +432,20 @@ curl -s -X PATCH http://localhost:8466/admin/settings/password \
```json
{ "code": 401, "msg": "旧密码错误" }
```
## 手动回收:POST /admin/recycle/run
**26.9**:手动触发一轮过期分享回收(定时循环之外的管理端入口)。回收范围:
时间已过期、次数已耗尽、创建时间超过 `retention_days` 的分享——删除记录并
连带删除存储对象(SHA512 去重开启时做引用计数,仍有其他分享引用的对象保留)。
```bash
curl -s -X POST "http://localhost:8466/admin/recycle/run" -H "Authorization: Bearer $TOKEN"
```
```json
{ "code": 200, "msg": "ok", "data": { "removed": 3 } }
```
相关配置键:`recycle_enabled`(定时开关)、`recycle_interval`(扫描间隔)、
`retention_days`(最长存储时长)、`dedup_enabled`(引用计数开关)。
+8
View File
@@ -80,6 +80,14 @@ DSN 缺省落 `./data/fileshare.db`);`FCB_DB_DRIVER=postgres` 时 `FCB_DB_DS
|---|---|---|---|
| `uploadCount` / `uploadMinute` | int1~10000 / 1~1440 | 10 / 1 | 窗口内允许上传次数 / 窗口分钟(上传成功才计数,超限 423;管理端修改后运行时同步限流规则,立即生效) |
| `upload_rate` / `download_rate` | int640~1 GiB/s | 0 / 0 | **26.9**:上下行带宽字节/秒,0=不限速;管理端改后立即生效(每请求动态读 KV)。详见《[带宽限速](13-bandwidth.md)》 |
| `recycle_enabled` | 0/1 | 1 | **26.9**:过期分享自动回收开关(定时扫描 + 取件惰性回收) |
| `recycle_interval` | int6460~86400 秒) | 1800 | **26.9**:回收扫描间隔(秒;管理端以分钟展示) |
| `retention_days` | int640~3650 天) | 0 | **26.9**:最长存储时长(天),上传超过该天数的分享自动回收;0=不限制 |
| `dedup_enabled` | 0/1 | 1 | **26.9**:SHA512 内容去重,相同文件仅存储一份(多分享引用同一对象,引用计数删除) |
| `direct_download` | 0/1 | 1 | **26.9**:对象存储直链下载(S3 引擎 302 到预签名 URL,文件不经过本站带宽) |
| `direct_link_expire` | int6460~3600 秒) | 900 | **26.9**:直链签名有效期(秒;不超过分享剩余时效) |
| `hotlink_enabled` | 0/1 | 0 | **26.9**:下载防盗链(Referer 白名单校验;空 Referer 放行) |
| `hotlink_whitelist` | string(≤2048 | 空 | **26.9**:防盗链白名单,逗号分隔域名,支持 `*.example.com` 通配;空=仅同源放行 |
| `errorCount` / `errorMinute` | int | 10 / 1 | 取件错误(失败计数)+ metadata 每次计数 |
| `loginCount` / `loginMinute` | int | 5 / 15 | 登录失败计数 |
+43
View File
@@ -168,6 +168,14 @@ paths:
uploadMinute: { type: integer, default: 1 }
upload_rate: { type: integer, format: int64, default: 0, description: '26.9 上行带宽字节/秒;0=不限速' }
download_rate: { type: integer, format: int64, default: 0, description: '26.9 下行带宽字节/秒;0=不限速' }
recycle_enabled: { type: integer, enum: [0, 1], default: 1, description: '26.9 过期分享自动回收开关' }
recycle_interval: { type: integer, format: int64, default: 1800, description: '26.9 回收扫描间隔秒(60~86400' }
retention_days: { type: integer, format: int64, default: 0, description: '26.9 最长存储时长天(0~36500=不限制)' }
dedup_enabled: { type: integer, enum: [0, 1], default: 1, description: '26.9 SHA512 内容去重开关' }
direct_download: { type: integer, enum: [0, 1], default: 1, description: '26.9 对象存储直链下载开关' }
direct_link_expire: { type: integer, format: int64, default: 900, description: '26.9 直链签名有效期秒(60~3600' }
hotlink_enabled: { type: integer, enum: [0, 1], default: 0, description: '26.9 下载防盗链开关' }
hotlink_whitelist: { type: string, maxLength: 2048, default: '', description: '26.9 防盗链白名单(逗号分隔域名,支持 *.example.com' }
allowed_file_types: { type: string, default: '*' }
openUpload: { type: boolean, default: true }
enableChunk: { type: boolean, default: false }
@@ -1379,6 +1387,14 @@ paths:
uploadMinute: { type: integer }
upload_rate: { type: integer, format: int64, description: '26.9 上行带宽字节/秒;0=不限速' }
download_rate: { type: integer, format: int64, description: '26.9 下行带宽字节/秒;0=不限速' }
recycle_enabled: { type: integer, enum: [0, 1], description: '26.9 过期分享自动回收开关' }
recycle_interval: { type: integer, format: int64, description: '26.9 回收扫描间隔秒(60~86400' }
retention_days: { type: integer, format: int64, description: '26.9 最长存储时长天(0~3650' }
dedup_enabled: { type: integer, enum: [0, 1], description: '26.9 SHA512 内容去重开关' }
direct_download: { type: integer, enum: [0, 1], description: '26.9 对象存储直链下载开关' }
direct_link_expire: { type: integer, format: int64, description: '26.9 直链签名有效期秒(60~3600' }
hotlink_enabled: { type: integer, enum: [0, 1], description: '26.9 下载防盗链开关' }
hotlink_whitelist: { type: string, maxLength: 2048, description: '26.9 防盗链白名单' }
admin_token: { type: string, example: '' }
_engine_hint:
type: object
@@ -1529,6 +1545,33 @@ paths:
"401": { $ref: "#/components/responses/Unauthorized" }
"503": { $ref: "#/components/responses/ServiceUnavailable" }
/admin/recycle/run:
post:
tags: [admin]
summary: 手动触发一轮过期回收(26.9
description: |
回收时间已过期、次数已耗尽、创建时间超过 retention_days 的分享:
删除记录并连带删除存储对象(dedup_enabled 开启时做引用计数,
仍有其他分享引用的对象保留)。返回本轮回收条数。
operationId: adminRecycleRun
security:
- bearerAuth: []
responses:
"200":
description: 回收完成
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
properties:
data:
type: object
properties:
removed: { type: integer, description: 本轮回收条数 }
"401": { $ref: '#/components/responses/Unauthorized' }
/admin/settings/password:
patch:
tags: [管理后台]