magic-wormhole 版本演进全解析:从 0.2.0 到 0.24.0 的功能、安全与协议变迁
2026/9/20 3:16:55 网站建设 项目流程
  • CLI
  • 密码学

【免费下载链接】magic-wormhole

get things from one computer to another, safely

项目地址:https://gitcode.com/gh_mirrors/ma/magic-wormhole
点击查看免费下载

magic-wormhole 是一个"在两台电脑之间安全传输文件/文本"的开源工具,其核心设计是让两端用户说出同一句魔法口令(code)即可建立一条端到端加密的数据通道。本文以仓库根目录的 NEWS.md 为主线,系统梳理该工具从 0.2.0 初始版本到 0.24.0 的完整版本演进:包括 CLI 命令的诞生与重构、Tor/QR 码/Dilation 等关键能力的引入、两起路径遍历漏洞(CVE)的修复过程,以及程序化 API 的多次破坏性变更。读完本文,你将理解 magic-wormhole 每个核心特性"为什么存在、何时出现、如何实现",并能依据版本差异安全地升级或选择正确的使用方法。

一、版本总览:一条持续十余年的演进线

NEWS.md 记录了从 2015 年 4 月的 0.2.0(初始版本)到 2026 年 5 月的 0.24.0 共二十余个版本的变更。整体演进可分为四个阶段:

  • 协议奠基期(0.2.0 ~ 0.8.x):确立"口令交换 + 中继 + PAKE"的对称协议,完成 CLI 子命令体系(send/receive/ssh)、WebSocket 连接、目录打包传输等基础能力;
  • 稳定与生态拆分期(0.9.x ~ 0.13.0):Tor 支持重写、转口中继(Transit Relay)与邮箱服务器(Mailbox Server)拆分为独立仓库、Python 2.7 停止支持、首个安全修复(恶意文件名清洗)落地;
  • Dilation 落地期(0.12.0 ~ 0.20.0):实验性 Dilation 协议引入并逐步成熟,新增状态反馈 API、Ping/Pong 超时、命名子协议(named subprotocol)与子通道组合能力;
  • 安全加固与现代化期(0.21.x ~ 0.24.0):修复两起路径遍历漏洞(CVE-2026-42448 及其前序回归)、排除有问题的 Autobahn 依赖、二维码默认展示、Bash < 4 补全等。

从源码结构看,当前仓库 src/wormhole/ 下的模块布局正是这些版本演进的沉淀结果:_mailbox.py(邮箱消息)、_key.py(密钥派生)、transit.py(大块数据传输)、_dilation/(新一代传输协议)等。

二、CLI 命令体系的成型史

2.1 从"一个可执行文件"到"子命令 + 别名"

早期版本(0.7.5 之前)CLI 通过单一wormhole可执行程序区分 send/receive 模式。0.7.5 起包同时安装wormhole(send/receive)与wormhole-server(中继服务器)两个可执行文件。0.8.1 引入 Click 参数解析并带来短别名:wormhole tx等价于wormhole sendwormhole rx等价于wormhole receive;0.8.2 又接纳recv作为receive的别名("to help bad spelers")。

这些别名至今仍保留在 src/wormhole/cli/cli.py 中:

ALIASES = { "tx": "send", "rx": "receive", "recieve": "receive", "recv": "receive", }

2.2 顶层参数与子命令参数的分工(0.8.1 关键变更)

0.8.1 将大多数参数从"wormhole 命令"挪到子命令上。按当前 cli.py 的实现,顶层仅保留四个参数

参数默认值说明
--appid=自定义应用 ID,供脚本/包装程序使用(0.9.0 加入)
--relay-url=公共中继地址(见public_relay.RENDEZVOUS_RELAY邮箱中继服务器 URL,支持wss(TLS,0.12.0 起)
--transit-helper=公共转中继地址(见public_relay.TRANSIT_RELAY大块数据传输中继
--dump-timing=调试:将事件时间线写入 JSON 文件(0.7.0 引入)

其中--relay-url--transit-helper均支持环境变量WORMHOLE_RELAY_URLWORMHOLE_TRANSIT_HELPER(0.10.4 加入)。

wormhole send的子命令参数包括:--code(人工指定口令)、--text(发送文本,-表示从 stdin 读取)、--ignore-unsendable-files(0.10.0 加入,跳过不可读文件/悬空符号链接)、--verify(展示验证串并等待人工确认)、--code-length(口令长度,默认 2 个单词)、--qr/--no-qr(0.18.0 起默认展示二维码,可用环境变量WORMHOLE_QR控制)、--debug-state(调试状态机迁移,可选机器为B,N,M,S,O,K,SK,R,RC,L,C,T)。

wormhole receive的独有参数包括:--output-file/-o(覆盖接收文件名/目录,0.6.1 实现)、--only-text/-t(拒绝文件传输)、--accept-file(跳过确认自动接受,0.18.0 加入,支持环境变量WORMHOLE_ACCEPT_FILE)、--allocate/-a(分配新口令而非输入,0.13.0 加入)。

0.10.3 起wormhole helpwormhole --help行为一致;0.20.0 还新增了magic-wormhole作为 CLI 入口命令。

2.3 口令输入与 Tab 补全

接收端支持 Tab 补全输入口令:wormhole receive若检测到用户未使用 Tab 键,会提示 "(note: you can use to complete words)"(0.9.2 起)。0.8.1 起 Tab 补全在 OS-X 自带 Python(libedit)下也能工作。底层实现见 cmd_receive.py 中的input_with_completion。0.10.3 起会在入口处拒绝非法口令(含空格或非数字前缀)。

2.4 零模式(zeromode)与分配口令

-0/--zeromode使用固定口令0-进入"无口令模式";receive --allocate则让接收端反向分配口令,随后发送端可用wormhole send --code <code>连接(0.13.0 加入)。分配成功后接收端会打印提示:

Allocated code: <code> On the other computer, please run: wormhole send --code <code> <filename>

注意 cli.py 中做了参数互斥校验:使用--allocate时不能再传 code,--code-length必须与--allocate搭配。

三、数据传输能力的时间线

3.1 文件、文本与目录

  • 0.6.1:开始支持发送/接收整个目录(传输前打包为 zipfile);
  • 0.10.0wormhole send DIRECTORY支持大于 2GB 的目录,但当时 zipfile 仍在内存中构建,受可用内存限制;
  • 0.12.0:真正用tempfile将大目录的 zipfile 写到磁盘上,"修复了一个五年历史、导致大于可用内存的目录传输失败的 bug";
  • 0.14.0:目录打包改为流式压缩(streaming compression),配合 cmd_send.py 中基于zipstream.ngZipStream实现;
  • 0.13.0:接收目录时超过 10MB 才落盘(SpooledTemporaryFile(max_size=10*1000*1000),见 cmd_receive.py)。

3.2 块设备发送(0.12.0)

wormhole send /dev/fd0可以发送命名块设备(U 盘、SD 卡、软盘等),对端收到的是普通文件。该逻辑位于 cmd_send.py:通过stat.S_ISBLK判断设备类型后按文件方式读取。

3.3 传输确认与校验

发送端在数据发送完毕后等待接收端回执(ack),其中包含 SHA-256 哈希:{"ack": "ok", "sha256": <hex>}(见 cmd_receive.py)。发送端比对本地计算的哈希与对端回传值,不一致则报 "Transfer failed (bad remote hash)"(见 cmd_send.py)。

3.4 进度条与磁盘空间检查

  • 0.7.6 起使用tqdm渲染进度条,可用--hide-progress关闭;0.19.0 修复了进度条尺寸自适应问题;
  • 0.9.0 起wormhole receive会在空间不足时拒绝传输(estimate_free_space,Windows 上不可用);
  • 0.12.0 起"接受此文件?"的默认答案从 no 改为 yes。

四、安全演进:从漏洞修复到防护机制

4.1 恶意文件名清洗(0.13.0,SECURITY)

0.13.0 修复"接收端显示中的怪异字符"问题(#476),对接收端展示的文件名进行清理。相关防护在 cmd_receive.py 中有明确注释:对repr()的使用"至少部分是为了防御可能干扰终端显示的恶意文件名"。

4.2 路径遍历漏洞与 CVE(0.21 ~ 0.24,SECURITY 重点)

这是近期版本中最重要的安全内容,NEWS.md 明确记录了两起漏洞:

  • 0.23.0(2026-03-10):@ikmckenz 发现一次回归删除了basename()的使用,使接收端暴露于路径名遍历攻击(path-name traversal),影响 0.21 与 0.22 两个版本。修复已随 0.23.0 发布并附带单元测试;
  • 0.24.0(2026-05-05):@marduc812 发现当接收端通过--output指定了一个已存在的目录时,同样存在缺失basename()的问题,编号 CVE-2026-42448。缓解措施是确保--output指向的路径不是已存在的目录,并升级到修复版本。

当前源码中的防护逻辑位于_decide_destname()(cmd_receive.py):无论是否使用--output-file,最终目标路径都会经过os.path.basename(destname)清洗;当--output-file指向已存在目录时,接收文件会被安全地放入该目录内部(而不覆盖整个目录树)。代码注释明确写道:"the basename() is intended to protect us against '~/.ssh/authorized_keys' and other attacks"。

仓库测试 test_cli.py 提供了成体系的回归验证:

  • _decide_destname("file", "../../evil.txt")必须被清洗为提取目录下的evil.txt(L1233);
  • test_existing_destdir_malicious验证对已存在输出目录传入../../../destination_file也不会逃逸(L1254-L1269);
  • test_destdir_traversal使用 Hypothesis 属性测试随机生成含..的路径段组合,断言_decide_destname的返回路径永远在基础目录之内(L1282-L1310)。

4.3 zipfile 解压防护

接收目录解压时,_extract_file()(cmd_receive.py)会校验解压目标不得逃逸出extract_dir,否则抛出 "malicious zipfile" 异常;同时手动恢复 zip 内记录的文件权限位(external_attr >> 16),因为 zipfile 模块本身不恢复权限。

4.4 其他安全相关变更

  • 0.8.2:目标文件已存在时不向发送端泄露该事实,仅回复 "transfer rejected";
  • 0.9.1:中继服务器支持--blur-usage关闭连接日志;0.6.x 起服务器可模糊化文件大小、粗化时间戳;
  • 0.10.1/0.10.2:服务器默认不再主动广播 CLI 版本(避免不必要的升级提醒);WebSocket 连接错误改为可读报错而非automat._core.NoTransition崩溃;
  • 0.13.0:所有历史版本二进制签名全部提交进 Git(signatures/目录),因为 PyPI 停止提供分离签名文件——这在 signatures/ 中可以看到从 0.7.0 到 0.24.0 的.asc文件;
  • 0.21.0:当用户代码要求时,对不需要的入站子协议产生错误;0.22.0 在连接丢失时对挂起的receive_record()调用执行 errback。

五、Tor 支持:从试验到默认依赖

Tor 能力经历了三个阶段:

  • 0.7.0(初步)pip install magic-wormhole[tor]后运行wormhole --tor send,自述"不稳定且缺乏测试";
  • 0.9.2(重写)wormhole sendreceivessh invitessh accept统一接受三个参数--tor(所有连接走 Tor 并隐藏 IP)、--launch-tor(自行启动 Tor 进程)、--tor-control-port=(指定控制端口)。当时的限制是仅支持 python2.7、需安装[tor]extra;
  • 0.10.0(默认依赖)txtorcon成为默认依赖,移除[tor]extra,只要系统装有 Tor 可执行文件即可用;Tor 同时支持 py3;0.10.4 修复了此前完全失效的--tor-control-port=,未指定时先尝试默认控制端口再回退到默认 SOCKS 端口。

当前 CLI 中的 Tor 参数定义见 cli.py,实际连接管理位于 tor_manager.py,测试 test_tor_manager.py 覆盖相关逻辑。

六、Dilation:新一代传输协议

Dilation 是 NEWS.md 中反复出现的技术主线,值得单列一节。

6.1 从实验到 API 定型

  • 0.12.0(2020-04):引入不完整的 Dilation 实验实现(#312),目标是实现断点续传、网络地址变化容忍、长驻 GUI/守护进程中的双向传输。当时协议未定稿、与旧 Transit 协议不兼容、无 CLI 入口,代码仅用于防回归与开发;
  • 0.19.0(2025-05):为 Dilation 增加"状态反馈"API(#591),并用该 API 在代码被对方使用时通知发送端(#575);新增 Ping/Pong 超时以加速重连(#590);改进版本协商(#606/#611);测试套件全面迁移到 pytest(#603/#610);
  • 0.20.0(2025-07)INCOMPAT——Dilation 扩展现在支持子通道(subchannel)组合,每个子通道有命名子协议(named subprotocol),并配套新 API,同时移除了通用的 "control" 子通道;Dilation 状态更新中附带hints信息(转中继提示)。

6.2 命名子协议与子通道 API

当前 src/wormhole/_dilation/manager.py 中,DilatedWormhole提供两个核心方法(L75-L107):

  • listener_for(subprotocol_name):返回IStreamServerEndpoint,用于监听指定名称的新子通道,listen()后每个新连接都会调用所给 Factory 的buildProtocol()
  • connector_for(subprotocol_name):返回IStreamClientEndpoint,用于向对端发起指定子协议的连接,对端会看到一个 OPEN 并实例化对应的 listener。

集成测试 test_dilate/test_full.py 展示了真实用法:eps1.listener_for("proto").listen(fserv0)配合eps2.connector_for("proto").connect(f2)建立单子协议通道(L52-L79),以及在同一链路上承载hello/bonjour两个不同名称子协议的test_double_subprotocol(L97-L136)。

6.3 Dilation 版本协商

Dilation 版本号以《地海传说》中的巫师命名,当前为["ged"](manager.py)。双方通过can-dilate版本列表取交集选择最佳版本(_find_shared_versions,L168-L189);若对端不支持 Dilation,w.dilate()会在收到 VERSIONS(KCM) 后 errback(L155-L156)。

6.4 状态反馈 API

0.19.0 引入的 Status API 定义在 src/wormhole/_status.py:通过类型联合表达邮件箱连接状态(Disconnected | Connecting | Connected | Failed | Closed)、密钥状态(NoKey | AllegedSharedKey | ConfirmedKey)、口令状态(NoCode | AllocatedCode | ConsumedCode)以及 Dilation 专用的对端连接状态(NoPeer | ConnectingPeer | ConnectedPeer | ReconnectingPeer | StoppedPeer)。

发送端在 cmd_send.py 中通过on_status_update回调订阅状态:当口令从AllocatedCode变为ConsumedCode时,向用户打印 "Note: code has been consumed and can no longer be used."——这正是 0.19.0 中"使用状态 API 在口令被消费时通知发送用户"的落地实现。

七、SSH 公钥互传:wormhole ssh invite/accept

0.8.2 加入实验性的wormhole ssh invitewormhole ssh accept子命令,用于安全地把你的~/.ssh/id_*.pub公钥追加进远端~/.ssh/authorized_keys

  • wormhole ssh invite [--user USER]:等待对方发送公钥;
  • wormhole ssh accept CODE [--key-file/-F PATH] [--yes/-y]:发送指定公钥(未指定时若~/.ssh/*.pub唯一则自动选择,多个则交互询问)。

实现见 cli.py 与 cmd_ssh.py:find_public_key()负责枚举.pub文件并解析出kind / keyid / pubkey三元组,发送前默认要求确认。0.13.0 还修复了"带注释的 SSH 密钥"解析问题(#434)。

八、程序化 API 的破坏性变更史

NEWS.md 反复强调"1.0 之前 API 不稳定",开发者在升级客户端代码时需注意以下断点:

  • 0.4.0:协议改为对称形式,内部布局重排,所有import wormhole的应用必须更新;
  • 0.8.0(完全协议重写).send_data()/.get_data()改为.send()/.get()且不再接受 phase 参数(Wormhole 成为记录管道);.get_verifier()改为.verify()并等待密钥确认消息;Wormhole 由函数调用构造而非类构造;close()总是等待服务器对出站消息的 ack;
  • 0.10.0:客户端代码用 Automat 状态机完全重写,附带"Journaled Mode(日志模式)"铺垫(详见 docs/journal.rst);
  • 0.19.0(打包变更):sdist 文件名改用下划线(magic_wormhole-0.19.0.tar.gz),原因是 setuptools v69.3.0 于 2024 年实现了 PEP 625。

中继服务也同步演进:0.11.0 将 Rendezvous Server(更名 Mailbox Server)拆分为独立仓库magic-wormhole-mailbox-server;0.10.4 将 Transit Relay 拆分为magic-wormhole-transit-relay。运行自有服务器需分别pip install这两个包,当前客户端仅为测试导入它们。

九、性能、可用性与依赖治理

  • 启动速度(0.10.5):升级 python-spake2 后不再为未使用的参数集计算盲化因子,Raspberry Pi 3 上wormhole --version从约 19 秒降到 7 秒;
  • 长连接保活(0.8.1):双方定期发送 keep-alive 消息,防止 NAT/防火墙因空闲断开导致双方永久挂起;
  • 长时间等待(0.6.0):增加密钥确认消息,避免接收方输错口令时发送方一直挂起;0.12.0 修复双方同时--verify时接收方无法展示验证串的死锁(#349);
  • 转中继优先级(0.9.1)--transit-helper tcp:host:port:priority=2.5支持数值优先级,双方交换中继建议后优先尝试最高优先级中继,直连永远优先于中继;
  • 依赖排除:0.21.0 排除 autobahn 24.9.1/25.10.1,0.21.1 排除 25.10.2(Windows 故障),0.22.0 排除 25.11.1/25.12.1——这是 Autobahn 发布质量问题引发的连锁治理;
  • Python 版本策略:0.13.0 弃用 Python 2.7 与 3.5/3.6;0.18.0 弃用 3.8;0.19.0 弃用 3.9 并将 CI 迁移至 GitHub Actions;0.20.0 全面清除 Python 2 痕迹(移除u前缀、type()调用改为直接使用类、格式化字符串改为 f-string)。

十、运维与打包

  • 服务器参数(0.10.3)wormhole-server start新增--relay-database-path--stats-json-path--websocket-protocol-option=--disallow-list可禁用 nameplate 列表请求(即禁用口令数字前缀的 Tab 补全,同时让 DoS 更易检测,0.10.0);提升 RLIMIT_NOFILE 以容纳更多并发连接;"crowded"(拥挤)邮箱会直接向客户端返回错误(0.10.3),客户端据此提示用户重新生成口令而非反复重连(错误文案见 cli.py);
  • 命令行补全(0.14.0):为 bash、zsh、fish 提供补全文件,见仓库根目录的 wormhole_complete.bash、wormhole_complete.zsh、wormhole_complete.fish;0.21.0 新增面向 macOS 的 Bash < 4.0 补全补丁 bash-completions-version-4.patch;
  • 打包渠道:0.9.2 加入 snapcraft 打包配置(snapcraft.yaml);0.18.0 支持 PEP 518(pyproject.toml);0.19.1 修复 sdist 中测试运行与测试服务器版本号报告问题;
  • 调试利器--dump-timing=FILE.json可记录双方事件时间线并合并分析延迟(0.7.0),配套可视化脚本见 misc/dump-timing.py;--debug-state可观察 Automat 状态机迁移轨迹。

十一、升级建议与兼容性速查

依据 NEWS.md 的兼容性声明,可按以下原则规划升级:

  1. 协议兼容:0.8.0 与 0.7.x 完全互不兼容(但老客户端"察觉不到"新客户端);0.9.x 起转中继要求双方均 ≥ 0.9.0;其余相邻版本大体保持前后兼容;
  2. 必须升级的安全版本:0.13.0(文件名清洗)、0.23.0(路径遍历回归修复)、0.24.0(CVE-2026-42448 修复)——尤其当你会用wormhole receive --output指向已存在目录时;
  3. 依赖锁定:若受 Autobahn 发布问题困扰,优先升级到 0.22.0+(已排除 25.11.1/25.12.1);
  4. Python 版本:当前版本要求 Python ≥ 3.10(0.19.0 起弃用 3.9);
  5. API 使用者:若你的代码依赖 0.7.x 之前的.send_data()/.get_data()等接口,需按 0.8.0 的 API 文档迁移;Dilation 子协议 API(0.20.0 定型)仍属实验性质,版本命名与行为可能继续调整。

如需深入某一模块,可直接阅读 docs/ 下的协议文档(如 docs/client-protocol.rst、docs/file-transfer-protocol.rst、docs/dilation-protocol.rst、docs/transit.rst)与对应源码 src/wormhole/,将版本史与实现细节相互印证。

  • CLI
  • 密码学

【免费下载链接】magic-wormhole

get things from one computer to another, safely

项目地址:https://gitcode.com/gh_mirrors/ma/magic-wormhole
点击查看免费下载
上一篇:Mailtrain GDPR合规性:用户数据保护与隐私政策配置终极指南
下一篇:Go语言高级编程:CGO异常栈追踪,调试跨语言问题的终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询