EmDash 在预览、评论、认证、存储和插件中使用少量密钥。本页是完整清单:每个密钥的来源、存储位置、轮换方法以及丢失后的影响。
概览
| 密钥 | 来源 | 存储位置 | 丢失影响 |
|---|---|---|---|
EMDASH_ENCRYPTION_KEY | 运维人员 (emdash secrets generate) | 仅环境变量 / Worker 密钥 | 加密的插件密钥变得不可恢复(静态加密上线后) |
| 预览密钥 | 自动生成(env 覆盖) | options 表 (emdash:preview_secret) | 已发放的预览链接失效;新链接正常 |
| IP 盐值 | 自动生成(env 覆盖) | options 表 (emdash:ip_salt) | 评论速率限制连续性重置 |
| 会话和 API 令牌 | 按会话/令牌生成 | 会话存储 / 数据库(仅哈希) | 无影响 — 明文从不存储 |
| OAuth 提供商凭证 | 您(Google/GitHub 控制台) | 环境变量 | 该提供商的登录停止直到替换 |
| Turnstile 密钥 | 您(Cloudflare 仪表板) | 环境变量 | 评论 CAPTCHA 验证失败 |
| S3 凭证 | 您(存储提供商) | 环境变量或配置 | 媒体上传/下载失败直到替换 |
| 插件密钥 | 您(管理后台设置 UI) | 数据库(插件设置/存储) | 在管理后台重新输入 |
| CLI 凭证 | emdash login / emdash plugin publish 设备流 | ~/.config/emdash/auth.json(模式 0600) | 重新运行设备流 |
| 注册表 CLI 凭证 | emdash-plugin atproto OAuth | ~/.emdash/oauth/、~/.emdash/credentials.json(模式 0600) | 重新登录;身份存于您的 PDS |
加密密钥
EMDASH_ENCRYPTION_KEY 是站点用于静态加密插件密钥的密钥。它由运维人员提供,从不存储在数据库中 — 数据库只包含密文,因此泄露的备份不会暴露密钥。
生成一个并设为环境变量(或 Worker 密钥):
npx emdash secrets generate
# emdash_enc_v1_<43 个 base64url 字符>
# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY
格式为 emdash_enc_v1_ 后跟 32 字节随机数据的无填充 base64url 编码。密钥在运行时启动时验证;格式错误的值会记录面向运维人员的错误,但不会中断请求路径。
轮换
变量接受逗号分隔的密钥列表。第一个条目是主密钥,用于新的写入;所有条目都会尝试用于解密。每个加密值都标记了 8 字符的密钥指纹(kid,可通过 emdash secrets fingerprint <key> 打印),因此运行时会自动选择正确的密钥。
轮换方法:生成新密钥,添加到列表前面(EMDASH_ENCRYPTION_KEY="新密钥,旧密钥"),重新部署,在现有值重新加密后移除旧密钥。
生成的站点密钥
两个密钥在首次使用时自动生成并持久化到 options 表中,因此在请求、部署和隔离区间保持稳定。生成是原子性的 — 并发的冷启动会收敛到一个值。
预览密钥
签署预览 URL(HMAC)。存储为 emdash:preview_secret;32 字节随机数据,base64url。
- 覆盖: 如果需要跨多个进程使用相同密钥或出于审计原因固定密钥,请设置
EMDASH_PREVIEW_SECRET(旧别名:PREVIEW_SECRET)。环境变量始终优先于存储值。 - 轮换: 删除
emdash:preview_secret行(或更改 env 变量)并重新部署。影响:之前发放的预览链接停止验证。其他不受影响 — 下次预览请求时会生成新密钥(或从 env 读取)。 - 丢失时: 无不可恢复的内容。预览链接设计上就是短期的。
参阅预览指南了解预览 URL 的构建和验证方式。
IP 盐值
为评论速率限制中使用的评论者 IP 地址 SHA-256 哈希(评论上的 ip_hash)加盐。存储为 emdash:ip_salt。站点特定,因此哈希在 EmDash 安装之间不可关联。
- 覆盖: 设置
EMDASH_IP_SALT。为向后兼容,也会查询EMDASH_AUTH_SECRET/AUTH_SECRET— 历史上从这些值推导盐值的安装保持稳定的哈希。 - 轮换: 更改 env 变量或删除
emdash:ip_salt行。影响:新评论提交产生不同的哈希值,所有人的速率限制计数重新开始。现有评论及其存储的哈希不受影响。 - 丢失时: 无数据丢失。仅速率限制连续性重置。
会话和 API 令牌
- 会话使用 Astro 的会话存储(Cloudflare 上的 Workers KV,Node 上的文件系统)。Cookie 携带不透明的会话 ID;没有需要管理的签名密钥。登出以结束会话,或清除会话存储(例如 KV 命名空间)以强制所有人重新登录。
- API 令牌(
ec_pat_、ec_oat_、ec_ort_前缀)是不透明的 256 位随机值;仅存储其 SHA-256 哈希。明文在创建时显示一次。通过在管理后台撤销并重新创建来轮换。 - 邀请、魔法链接和恢复令牌是单一用途的,以 SHA-256 哈希形式存储在
auth_tokens中,且有时间限制(邀请 7 天,魔法链接 15 分钟)。
无需主动备份或轮换:数据库泄露仅暴露哈希,每个令牌都可以从管理后台撤销或重新发放。
用户提供的服务凭证
外部服务的凭证从环境变量读取,从不写入数据库。在提供商处轮换,更新变量,重新部署。
| 服务 | 变量 |
|---|---|
| Google 登录 | EMDASH_OAUTH_GOOGLE_CLIENT_ID、EMDASH_OAUTH_GOOGLE_CLIENT_SECRET(或无前缀别名) |
| GitHub 登录 | EMDASH_OAUTH_GITHUB_CLIENT_ID、EMDASH_OAUTH_GITHUB_CLIENT_SECRET(或无前缀别名) |
| Marketplace 发布(CI) | EMDASH_MARKETPLACE_TOKEN |
| Turnstile(评论) | EMDASH_TURNSTILE_SECRET_KEY(或 TURNSTILE_SECRET_KEY) |
| S3 兼容存储 | S3_ACCESS_KEY_ID、S3_SECRET_ACCESS_KEY、S3_ENDPOINT、S3_BUCKET、S3_REGION |
在 Cloudflare 上使用 wrangler secret put 设置;本地放在 .env 中。通过绑定使用 R2 无需凭证 — 访问由 wrangler.jsonc 中的绑定授权,这是 Workers 上推荐的设置。参阅存储选项。
插件密钥
插件用 type: "secret" 声明的设置(邮件提供商 API 密钥、表单 CAPTCHA 等)在管理 UI 中输入并存储在数据库中 — 在 options 表的 plugin:<id>:settings:<key> 下,或在插件的键值存储中。存储的密钥是否返回到管理 UI 取决于插件;编写良好的插件仅返回”值已设置”标志而非密钥本身(内置的表单插件就是这样做的)。
- 轮换: 在提供商处轮换密钥并将新值粘贴到插件的设置页面。立即生效。
- 丢失时: 在管理后台重新输入值。无其他依赖。
CLI 凭证
emdash CLI 持有两种凭证,都在 ~/.config/emdash/auth.json(遵循 XDG_CONFIG_HOME)中,以仅所有者权限(0600)创建:
- 站点令牌 —
emdash login通过 OAuth 设备流对您的 EmDash 实例进行认证,并将结果令牌按实例 URL 索引存储。emdash logout将其移除;每次调用时--token或EMDASH_TOKEN覆盖存储的令牌。 - Marketplace 令牌 —
emdash plugin publish通过 GitHub 设备流对 EmDash Marketplace 进行认证,并将结果 JWT 以marketplace:<origin>索引存储。对于 CI 发布,请设置EMDASH_MARKETPLACE_TOKEN— 它优先于存储的凭证。
丢失文件是无害的:重新运行 emdash login(或 emdash plugin publish,它会重新运行设备流)。
插件注册表 CLI 凭证
独立的 emdash-plugin CLI(包 @emdash-cms/plugin-cli)面向实验性的 AT Protocol 注册表。在那里发布与您的 AT Protocol 身份(您的发布者 DID)绑定 — 站点本身不持有发布凭证,安装会根据归属于该 DID 的发布记录中的校验和验证工件。
- 通过 atproto OAuth 认证。OAuth 会话/状态 blob 存在于
~/.emdash/oauth/,发布者身份(DID、handle、PDS)缓存在~/.emdash/credentials.json;两者都以仅所有者权限写入。 - 在 CI 中,通过
EMDASH_PUBLISHER_DID、EMDASH_PUBLISHER_HANDLE和EMDASH_PUBLISHER_PDS提供身份;EMDASH_REGISTRY_URL覆盖注册表主机。CI 的自动publish仍需要运行器上~/.emdash/oauth/中的 OAuth 会话文件 — 环境变量本身不携带 OAuth 会话。 - 发布访问的轮换或撤销在您的 AT Protocol 帐户(例如应用密码)中进行,而非在 EmDash 中。参阅 Atmosphere auth。
轮换快速参考
| 我想要… | 操作方法 |
|---|---|
| 轮换加密密钥 | 在前面添加新密钥:EMDASH_ENCRYPTION_KEY="新密钥,旧密钥",重新部署,之后移除旧密钥 |
| 使所有预览链接失效 | 删除 emdash:preview_secret 选项行(或更改 env 覆盖) |
| 重置评论速率限制哈希 | 更改 EMDASH_IP_SALT(或删除 emdash:ip_salt 选项行) |
| 撤销泄露的 API 令牌 | 管理后台 → 用户 → API 令牌 → 撤销,然后创建替代 |
| 终止所有会话 | 清除会话存储(Workers KV 命名空间 / 会话目录) |
| 替换提供商凭证 | 在提供商处轮换,更新 env 变量,重新部署 |
| 替换插件 API 密钥 | 在提供商处轮换,在插件的管理后台设置中重新输入 |