使用手册 · 双语 · 面向第一次接触更新签名的你
Keyward 使用手册
这本手册面向第一次接触更新签名的用户。它不假设你懂任何密码学, 也不假设你用过任何类似工具。跟着章节一步步做,你会完成: 安装 → 建库/接库 → 认识界面 → 日常操作 → 把钥匙接进 CI → 发布带更新的版本 → 轮换钥匙 → 出事时的自救。
读法建议:第 0 章是背景(10 分钟,强烈建议读);第 1–3 章带你上手; 第 4–5 章是日常操作参考;第 6 章是发版与轮换(做完一遍你就全通了); 附录是速查表,用的时候翻。
0. 背景知识:为什么需要这个东西(10 分钟)
0.1 你的应用是怎么“自己更新”的
你写了一个桌面应用,用户装在了自己电脑上。某天你修了个 bug,发布了 1.0.1 版。 用户电脑上的 1.0.0 怎么知道该更新、怎么确认下载下来的东西是你发的?
主流方案(Sparkle、Tauri updater、electron-updater、WinSparkle、Google Omaha, 全都是这一套)分三步:
- 你的应用启动时去一个固定网址拉一份更新清单(一个小 JSON 文件,里面写着“最新版本是 1.0.1,安装包在哪,它的 SHA-256 是多少”);
- 清单附带一个签名——这是用一把只有你持有的私钥对清单内容算出来的数学印记;
- 你的应用出厂时就内置了配对的公钥,用它验证签名对得上,才敢下载并安装。
类比:更新清单是信,私钥是你的私人印章,公钥是发给每个用户的印鉴样本。 印章只在你手里,别人仿不出你的印。
0.2 唯一的麻烦:那把私钥
公钥嵌在应用里,公开没关系。私钥必须只有你有——一旦泄漏,别人就能冒充你给所有用户推恶意更新; 一旦丢失,你就再也发不出任何用户能通过的更新(所有老用户断更)。
而现实中的事故从来不是黑客,是日常手滑:
- 调试时一条命令把私钥内容打进了聊天记录/日志;
- 测试用的 PEM 文件忘在工作目录里,跟着仓库公开了;
- 私钥只存在 CI 的 secret 里,没留任何备份,有一天手滑删了;
- 轮换了新钥,某个角落里的旧钥副本忘了删。
Keyward 就是管这些的:它给你一个桌面界面,把所有产品的签名钥匙集中在一个文件里 (放在你自己的同步盘),并替你守住四条纪律——值永不显示(只能复制)、每次改动先自动快照 (丢了能一键恢复)、一键体检(钥匙是否健康、公私钥是否配对)、生成钥匙直接入库(不留任何散落文件)。
0.3 Keyward 不管什么
- 密钥库引擎不联网;剪贴板与用户自选同步文件夹仍可能将私钥复制到其他进程或设备。密钥库是明文 INI,不等于硬件安全模块。
- 它不管理网站 API key、npm token、SSH 私钥这类东西(只放产品更新/发布签名钥);
- 它不发明新格式——库就是一个纯文本 INI 文件,放在你自己的同步盘里,任何编辑器都能打开它。
1. 安装与首次启动
1.1 安装(macOS)
两种方式,选其一:
方式 A:下载安装包(推荐)
打开 https://keyward.jrtx.site → 点击“下载” → 下载 DMG →
双击打开 → 把 Keyward 图标拖进“应用程序”文件夹。
方式 B:从源码构建(开发者)
git clone https://github.com/turinglambdaai/keyward
cd keyward
raco rivet package # 产物在 dist/keyward.app
把 dist/keyward.app 拖进“应用程序”即可。
1.2 首次启动:选择你的钥匙库
第一次打开 Keyward,主界面会显示 “No vault selected”(未选择库)和一个 “Choose Vault…” 按钮。
- 还没有库?先跳到第 2 章,花两分钟建一个,再回来点这个按钮。
- 已有库?点 “Choose Vault…”,在文件选择框里选中你的
secrets.ini,点“打开”。
选择会被永久记住(存在 ~/.keyward/config.json,里面只有路径、没有任何钥值),
以后每次启动直接进入你的库,不再询问。
这个文件是什么?它就是你的钥匙库——一个纯文本 INI 文件。每个产品一个
[产品名] 小节,小节里一行一条 名字 = 值。它应该放在你的同步盘
(iCloud/Resilio/坚果云…)里,这样多台设备自然就有备份。Keyward 不关心文件在哪,你选哪它读哪。
1.3 认识界面(30 秒导览)
- 左侧栏:三块概览磁贴(Products 产品总数 / Paired 配对正常的数量 / Attention 需要注意的数量)+ 产品列表。每行前面的小圆点:绿=健康,灰=这个产品还没有钥,黄=有问题(点开看)。
- 右侧内容区:点了某个产品后显示它的详情——产品名 + 徽章(条目数 / key id / 指纹 / 状态)、Deep Check 结果徽章、Entries 列表。
- 底部状态栏:操作反馈 + 当前库的路径。
- 快捷键:
⌘O选择库 ·⌘R一键体检 ·⌘L快照列表。
2. 建库(还没有库的人看这里)
- 打开“文本编辑”(TextEdit)或任何纯文本编辑器(不要用 Word,要纯文本格式);
- 新建一个文件,内容可以先只有一行注释:
# 我的更新签名钥库 - 保存为
secrets.ini,位置放进你的同步盘文件夹(例如~/Sync/Keys/secrets.ini); - 回到 Keyward,点 “Choose Vault…”,选中它。
就这些。以后每把钥都以“条目”的形式加进这个小节里(第 4 章教)。 不要把这个文件放进任何 git 仓库。
3. Deep Check:一键看懂全库健康状况
点右上角 Deep Check(或按 ⌘R)。Keyward 会把库里每把私钥读出来、
验证它和公钥是否配对、算出指纹,然后给你一屏结果。
每个产品的状态词是什么意思、该做什么:
| 状态词 | 意思 | 你要做的事 |
|---|
徽章解读(产品页顶部):
entries这个产品小节有几条;key id钥匙代号(如myapp-2026-10,惯例是产品名-年-月);fingerprint指纹——公钥的“人脸”,16 位十六进制。同一把钥在任何地方指纹都一样,核对两把钥是否相同,对指纹即可;kind钥匙类型(Ed25519 / RSA);paired公私钥是否配对(yes配对 /missing-public库里没存公钥 /no对不上)。
4. 日常操作(每步都截图级)
通用前提:先在左侧点中一个产品(行会高亮),右侧出现它的详情。以下操作都在右侧详情区完成。
4.1 复制一个值(最常用的操作)
场景:你要把私钥贴到 GitHub 的 CI secret 里,或贴到应用源码里。
- 选中产品,在 Entries 列表里找到那条(比如
UPDATE_ED25519_PRIVATE_KEY_B64); - 鼠标悬停在这一行上 → 行尾出现 Copy 按钮 → 点击;(或点行尾
⋯菜单 → “Copy value to clipboard”) - 值已进剪贴板,去粘贴。界面上任何地方都不会显示值——这是故意的,防偷窥防误贴。
4.2 新建一条
- Entries 区右上角
+菜单 → New entry…; - 弹窗里填两条:NAME(大写字母+数字+下划线,如
UPDATE_ED25519_PRIVATE_KEY_B64)和 value(必须单行); - 点 Set。每次改动都会先自动拍快照(第 5 章),不怕改错。
命名惯例(rivet 系产品的三件套,照抄即可):
| 条目名 | 装什么 |
|---|
4.3 从 PEM 文件导入(手上已有 key.pem 的人)
+菜单 → Import PEM file…(或目标条目的⋯菜单 → Import PEM file…);- 选你的
xxx.pem文件; - Keyward 把它转成单行 base64 存进库——原文件还在你手上,想删现在就可以删了(库里已有完整副本)。
4.4 生成一把全新的更新钥匙对(从零开始的人看这里)
场景:你的产品要做在线更新,这是第一把钥。
- 选中产品 →
+菜单 → Generate update key…; - 看一遍确认框的文字,点 Generate;
- 完成后库里自动多出 4 个条目(就是 4.2 表里的三件套 + key id),状态栏会显示新钥匙的指纹。
接下来把公钥“钉”进你的应用(这一步让已装出去的应用认识新钥):
- 复制
UPDATE_ED25519_PUBLIC_KEY_RAW_TAIL32_B64的值 → 粘贴到你应用里验签代码的公钥锚位置(rivet 应用在更新模块和原生宿主里,各有一处形如"XXXX…="的字符串常量); UPDATE_ED25519_PUBLIC_KEY_SPKI_B64的值给需要 DER 形态的地方。
再把私钥配进 CI(让 CI 能签出合法清单):
- GitHub 仓库 → Settings → Secrets and variables → Actions → New repository secret;
- Name 填你的 workflow 约定的名字(rivet 系常为
UPDATE_ED25519_PRIVATE_KEY,各家不同,看你仓库的 release workflow); - Secret 的值:注意形态。Keyward 里存的是 base64(DER);如果你的 workflow 直接要 PEM 文本,用这一行命令转换(把
base64der换成你复制的值):
输出以echo 'base64der' | base64 -d | openssl pkey -inform DER-----BEGIN PRIVATE KEY-----开头的整段就是 secret 的值。
4.5 删除一条
条目 ⋯ 菜单 → Delete… → 确认。删除前 Keyward 自动拍了快照,删错了去第 5 章恢复。
4.6 多个库 / 换库
菜单栏 Vault → Choose Vault…(⌘O),选另一个 secrets.ini。选择会覆盖记忆(上一次的选择不再保留)。
5. 快照:你的“后悔药”
机制:每次对库的任何修改(生成/导入/改/删/恢复)之前,Keyward 都会先把整个库原样复制一份,
存到库所在文件夹的 .history/keyward/ 里。这个文件夹和库在同一个同步盘里,
所以每台同步设备上都有一份完整历史。
恢复:工具栏 Snapshots(⌘L)→ 每行是一个快照(时间戳+大小)→ 点 Restore。 恢复本身也会先给当前状态拍一张快照,所以“恢复错了”还能再恢复回来。永不丢,放心改。
6. 发布一个带更新的版本(完整闭环,做完一遍你就毕业了)
6.1 钥匙在发布链路里的位置
Keyward 库 ──复制──▶ GitHub Secret ──CI 发版时读取──▶ 签出 update-manifest.json
│
已装应用(内置公钥验签)◀── 用户应用自动下载安装 ◀── 发布到 Releases
记住三句话:
- 私钥只该存在于两处:你的 Keyward 库、GitHub 的 secret;
- 公钥嵌在应用源码里(随应用发布给所有用户);
- 发版时钥匙不需要动——CI 自动用 secret 里的私钥签名。
6.2 第一次给产品配置更新签名(10 分钟)
以一个 rivet 系产品为例(其他框架步骤相同,只是公钥嵌入位置不同):
- 生成钥匙:Keyward 里选中该产品 → Generate update key…(第 4.4 节);
- 嵌公钥:把
UPDATE_ED25519_PUBLIC_KEY_RAW_TAIL32_B64的值粘贴到应用源码里验签模块的公钥常量(rivet 应用=更新模块一处 + 各原生宿主一处;改完提交并推送); - 配 CI secret:GitHub → Settings → Secrets and variables → Actions → New repository secret(第 4.4 节的形态转换注意);
- 发一个版本验证:打 tag 推送,让 CI 出包。装到你自己机器上,用应用内“检查更新”确认能通过验证并升级。
6.3 日常发版(钥匙没变时)
钥匙不需要任何操作。发版前按 ⌘R 做 Deep Check,全绿就放心发。
如果哪个产品不是 ok,先按第 3 章的表处置。
6.4 轮换钥匙(定期保健,或泄漏后自救)
什么时候轮换:怀疑泄漏(立即);或定期(比如每半年)。
两阶段流程(先让所有用户“认识”新钥,再启用新钥):
- 第一阶段:在 Keyward 里生成新钥对(它会成为库里该产品的现役钥)。⚠️ 先不要动 GitHub secret——把新公钥嵌进应用源码,正常发一个版本。这个版本用旧钥签名,所以老用户能正常自动升级;升级后的用户内置了新公钥。
- 第二阶段:等第一阶段版本发布后,把 GitHub secret 换成新私钥(第 4.1 节复制 → 粘贴覆盖 secret;注意第 4.4 节的形态转换)。之后再发的版本全部由新钥签名。
- 收尾:全机搜索旧钥散件(旧 PEM 文件、旧 secret 名)并删除;Keyward 库里如果还留着旧钥条目,删除(有快照兜底)。
泄漏后的急迫版本:流程相同,但第一阶段发布后尽快做第二阶段,并在发布说明里告知 “旧版本用户需手动下载更新一次”。
6.5 事故处理速查
| 事故 | 处置 |
|---|
7. 多设备与团队
- 库在同步盘里 = 每台同步设备上都有一份完整钥匙库 + 完整快照历史。在 A 机器上用 Keyward 改了什么,B 机器打开就是新的。
- 每台机器都装一个 Keyward,都指向同一个
secrets.ini。 - 铁律:库(和
.history)永远不进 git、不进网盘分享链接、不进截图。 - 团队场景(多人可信):把同步盘成员限制到必需的人;人员离队时轮换所有钥(6.4)。
8. 安全模型,一句话版
库是明文的——这是设计决策:同步只发生在你自己的信任设备之间,防“丢”靠多设备同步+快照, 防“偷”靠各机全盘加密(FileVault / BitLocker / LUKS)。Keyward 引擎零网络代码,钥匙不出你的电脑。
附录
附录 A:快捷键
| 快捷键 | 动作 |
|---|
附录 B:常见问题
附录 C:术语表(人话版)
| 词 | 人话 |
|---|