Files
filedrop/plans/phase1-architecture.md
agent 4b34a85599 init: FileDrop phase1 architecture and scaffold
- Rust axum signaling server with WebSocket support
- Lit + TypeScript frontend with Vite
- Redis session storage with TTL
- WebRTC transport and crypto client stubs
- Phase1 architecture plan in plans/
- Deploy directory structure prepared
2026-04-09 10:32:06 +08:00

7.7 KiB
Raw Permalink Blame History

FileDrop - 安全无痕文件传输 Web App

产品定位

免费、无注册、无历史记录的安全文件传输工具。

  • 优先局域网,兼顾公网
  • WebRTC 直连优先TURN 兜底
  • 浏览器端端到端加密
  • 传完即销毁,不留痕迹

第一期范围

要做

  • 扫码/短码配对
  • WebRTC DataChannel 传输
  • 浏览器端 AES-GCM 分块加密
  • TURN 回退
  • 会话超时自动清理
  • 小文件传输(<100MB

不做

  • 用户注册/登录
  • 历史记录
  • 大文件/断点续传
  • 付费/套餐
  • Postgres
  • WASM
  • 对象存储中转

技术栈

技术
前端 Lit + TypeScript + Vite
后端 Rust + axum + tokio
临时状态 Redis
NAT 穿透 coturn
反向代理 Caddy
部署 Debian 12 + systemd

系统架构

Browser A                    Browser B
  |                              |
  |---- HTTPS / WSS -------------|
  |                              |
         Rust Signaling Server
                |
              Redis
                |
             coturn

职责划分

浏览器

  • 选文件
  • 生成会话密钥
  • 二维码/短码配对
  • WebRTC 建连
  • 文件分块加密
  • DataChannel 发送/接收

Rust 服务端

  • 创建/加入会话
  • WebSocket 信令转发
  • 临时会话状态
  • 过期清理
  • 下发 ICE 配置

Redis

  • 会话临时状态
  • 在线状态
  • 一次性加入令牌
  • TTL 自动过期

coturn

  • STUN/TURN 服务

核心流程

1. 创建会话

  1. 发送端选择文件
  2. 浏览器本地生成 session_secret
  3. 请求 POST /api/sessions
  4. 服务端返回 room_idjoin_tokenws_urlice_servers
  5. 前端生成分享信息:
    • 短码:room_id
    • 链接:/join/{room_id}#k={session_secret}&t={join_token}

#k= 在 URL fragment 中,不会发给服务端

2. 加入会话

  1. 接收端扫码进入
  2. 前端从 fragment 取出 session_secretjoin_token
  3. 请求 POST /api/sessions/{room_id}/join
  4. 服务端校验会话状态和 token
  5. 成功后建立 WebSocket

3. 信令协商

  1. 双方连上 WS /ws
  2. 发送端创建 offer
  3. 接收端返回 answer
  4. 双方交换 ICE candidate
  5. 建立 RTCDataChannel

4. 文件传输

  1. 发送端发送 file_manifest
  2. 文件切块64KB ~ 256KB
  3. 每块独立 AES-GCM 加密
  4. 通过 DataChannel 发送
  5. 接收端逐块解密并缓存
  6. 完成后生成下载文件
  7. 双方发送完成确认并关闭会话

5. 会话销毁

触发条件:

  • 传输完成
  • 用户主动取消
  • 超时15 分钟)
  • WebSocket/RTC 长时间断开

协议设计

HTTP API

POST /api/sessions

创建会话

请求

{
  "file_count": 2,
  "total_size": 1834201
}

响应

{
  "room_id": "8F4K2P",
  "join_token": "opaque-token",
  "ws_url": "wss://app.example.com/ws",
  "expires_at": "2026-04-09T12:00:00Z",
  "ice_servers": [
    { "urls": ["stun:turn.example.com:3478"] },
    {
      "urls": ["turn:turn.example.com:3478?transport=udp"],
      "username": "u",
      "credential": "p"
    }
  ]
}

POST /api/sessions/{room_id}/join

加入会话

请求

{
  "join_token": "opaque-token"
}

响应

{
  "ws_url": "wss://app.example.com/ws",
  "expires_at": "2026-04-09T12:00:00Z",
  "ice_servers": [...]
}

GET /health

健康检查

WebSocket 消息

统一格式:

{
  "type": "offer|answer|ice|ready|cancel|error|ping|pong",
  "room_id": "8F4K2P",
  "role": "sender|receiver",
  "payload": {}
}

DataChannel 消息

控制消息JSON

  • file_manifest - 文件清单
  • chunk_ack - 分块确认
  • transfer_complete - 传输完成

数据面:ArrayBuffer(加密分块)


安全设计

  1. 会话密钥只在浏览器生成和持有
  2. 文件名和文件内容都加密
  3. 服务端只看到 room_id、连接状态、粗粒度元信息
  4. 不保存文件内容
  5. 不保存传输历史
  6. Redis 全部使用 TTL
  7. 所有页面和 WS 强制 HTTPS/WSS
  8. TURN 使用临时凭证
  9. 前端在完成或取消后清空密钥和缓存

加密方案

  • 会话密钥32 字节随机
  • 密钥派生HKDF-SHA-256
  • 分块加密AES-GCM
  • 摘要校验SHA-256

前端页面

路由 说明
/ 首页:发送/接收入口
/send 选文件、创建会话、展示二维码
/join/:roomId 扫码进入、确认接收、下载
/expired 会话失效提示

Redis 设计

Key 结构

  • session:{room_id} - 会话元数据
  • presence:{room_id}:sender - 发送端在线状态
  • presence:{room_id}:receiver - 接收端在线状态
  • join_token:{room_id} - 一次性加入令牌
  • ws:{connection_id} - WebSocket 连接映射

TTL

  • 会话15 分钟
  • 已完成会话:立即删除或保留 1 分钟缓冲
  • WebSocket presence30-60 秒心跳续期

开发里程碑

P0 原型

  • 创建/加入会话
  • WS 信令
  • DataChannel 建立
  • 文本消息互通

P1 小文件传输

  • 文件 manifest
  • 分块发送
  • 接收后下载
  • 进度显示

P2 安全闭环

  • 会话密钥生成
  • 文件名/内容加密
  • 会话销毁
  • Redis TTL 清理

P3 稳定性

  • TURN 兜底验证
  • 异常断开处理
  • 超时与取消
  • Chrome / Safari / iOS 测试

P4 上线

  • Debian 部署
  • HTTPS/WSS
  • 基础限流
  • 基础日志与监控

项目结构

filedrop/
├── Cargo.toml
├── plans/
│   └── phase1-architecture.md
├── server/
│   ├── src/
│   │   ├── main.rs
│   │   ├── config.rs
│   │   ├── api/
│   │   │   ├── mod.rs
│   │   │   ├── sessions.rs
│   │   │   └── health.rs
│   │   ├── signaling/
│   │   │   ├── mod.rs
│   │   │   ├── ws_handler.rs
│   │   │   └── room.rs
│   │   ├── session/
│   │   │   ├── mod.rs
│   │   │   ├── service.rs
│   │   │   └── store.rs
│   │   └── ice/
│   │       ├── mod.rs
│   │       └── config.rs
│   └── Cargo.toml
├── web/
│   ├── package.json
│   ├── tsconfig.json
│   ├── vite.config.ts
│   ├── index.html
│   └── src/
│       ├── main.ts
│       ├── api/
│       │   ├── session-api.ts
│       │   └── signaling.ts
│       ├── webrtc/
│       │   ├── transport.ts
│       │   └── ice.ts
│       ├── crypto/
│       │   └── crypto-client.ts
│       ├── transfer/
│       │   ├── file-transfer.ts
│       │   └── state.ts
│       └── ui/
│           ├── pages/
│           │   ├── home-page.ts
│           │   ├── send-page.ts
│           │   ├── join-page.ts
│           │   └── expired-page.ts
│           └── components/
│               ├── qr-display.ts
│               ├── file-picker.ts
│               ├── progress-bar.ts
│               └── status-indicator.ts
├── deploy/
│   ├── docker-compose.yml
│   ├── Caddyfile
│   ├── coturn.conf
│   └── filedrop.service
└── README.md

部署拓扑

最小部署:

  • Caddy/Nginx
  • axum app
  • Redis
  • coturn

域名建议:

  • app.example.comWeb App + API + WS
  • turn.example.comTURN 服务

风险与注意事项

  1. Safari 对 WebRTC/DataChannel、后台标签页较敏感
  2. TURN 成本需监控,大文件应尽快切应用层密文中转
  3. 浏览器内存占用,大文件必须按块处理
  4. 断点续传复杂度不适合首版
  5. 端到端加密需覆盖文件名和文件列表