Files
lou 4b25231c01 新增孤儿清理工具 + 看门狗每小时自动清理 + start.sh 无条件补拉看门狗
- 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
2026-08-11 14:22:28 +08:00

3.9 KiB
Raw Permalink Blame History

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 base64enc: 前缀)

安装 (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 (含账户隔离 / 目录 / 完整链路上传下载 / 孤儿清理边界)