基于 QSP 项目的多设备联机逻辑实现的文档共享方案,支持网页端访问和多设备 P2P 同步。
- 抗量子加密传输:使用 Kyber 密钥交换 + AES-256-GCM 加密
- P2P 直连:通过 UDP 打洞实现 NAT 穿透,无需中继服务器
- 网页端访问:提供 Web 界面进行文档管理
- 多设备同步:文档可在多个设备间 P2P 传输共享
- 身份验证:基于 Dilithium 数字签名的节点身份认证
co_documents/
├── __init__.py # 模块初始化
├── main.py # 启动入口
├── document_server.py # Flask Web 服务器
├── p2p_document_sharing.py # P2P 文档共享核心
├── templates/
│ ├── index.html # 文档管理页面
│ └── peers.html # 节点连接页面
└── static/ # 静态资源目录
pip install flask
# QSP 项目依赖已在 requirements.txt 中定义# 仅 Web 服务(不启用 P2P)
python -m co_documents.main
# 启用 P2P 网络功能
python -m co_documents.main --enable-p2p --p2p-port 19999
# 指定端口和存储目录
python -m co_documents.main --port 8080 --storage ./my_documents打开浏览器访问 http://localhost:5000
在文档管理页面点击上传区域或拖拽文件进行上传。
- 在"节点连接"页面复制本机邀请码
- 在另一设备上粘贴邀请码并点击"连接"
- 连接成功后可进行文档分享
- 广播:点击"广播文档"向所有已连接节点分享本地文档列表
- 单独分享:点击文档行的"分享"按钮选择目标节点
本项目引用了 QSP 项目的核心网络模块实现 P2P 文档共享功能。以下是具体引用位置和用途:
文件位置:src/network/p2p_manager.py
引用代码示例:
# co_documents/p2p_document_sharing.py
from src.network.p2p_manager import P2PNode, InviteCodeManager
class P2PDocumentSharing:
def start_p2p(self, host: str = "0.0.0.0", port: int = 19999,
static_sk=None, dil_pk=b"", dil_sk=None):
self.p2p_node = P2PNode(
host=host,
port=port,
static_sk=static_sk,
dil_pk=dil_pk
)
# 通过 STUN 发现公网坐标
self.p2p_node.discover_public_coordinates()
# 启动监听
self.p2p_node.start()核心功能:
discover_public_coordinates(): 通过 STUN 服务器发现公网 IP/端口generate_invite_code(): 生成包含坐标和公钥指纹的邀请码connect_via_invite(): 解析邀请码并执行 UDP 打洞连接
文件位置:src/network/p2p_manager.py#L36-L80
引用代码示例:
# co_documents/p2p_document_sharing.py
from src.network.p2p_manager import STUNClient
class MyNode:
def __init__(self, sock):
self.stun_client = STUNClient(sock)
self.stun_client.discover_public_coordinates()
print(f"公网坐标: {self.stun_client.public_ip}:{self.stun_client.public_port}")STUN 服务器配置:
STUN_SERVERS = [
('stun.qq.com', 3478), # 腾讯 STUN
('stun.miwifi.com', 3478), # 小米 STUN
('stun.aliyun.com', 3478), # 阿里云 STUN
('stun.l.google.com', 19302), # Google
]文件位置:src/network/p2p_manager.py#L82-L93
引用代码示例:
# co_documents/p2p_document_sharing.py
from src.network.p2p_manager import InviteCodeManager
# 生成邀请码
invite_code = InviteCodeManager.generate_invite_code(
local_ip="192.168.1.100",
local_port=19999,
public_ip="123.456.78.90",
public_port=19999,
dil_pk=node_public_key
)
# 格式: QSP-Invite://Base64编码的压缩数据
# 解析邀请码
info = InviteCodeManager.parse_invite_code(invite_code)
# 返回: {"lip": "...", "lport": ..., "pip": "...", "pport": ..., "fp": "..."}文件位置:src/network/secure_link.py
引用代码示例:
# co_documents/p2p_document_sharing.py
from src.network.secure_link import SecureLink
# 创建安全链路(服务端/客户端)
link = SecureLink(
send_raw_fn=self._send_raw,
peer_addr=addr,
session_id=session_id,
role='server', # 或 'client'
peer_fp=peer_fingerprint,
local_pk=self.dil_pk,
local_sk=self.static_sk
)
# 设置数据接收回调
link.on_app_data_received = lambda peer_id, data: \
self.router.route_message(peer_id, data)核心回调:
on_link_established: 连接建立(握手完成)时触发on_app_data_received: 收到解密数据时触发on_link_closed: 连接关闭时触发
引用代码示例:
# co_documents/p2p_document_sharing.py
from src.app.app_router import AppRouter
from src.app.app_protocol import AppCmd
class P2PDocumentSharing:
def __init__(self):
self.router = AppRouter()
self.router.register_handler(AppCmd.SHARE_PUSH, self._handle_doc_upload)
self.router.register_handler(AppCmd.PULL_REQ, self._handle_doc_download)
self.router.register_handler(AppCmd.PULL_RESP, self._handle_doc_response)
def on_data_received(self, peer_id, data):
# 强制身份覆写:使用底层验证的 peer_id
self.router.route_message(peer_id, data)安全特性:
- 强制身份覆写机制:绝不信任报文自称的身份,使用底层密码学验证的真实 ID
- 防止身份伪造攻击
引用代码示例:
# co_documents/p2p_document_sharing.py
from src.app.app_protocol import AppMessage, AppCmd
# 构造消息
msg = AppMessage(
cmd=AppCmd.SHARE_PUSH,
file_hash=doc_hash,
share_data=json_payload.encode('utf-8'),
chunk_index=0,
total_chunks=10
)
# 序列化发送
packet_data = msg.pack()
# 反序列化接收
received_msg = AppMessage.unpack(packet_data)消息格式:
{
"cmd": "SHARE_PUSH",
"file_hash": "abc123...",
"chunk_index": 0,
"total_chunks": 10,
"share_data_b64": "base64编码的数据"
}引用代码示例:
# co_documents/p2p_document_sharing.py
from src.network.protocol import QSPProtocol, PacketType
# 打包数据包
pkt = QSPProtocol.pack(
PacketType.DATA,
seq=chunk_index,
payload=encrypted_data,
session_id=self.session_id
)
# 发送
self._send_raw(pkt, peer_addr)
# 解包接收
parsed = QSPProtocol.unpack(data)
msg_type = parsed['type'] # PacketType.DATA
payload = parsed['payload']协议头格式:
MAGIC (2B) + VERSION (1B) + TYPE (1B) + SESSION_ID (4B) +
SEQ (4B) + ACK (4B) + TIMESTAMP (8B) + PAYLOAD_LEN (2B) + PAYLOAD
文件位置:src/network/protocol.py#L10-L22
数据包类型:
class PacketType(IntEnum):
# NAT 穿透信令
HOLEPUNCH = 0x01 # UDP 打洞包
HOLEPUNCH_ACK = 0x02 # 打洞确认
KEEPALIVE = 0x03 # 心跳保活
# 抗量子安全握手
HANDSHAKE_INIT = 0x10 # 握手初始化
HANDSHAKE_RESP = 0x11 # 握手响应
# RUDP 可靠传输
DATA = 0x20 # 数据包
ACK = 0x21 # 确认
SACK = 0x22 # 选择性确认
FIN = 0x2F # 结束文件位置:src/network/p2p_manager.py#L26-L32
引用代码示例:
# co_documents/p2p_document_sharing.py
from src.network.p2p_manager import PunchState
class P2PDocumentSharing:
def connect_to_peer(self, invite_code):
self.p2p_node.connect_via_invite(invite_code, session_id)
# 等待打洞完成
while self.p2p_node.punch_state == PunchState.PUNCHING:
time.sleep(0.1)
if self.p2p_node.punch_state == PunchState.CONNECTED:
print("打洞成功!")
else:
print("打洞失败!")状态流转:
IDLE -> PUNCHING -> CONNECTED
↓
FAILED
文件位置:src/network/rudp.py
引用代码示例:
# 在 SecureLink 中自动使用
from src.network.rudp import RUDPConnection
# SecureLink.handle_network_packet 中已集成 RUDP
# 用于确保文档分块的可靠传输
deliverable, current_ack, sack_blocks = self.rudp.receive_data(seq, cleartext)| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/documents |
获取文档列表 |
| POST | /api/documents |
上传文档 |
| GET | /api/documents/<doc_id> |
下载文档 |
| DELETE | /api/documents/<doc_id> |
删除文档 |
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/p2p/status |
获取 P2P 连接状态 |
| GET | /api/p2p/invite |
获取本机邀请码 |
| POST | /api/p2p/connect |
连接对等节点 |
| POST | /api/p2p/share/<doc_id> |
分享文档到节点 |
| POST | /api/p2p/broadcast |
广播文档列表 |
- 使用 STUN 协议发现公网坐标
- 双方同时发送 UDP 包建立连接
- 支持对称型 NAT 和端口限制型 NAT
- 使用 Kyber 算法进行密钥交换
- 即使量子计算机也无法破解
- 密钥前向安全性
- 基于 Dilithium 数字签名
- 连接双方验证对方身份
- 防止中间人攻击
- AES-256-GCM 加密文档内容
- 每个连接使用独立的会话密钥
- 完美前向保密
本项目依赖 QSP 项目的基础模块:
src/network/p2p_manager.py- P2P 节点管理src/network/secure_link.py- 安全链路src/network/protocol.py- 网络协议src/network/rudp.py- 可靠 UDPsrc/app/app_router.py- 消息路由src/app/app_protocol.py- 应用协议src/crypto_lattice/keygen.py- 密钥生成
完整依赖列表请参考 requirements.txt。
- 防火墙设置:确保 UDP 端口(如 19999)对端可访问
- NAT 类型:某些严格 NAT 可能导致打洞失败
- 邀请码格式:
QSP-Invite://开头,请完整复制 - 文档大小:建议单文件不超过 1GB 以获得最佳性能
- 网络断开:P2P 连接为直接连接,网络断开后需重新连接
继承 QSP 项目的 License。