Conversation
DPAPI 默认把密钥绑定到当前 Windows 账户,而一份安装只有一份 config/。 同一台机器换个账户启动后,load() 把本账户解不开的密文当成明文又加密一层, 再顺着脏标记写回配置文件,账号密码从此变成一串密文文本且无法恢复。 - 加密改用机器作用域,同机各账户都能解开;解密侧无需改动,作用域写在密文 里,CryptUnprotectData 与 .NET ProtectedData 都会忽略调用方传入的作用域 - 配置项按 DPAPI 结构而非「能否解密」区分存量密文与用户新填的明文 - 解不开的密文落盘原样保留、读取给占位提示,并允许用户直接覆盖重填 存量密文不受影响:旧的用户作用域密文继续正常解密,也不会被自动重写; 需要跨账户共享时由用户重新填写一次。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
审查者指南本 PR 将新生成的 DPAPI 密文切换为机器作用域,并在配置层按 blob 结构区分密文与明文,从而避免跨账户启动时改写存量密文;不可解密的密文原样落盘、读取时显示占位提示且可被用户重新填写,同时保留旧用户作用域密文的解密兼容性。 跨账户加载密钥及防止覆盖的时序图sequenceDiagram
participant AccountA as Windows账户A
participant Config as 配置项
participant File as 配置文件
participant AccountB as Windows账户B
participant DPAPI as DPAPI
AccountA->>Config: setValue(明文)
Config->>DPAPI: dpapi_encrypt(明文)
DPAPI-->>Config: 机器作用域 DPAPI blob
Config->>File: 保存(blob)
AccountB->>Config: 加载(blob)
Config->>Config: looks_like_dpapi_blob(blob)
Config->>DPAPI: dpapi_decrypt(blob)
DPAPI-->>Config: 已解密的密钥
Config-->>AccountB: 密钥值
AccountB->>Config: setValue(新明文)
Config->>Config: looks_like_dpapi_blob(新明文)
Config->>DPAPI: dpapi_encrypt(新明文)
DPAPI-->>Config: 机器作用域 DPAPI blob
Config->>File: 保存(新 blob)
保留不可读 DPAPI 密钥的流程图flowchart TD
A[已加载配置值] --> B{looks_like_dpapi_blob}
B -->|否| C[dpapi_encrypt 明文]
B -->|是| D{dpapi_decrypt 成功}
D -->|是| E[使用已解密的密钥]
D -->|否| F[保持 blob 不变]
F --> G[返回 UNREADABLE_SECRET_PLACEHOLDER 以供显示]
G --> H[用户输入替换值]
H --> C
文件级变更
提示和命令与 Sourcery 交互
自定义使用体验访问你的控制面板以:
获取帮助Original review guide in EnglishReviewer's Guide本 PR 将新生成的 DPAPI 密文切换为机器作用域,并在配置层按 blob 结构区分密文与明文,从而避免跨账户启动时改写存量密文;不可解密的密文原样落盘、读取时显示占位提示且可被用户重新填写,同时保留旧用户作用域密文的解密兼容性。 Sequence diagram for cross-account secret loading and overwrite protectionsequenceDiagram
participant AccountA as WindowsAccountA
participant Config as ConfigItem
participant File as ConfigFile
participant AccountB as WindowsAccountB
participant DPAPI as DPAPI
AccountA->>Config: setValue(plaintext)
Config->>DPAPI: dpapi_encrypt(plaintext)
DPAPI-->>Config: machine-scope DPAPI blob
Config->>File: save(blob)
AccountB->>Config: load(blob)
Config->>Config: looks_like_dpapi_blob(blob)
Config->>DPAPI: dpapi_decrypt(blob)
DPAPI-->>Config: decrypted secret
Config-->>AccountB: secret value
AccountB->>Config: setValue(new plaintext)
Config->>Config: looks_like_dpapi_blob(new plaintext)
Config->>DPAPI: dpapi_encrypt(new plaintext)
DPAPI-->>Config: machine-scope DPAPI blob
Config->>File: save(new blob)
Flow diagram for preserving unreadable DPAPI secretsflowchart TD
A[Config value loaded] --> B{looks_like_dpapi_blob}
B -->|No| C[dpapi_encrypt plaintext]
B -->|Yes| D{dpapi_decrypt succeeds}
D -->|Yes| E[Use decrypted secret]
D -->|No| F[Keep blob unchanged]
F --> G[Return UNREADABLE_SECRET_PLACEHOLDER for display]
G --> H[User enters replacement]
H --> C
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
同一台电脑上有多个 Windows 账户轮流启动同一份安装时,换账户后已保存的账号密码会变成一串密文文本,每次都要重新填写。
config/。ConfigItem.setValue用「能否解密」来区分明文和密文,于是换账户启动后,本账户解不开的密文被当成明文又加密了一层,再顺着load()的脏标记写回配置文件,原密码不可恢复。CRYPTPROTECT_LOCAL_MACHINE),同一台机器的各账户都能解开。解密侧不动:作用域写在密文里,CryptUnprotectData与 .NETProtectedData都会忽略调用方传入的作用域。setValue的相等性判断也不再因解密失败抛错,用户可以直接覆盖重填。app/task/HSR/tools/sra_runtime.py把 MAS 的密文原样写进 SRA 的 startGame 配置、由 SRA 自己解),不能加版本前缀或 entropy 来做自动迁移,因此跨账户共享需要用户重新填写一次。本地验证
Windows 11 / Python 3.12 / 本分支 worktree 的
.venv。回归测试
python -m pytest tests:1053 passed, 4 skippedpython -m pytest tests --collect-only -q:退出码 0ruff check与ruff format --diff:本 PR 改动的文件全绿(仓库基线另有 9 处既有告警,均在本 PR 未触及的文件里)全字段端到端
反射取出全部 25 个声明
EncryptValidator的字段(各专项Info.Password、HSR Info.Id与Direct.SRAConfig/M7AConfig、三处MirrorChyanCDK、7 个签到 token、3 个通知密钥等),每个字段走真实的connect()(读文件 →load()→ 脏则写回)后检查落盘内容,对比修复前后:「解不开的密文」用了三种构造:DPAPI 真实生成但读取时不提供对应 entropy(未经任何手工改动)、真实密文抹掉 master key GUID、以及密文被截断,三者走的代码路径一致、结果一致;手工把明文填进配置文件的情况也照常加密后正常读回。
另单独驱动
MultipleConfig(UserData)这一层,覆盖 HSR 用户的账号与密码:修复前落盘被改写、toDict(if_decrypt=False)取到的也已变质(会一起带进 SRA 配置),修复后全部通过。兼容性
CurrentUser/LocalMachinescope 四种组合均解密成功,确认改动对 SRA 侧透明;getValue(if_decrypt=False)交给 SRA 的密文与配置文件逐字一致。🤖 Generated with Claude Code