4b25231c01
- clean_orphans.py: 只删数据库无记录的孤儿 (tmp 终态/僵尸任务卷, storage 无记录目录) - 目录级判断: files 记录指向的目录整体跳过, 内部文件永不单独删除 (防误删) - 路径 resolve 统一, 调用方 cwd 无关 - 边界: tmp 终态超 1h 删/进行中保留/超 7 天判僵尸; storage 孤儿超 24h 删 - watchdog.sh: 每 30s 保活服务 + 每小时自动跑清理 (失败 30s 后重试) - start.sh: 看门狗拉起移到无条件位置 (原 main.py 在跑时 exit 短路, 看门狗死亡无人接管) - tests: 新增 test_clean_orphans 5 项 (含有效目录内 chunk 不删的误删回归断言) - README: 数据目录补 tmp, 新增运维节, 测试数 13->17
3.9 KiB
3.9 KiB
7z-encrypt-server
零知识零合并文件传输服务端 | FastAPI + SQLite | 只存卷, 不解密, 不持有密钥
发行版下载 (deb 安装包, 依赖自动安装): Gitee Releases v1.3.0 · Gitea Releases v1.3.0
与 7z-encrypt 配套的服务端。零知识 + 零合并: 只存密文卷/传密文卷, 不合并不解密, 不持有密钥。
核心设计
- 零合并: 密文卷原样落盘(
storage/{user}/{date}/{task_id}/chunk_0001...), 服务端无拼接/解密代码路径 - 零知识: 加密参数经响应头 X-Enc-Params 下发给客户端, 服务端不持久化密钥
- 账户隔离: 一个账户一个空间(admin 只认自己 + 无主旧文件), 跨账户 403
- 目录管理: dirs 表 + CRUD 端点 + 文件移动/克隆 + 上传指定目录
- aria2 反向拉: 上传时服务端主动 pull 客户端临时 HTTP 服务, pull-status 轮询实时进度
- 完整性: 逐卷 SHA-256 校验落盘 + complete 总哈希核对(卷齐才入库)
- 文件名加密: 存储名/下载名均 URL-safe base64(enc: 前缀)
安装 (deb, 依赖自动安装)
# postinst 自动安装: aria2 + p7zip-full + python3-venv + venv(fastapi/uvicorn/cryptography/tqdm)
sudo dpkg -i 7z-encrypt-server_1.3.0_all.deb # 源码版 (手机/容器)
sudo dpkg -i 7z-encrypt-server-bin_1.3.0_amd64.deb # Nuitka 编译版 (PC, 免 Python)
# 源码运行
python3 -m venv .venv && .venv/bin/pip install fastapi "uvicorn[standard]" cryptography tqdm
.venv/bin/python main.py # 端口 8000 (SZ_PORT 可覆盖)
API 一览
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/auth/register | 注册 (自动登录) |
| POST | /api/auth/login | 登录 -> token |
| DELETE | /api/auth/logout | 注销 |
| POST | /api/transfer/init | 建任务 (可带 dir_id) |
| POST | /api/transfer/{id}/pull | aria2 反向拉卷 |
| GET | /api/transfer/{id}/pull-status | 已落盘卷数 (实时进度) |
| PUT | /api/transfer/{id}/chunk/{n} | 逐卷上传 (回退) |
| POST | /api/transfer/{id}/complete | 零合并校验入库 |
| GET | /api/files | 文件列表 (带目录名) |
| GET | /api/files/{id}/chunk/{n} | 下载密文卷 + X-Enc-Params |
| DELETE | /api/files/{id} | 删除 (卷目录 + 记录) |
| PUT | /api/files/{id}/move | 移动文件到目录 |
| POST | /api/files/{id}/clone | 克隆文件 (物理复制卷) |
| POST/GET/DELETE | /api/dirs | 目录 CRUD (按用户隔离) |
| GET | /api/quota | 空间配额 |
数据目录
data/
├── app.db # SQLite: users / files / transfers / dirs
├── tmp/{task_id}/ # 传输中临时卷 (aria2 落盘, complete 后移走)
└── storage/{user}/{date}/{task_id}/chunk_NNNN # 密文卷原样
运维: 孤儿清理 + 看门狗
中断传输/失败任务会在 data/tmp/ 留下残留卷, 旧架构迁移也可能在 data/storage/
留下无记录目录。clean_orphans.py 只删数据库无记录的孤儿, 绝不碰有效数据
(files 记录指向的目录整体跳过, 内部文件永不单独判断):
./clean_orphans.py --dry-run # 预览不删
./clean_orphans.py # 实际清理
./clean_orphans.py --quiet # 静默 (日志仍写 /tmp/sz-clean.log)
清理边界: tmp 终态任务 (done/failed) 超 1 小时删, 进行中保留, 超 7 天无动静 判僵尸删; storage 孤儿超 24 小时删 (给客户端 complete 重试窗口)。
watchdog.sh (由 start.sh 拉起) 每 30s 检查服务进程, 挂了自动拉起, 并每小时
自动跑一次孤儿清理。start.sh 幂等: main.py 已在跑则跳过启动, 但无条件补拉
看门狗 (防看门狗死亡后无人接管)。
测试
.venv/bin/pytest -q # 17 tests (含账户隔离 / 目录 / 完整链路上传下载 / 孤儿清理边界)