Skip to content

gen 工作线开发文档(passno-gen / passno-totp / passno-match) ​

本文记录 feat/gen 分支在 v0.1 阶段交付的三个核心库 crate、内置外部数据及更新脚本。

1. 交付内容 ​

组件路径职责
passno-gencrates/passno-gen随机密码、EFF 长词表口令短语、PIN 码、Apple PMR 网站密码规则生成与密码强度/熵估算
passno-totpcrates/passno-totpotpauth://totp/... URI 与容错裸 Base32 密钥解析,基于 RFC 6238 生成动态验证码
passno-matchcrates/passno-matchURL 规范化(IDN/punycode、默认端口、尾点、大小写、裸主机)、PSL(含私有段)匹配、PMR 共享凭据组与自动填充排序
词表与 PMR 数据crates/passno-gen/data/EFF 长词表(eff_large_wordlist.txt,CC-BY-3.0 署名见 NOTICE)与 Apple PMR 4 个 JSON 文件(MIT 见 pmr/LICENSE.md)
数据更新脚本tools/update-pmr.sh从 apple/password-manager-resources 拉取最新 quirks/*.json 与 LICENSE.md

2. 构建与测试 ​

在工作区根目录运行:

bash
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test --workspace

刷新内置 Apple PMR 数据(需要网络):

bash
./tools/update-pmr.sh

验证文档同步检查:

bash
./tools/ci/check-docs-sync.sh origin/main HEAD

测试覆盖情况 ​

  • passno-gen(crates/passno-gen/tests/gen_tests.rs):
    • 遍历 uppercase × digits × symbols × avoid_ambiguous × length 全组合样本校验约束与防歧义字符过滤。
    • 每类最少字符数、extra_chars 自定义字符集及非法参数拒绝。
    • EFF 长词表(7,776 词)口令短语(分隔符、首字母大写、附加数字)与 PIN 码生成。
    • 遍历内置 password-rules.json 全部 458 条真实网站规则(含 activision.com、aeon.co.jp、amundi-ee.com、google.com、ototoy.jp 等)与原始 passwordrules 字符串,逐条用 password-rules-parser 校验生成结果完全合规。
    • 统计一致性:4,000 次样本验证首尾位置无字符类偏向;5,000 次 1 位 PIN 验证 0–9 分布均匀。
    • 精确熵公式与 zxcvbn 手输口令强度映射验证。
  • passno-totp(crates/passno-totp/src/lib.rs):
    • 覆盖 RFC 6238 Appendix B 全部 SHA1 / SHA256 / SHA512 测试向量(8 位,时间戳 59 至 20,000,000,000)。
    • 验证 remaining 跨步长边界倒计时、tests/fixtures/import/apple/passwords.csv 中的 otpauth:// 用例、URL 编码标签与参数优先级、空格/连字符/小写/无填充 Base32 容错、Debug 脱敏与非法输入拒绝。
  • passno-match(crates/passno-match/tests/match_tests.rs):
    • 表驱动覆盖 Domain / Host / StartsWith / Exact / Never 五种模式、IDN/punycode、默认端口(80/443)、非默认端口、尾点、大小写、裸主机、HTTPS 禁降级 HTTP、私有 PSL 隔离(a.github.io 不匹配 b.github.io)、单向子域(example.com 匹配 login.example.com,反向不匹配)。
    • 验证 shared-credentials.json 双向共享组(safeway.com ↔ acmemarkets.com)与单向迁移(twitter.com → x.com,反向不匹配)。
    • 验证 tests/fixtures/import/apple/passwords.csv 全部测试 URL 及 Exact > Host > Domain 自动填充排序。

3. 设计决策与依据 ​

  1. 避免 passno-gen 与 passno-match 循环依赖: passno-match 通过 include_str!("../../passno-gen/data/pmr/shared-credentials.json") 直接读取统一存放的 PMR 共享凭据文件,不依赖 passno-gen;passno-gen 则依赖 passno-match 来规范化 for_domain 主机名并查找父域至 eTLD+1 对应的 password-rules.json 规则,做到数据零重复、单向依赖。
  2. 严格对齐 docs/dev/api.md 并提供扩展配置类型: GeneratorOptions、Generated、Strength、GeneratorKind(以及 passno-totp::TotpCode)字段和名称与 docs/dev/api.md 保持 100% 一致,确保其他工作线直接按契约构造结构体字面量即可编译;同时额外导出 RandomOptions、PassphraseOptions、PinOptions、generate_from_rules 与 estimate_user_password,完整覆盖每类最小数量、extra_chars、口令附加数字及原始 passwordrules 字符串。
  3. 密码学随机源与无偏采样: 使用 rand 0.10 的 SysRng(经 UnwrapErr(SysRng) 直接调用 OS CSPRNG),以 random_range 做无偏索引采样,先放入必需字符再经 Fisher-Yates(SliceRandom::shuffle)整体打乱,避免用户态 PRNG 残留或位置偏向。
  4. 精确熵与强度阈值:
    • Random 密码:利用对数空间指数生成函数(EGF)动态规划计算长度 $L$ 且满足各类最小字符数约束后的精确密码空间大小 $\log_2(\text{valid_count})$。
    • Passphrase:$k \cdot \log_2(7776) + (\log_2 10 \text{ 若附加数字})$(首字母大写为确定性变换,不计入额外熵)。
    • Pin:$L \cdot \log_2(|\text{pool}|)$。
    • 生成密码强度阈值:< 40.0 bits → Weak;40.0..60.0 bits → Fair;60.0..80.0 bits → Strong;>= 80.0 bits → VeryStrong(使 6 词口令短语≈77.5 bits 为 Strong,6 词+数字≈80.9 bits 为 VeryStrong)。
    • 手输密码强度:使用 zxcvbn 3.1(score 0–1 → Weak、2 → Fair、3 → Strong、4 → VeryStrong),支持传入 user_inputs 惩罚用户名/邮箱等上下文词汇。
  5. PMR 规则处理细节:
    • 通用 Special / AsciiPrintable / Unicode 字符类默认过滤空格 ' ',避免无意在常规网站密码中插入空格(Custom 类仅在全是空格时保留)。
    • target_len 自动夹紧在 [max(minlength, required.len()), maxlength] 区间内;遇到 max-consecutive 限制时通过保持字符多重集的交换修复与重试确保既满足连续重复上限又不破坏 required 约束。
  6. 密钥内存保护: TotpConfig 内部密钥使用 zeroize 在 Drop 时清零,并自定义 Debug 输出为 [REDACTED]。

4. 已知缺口与 v0.2 待办 ​

  • 契约可选扩展:若 v0.2 需要让桌面端 / CLI 通过单一 GeneratorOptions 直接传入 min_*、extra_chars 或页面抓取到的原始 passwordrules 属性,届时可协商扩展 docs/dev/api.md(当前 v0.1 通过 passno_gen::RandomOptions 与 generate_from_rules 已可调用)。
  • 复杂 PMR 规则熵估值:当 passwordrules 同时包含重叠的 required 组或 max-consecutive 约束时,estimate_rules_entropy 采用允许字符集上界或一阶马尔可夫公式估算,未对任意重叠条件构造精确自动机计数。
  • fromDomainsAreObsoleted 提示:shared-credentials.json 中的 fromDomainsAreObsoleted 标志已解析并保存在 SharedGroupEntry::Migrated,v0.2 浏览器扩展与安全体检可据此向用户提示旧站点条目可更新为新域名。
  • 最小化根 Cargo.toml:当前分支根 Cargo.toml 仅包含本工作线三个 crate,合并进主分支时需由协调者合并进完整 workspace。

文档对应提交 80b7c2d · 由仓库 docs/ 自动生成