edit | blame | history | raw

Bilibili 已登录会话扩展零手工标准加载设计 V004

1. 修订范围与基线

  • 原事项:DEV-PROJECT-INFO-BILI-AUTHENTICATED-SESSION-DOWNLOAD-20260805-001
  • 上游需求:REQ-BILI-DYNAMIC-COLLECTOR-20260804-001
  • 唯一 owner:dev.developer.project.secondary / infodev-2
  • 唯一审核员:dev.reviewer.project / inforev
  • 基础方案:CODE-DESIGN-PROJECT-INFO-BILI-AUTHENTICATED-EXTENSION-MANAGED-LOAD-V003.md=17715/1EC7F6D8D6CD6AA9BEE5F5696D1CB578514CA3C61ADA838777093C8EFEF2C2F1
  • V003 审核:HOLD/6,审计 ID=DEV-AUDIT-PROJECT-INFO-BILI-AUTHENTICATED-EXTENSION-MANAGED-LOAD-V003-DESIGN-20260810-001

本文件只闭合 F1—F6。V003 未被本文件替换的合同继续有效;发生文字冲突时,本 V004 优先。总体路径继续唯一为 Chrome Web Store 签名发布物加 Windows ExtensionInstallForcelist,不回退到 chrome://extensions、unpacked、命令行加载、CDP、profile 注入、自托管更新服务或第三方 Host。

本修订仍是设计阶段。bili_authenticated_extension_managed_load/ 代码、测试、图标文件和候选 ZIP 均不得在 V004 PASS/0 前创建。Web Store 发布、policy/HKCU、Chrome、Cookie/session、网络、下载、真实媒体、F:\video、formal ana-data 和转写保持为0。

2. F1:可上传的确定性 packaging overlay

2.1 不修改冻结运行时

原扩展源码树继续固定为 17/17 exact,source manifest 固定为:

dev/project-dev/bili_authenticated_extension/source-artifact-manifest.json|3681|333BA59512C5F68B35C00B8C9738C8B26FB78285F05851F9F35BA3FC44819535

manifest.json 与四个运行时文件不得改写。Web Store 包中的 manifest.json 由 source-controlled managed-load-contract.json 内的 packaging overlay 精确投影;其余四个运行时文件仍逐字取自冻结源码。manifest overlay 只允许相对原对象追加以下字段,其他 key、value、顺序和语义全部逐项相等:

"icons": {
  "16": "icons/icon16.png",
  "32": "icons/icon32.png",
  "48": "icons/icon48.png",
  "128": "icons/icon128.png"
}

overlay manifest 固定为 UTF-8、无 BOM、LF、末尾一个 LF、2-space indent,精确实物为:

  • bytes=1150
  • SHA-256=92F2E950BA5CA5ECDA5A0F167DD90FB19449D4CC3AE1C6AB7AB404A337BA7A43
  • canonical base64:
ewogICJtYW5pZmVzdF92ZXJzaW9uIjogMywKICAibmFtZSI6ICJwcm9qZWN0LWluZm8gQmlsaWJpbGkg5a6M5pW06KeG6aKR5YWl5Y+jIiwKICAidmVyc2lvbiI6ICIxLjAuMCIsCiAgInZlcnNpb25fbmFtZSI6ICIxLjAuMCsyMDI2MDgwNS52MDAyIiwKICAiZGVzY3JpcHRpb24iOiAi5LuF5aSE55CG5bey5o6I5p2D55qEIEJWMUhBM282b0VKSiDlrozmlbTop4bpopHku7vliqHjgIIiLAogICJrZXkiOiAiTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF0MmRUMUhHWWFJMERYTTd6WndPVE5CV1hUS2xNQkpNcHlEVmpSVWMrdjZiVW90bUx5b3JhQytheTJzY3k5VVFsdVNaVllxMHRTOHF2UU5OdnVaT2xjNXcyYk9FeG00VEgySUlLdmFWTzhuVnRoSEJuTnoya1hkaU04SXROMHZQWkVtUys4Z3BUQ0kxKzZ3UFR1VWdsTW9YcHFZQlloaWk4Zko1UmtFTlJGM1BSSkJCaWdHdDhzb3FkQkZSWTFRWlVtcFF2OWRZdzRkUnE0TDJDNFF0QmdDbFVnNGJRcHVDcHBpVlo5TEhiZVBpOUlBamM5cjlSOTNLTHpwYUJ1WGRKcGZWUkU1dy82WUhueFA4b3ZYeEJkbDdYa3RtcmRIM3hqN21XVDdRN1pCeGtETnduMlJrcnVENDVYZ0REM3l1TnhPWVNrTEZNa3NlTitVYTY5Z1NTNHdJREFRQUIiLAogICJwZXJtaXNzaW9ucyI6IFsKICAgICJhY3RpdmVUYWIiLAogICAgImNvb2tpZXMiLAogICAgIm5hdGl2ZU1lc3NhZ2luZyIsCiAgICAic2NyaXB0aW5nIiwKICAgICJzaWRlUGFuZWwiCiAgXSwKICAiaG9zdF9wZXJtaXNzaW9ucyI6IFsKICAgICJodHRwczovL3d3dy5iaWxpYmlsaS5jb20vKiIKICBdLAogICJiYWNrZ3JvdW5kIjogewogICAgInNlcnZpY2Vfd29ya2VyIjogImJhY2tncm91bmQuanMiLAogICAgInR5cGUiOiAibW9kdWxlIgogIH0sCiAgInNpZGVfcGFuZWwiOiB7CiAgICAiZGVmYXVsdF9wYXRoIjogInNpZGVwYW5lbC5odG1sIgogIH0sCiAgImFjdGlvbiI6IHsKICAgICJkZWZhdWx0X3RpdGxlIjogIuaJk+W8gOWujOaVtOinhumikeS7u+WKoSIKICB9LAogICJpY29ucyI6IHsKICAgICIxNiI6ICJpY29ucy9pY29uMTYucG5nIiwKICAgICIzMiI6ICJpY29ucy9pY29uMzIucG5nIiwKICAgICI0OCI6ICJpY29ucy9pY29uNDgucG5nIiwKICAgICIxMjgiOiAiaWNvbnMvaWNvbjEyOC5wbmciCiAgfQp9Cg==

builder 必须 base64 严格解码、复算 bytes/SHA、严格 JSON 解析并证明相对原 manifest 只有上述 icons 差异;不得由 PowerShell JSON serializer 重新生成或容忍额外差异。

2.2 四个 exact PNG

四个 icon 以 canonical base64 存在 managed-load-contract.json,方案 PASS 后才由 builder 解码为 ZIP entry,不在原17文件树内新建资产:

entry bytes SHA-256 canonical base64
icons/icon16.png 109 FC9FC7B26C322BD264CF991FE92D5929446F1536201A9B8F4CDD4294ACB17EB3 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAANElEQVR42mMQMQn7TwlmGJwGgADFBhBrCF4DiDGEoAGEDCLaAFyG0M+AgQnEgUtIQyszAQCnXe2u8NCwkgAAAABJRU5ErkJggg==
icons/icon32.png 151 B18E2B064885BF2E682F6F4CF403554538AFBCED15E13DB90B0FD699A4508828 iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAXklEQVR42u3WwQ0AIAgDQIZwFGdx/000biBQQmJLwo/HPQjUxly7s00AAQR4HbzVDqhAuAFoSBiAQqQACAgEkEHAAFEIHOBFlAA8kD8BnEvIeYg4nxFvIFEmFECAqj7bk5WwHfB3ywAAAABJRU5ErkJggg==
icons/icon48.png 187 66BB68173A0DC211E4F1A6A5ABCB97AA466F83D42909817E3D197FCD3F7DDA97 iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAgklEQVR42u3YgQnAQAhD0Ruio3SW7r9JSzconEkqfsEBHhynZh3ndXfuBQAAAAAAAADoDHirPSCJKAOkIOUAN0ICcEKkAAdCDlBDbAAVwgpQQCKASkQMUAWJA3YRvwDsQACMf0J8owyyKasE6zQHzZSTkliFYItsFAAAAAAAAADwuR8pbeAzuPoqrAAAAABJRU5ErkJggg==
icons/icon128.png 405 FF72913CB2486830A8503E7B7E71FFCD2F51D7E13A9881ED3D1A4ECA09582210 iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAABXElEQVR42u3cUQ3EIAAFQUQgpVrw7wRSEfywc8ka6Jvk7lrSMb+11W24CAC4EAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJAAAgAASAABIAAEAACQAAIAAEgAK70f4wWBwABACAAAAEAIAAAAQAgAAABACAAAAEAIAAAAQAgAAABACAAAAEAIAAAAQAgAAABACAAAAEAIAAAAgAQAAACABAAAAIAcQQAxCEAEEcAQBwCAHEEAMQhAAAAAL4CAPAjEAB/AwFwIwgAt4IB8DAIAI+DAXAgBABHwgBwKBQAx8IBeHB4AIwPQHl4AIwPQHl4AIwPQHl4AIwPgBdFelUsADUARg8DMHgUgKHDAIwcBWDcMADDRgEYNAzAmFEARgwDMGAUgOHCAIwWBiAABIAAEAACQAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJAAAgAASAABIAAEAAAuAjpDuyucugIpcc7AAAAAElFTkSuQmCC

PNG 还必须由独立 parser 验证 signature、IHDR 尺寸、RGBA 8-bit、CRC、IDAT 可解压、scanline 长度和 IEND;只核对 hash 不足以接受损坏图像。

2.3 新 exact payload

ZIP entry 集合由5项修订为恰好9项:overlay manifest.json、原 background.js/sidepanel.html/sidepanel.css/sidepanel.js 四文件及上表四个 icon。manifest public key、版本、权限和 Native Host identity 不变,独立派生 extension ID 仍必须等于 oidmclckpdmpabbfedplkbdplmfcenbb。旧 exact-five 正例废止,改为负例;ZIP 缺 icon、尺寸错误、CRC 错误、额外图标或 manifest 任意其他差异均在输出接受前阻断。

3. F2:reviewer-owned source approval

正式 source approval 只能在 V004 实现审核 PASS/0 后由原 reviewer 创建,位于源码树、测试树、候选输出树和正式安装树之外。建议路径为 reviewer 私有 worklog;developer 不得创建、覆盖、自签或把临时 fixture 当正式批准。

schema 固定为1,顶层 exact keys 为:

schema
scope
status
task_id
approved_by_role
managed_load_contract
original_source_manifest
managed_load_source_tree
webstore_payload
implementation_review
approved_at

固定值和子合同:

  • scope=controlled-webstore-upload-source
  • status=APPROVED
  • task_id 为本事项 exact 值
  • approved_by_role=dev.reviewer.project
  • managed_load_contract={path,bytes,sha256}
  • original_source_manifest={path,bytes,sha256},必须是 3681/333BA5...19535
  • managed_load_source_tree={file_count,tree_sha256},tree hash 对实现目录 excluding approval/output 按 path UTF-8 + NUL + bytes ASCII + NUL + lowercase sha256 + LF 排序计算
  • webstore_payload={entry_count,payload_tree_sha256,entries};entries 为9项 exact {path,bytes,sha256}
  • implementation_review={audit_id,audit_path,audit_bytes,audit_sha256,verdict},verdict 必须为 PASS
  • approved_at 为带时区 RFC3339

正式 builder 的 -ValidateOnly/-Build 都必须由管理调度同时传入 approval 的 exact path、bytes 和 SHA-256,并在任何输出前复算。approval 只要任一绑定实物、实现审核或 exact set 漂移即失效;没有“按时间自动延长”或旧 approval fallback。

实现审核前的离线单元测试只允许在 TemporaryDirectory 构造 scope=test-only-controlled-webstore-upload-source 的 synthetic fixture,通过不可从生产 CLI 选择的内部 adapter 注入;生产参数和环境不能开启 test scope。测试必须证明 developer 自签、同树 approval、旧实现审核、错误角色/scope/status 和额外 key 均失败。

4. F3:秘密值和持久化 sink 门禁

V003 第10节“按字段名单词递归拒绝”废止。cookies permission、chrome.cookies API、cookie_store_id 和冻结内存协议字段是合法公开标识符,不因名称出现而阻断。

新的门禁由三层组成:

  1. 原17文件、四个运行时 payload 依靠 source manifest exact bytes/SHA,任何注入秘密值都会先成为 E_SOURCE_DRIFT
  2. contract、build receipt、source/release/install approvals、pending/final/recovery receipts 全部使用 exact key set 和受限值域;release evidence 只允许 exact item ID、version、公开状态枚举、公开 store URL、RFC3339 时间和 hashes,不允许 free-text、账号、邮箱、header、query、Cookie 或 token 文件。
  3. 工具永不枚举/序列化环境变量、Chrome profile、浏览器存储或进程命令行;错误输出只含固定 error code,不回显输入值、registry data 或外部正文。

测试使用唯一合成值:

MBX_TEST_SECRET_SENTINEL_7E21A9B9C9DD4E33B72BDCB7D43168B4

把该 sentinel 分别注入 unexpected JSON value、release evidence、审批路径名、合成 registry data、环境变量和错误对象;均须在业务写前失败或被固定错误码替代,且 sentinel 不得进入 ZIP、receipt、stdout/stderr、日志、argv 快照或证据。额外静态负例拒绝 credential literal、Authorization/Cookie header、signed media URL、.pem/private-key、Chrome profile/Cookies 数据复制和任何 secret output sink。文档中用于描述边界的单词及冻结运行时公开 API 不算 secret evidence。

5. F4:PowerShell 实际异常模型

产品实现保持 PowerShell,不再使用 Python BaseException/KeyboardInterrupt/SystemExit 术语。唯一口径为:

  • 所有 cmdlet 与 .NET 边界均使用 terminating error;Set-StrictMode -Version Latest$ErrorActionPreference='Stop'
  • 安全门禁在任何持久化前失败:SAFETY_STOP/exit 3,stdout 为单行 canonical JSON,stderr 只含固定 E_*
  • 普通 terminating error 在 pending 已存在后触发恢复:恢复成功为 FAILED_ROLLED_BACK/exit 4;原 ErrorRecord 仅以固定 error code/hash 写外部失败证据,不回显 message/stack 中的路径或值。
  • 可捕获的 [System.Management.Automation.PipelineStoppedException]/合作式取消执行同一恢复,恢复后 exit 130 且不得输出成功终态。
  • 真实 Ctrl+C 若 PowerShell 将其交付为 PipelineStoppedException,走上条;若宿主直接终止进程,则没有 stdout/exit 精确合同,由第6节 reopen recovery 收口。
  • Stop-Process -Force、进程崩溃和掉电均视为不可捕获中断;不得声称 catch/finally 已覆盖。

测试分别用 terminating .NET exception、显式 PipelineStoppedException、实际子进程 Ctrl+C(若测试宿主支持)和 Stop-Process -Force。不再测试或声称“原类型重抛”。非普通终止的核心断言是无成功终态、无伪 final receipt、下次启动按唯一恢复矩阵收口。

6. F5:durable intent、commit point 与 crash-reopen

6.1 既有 receipt parent 与互斥

install approval 必须冻结一个已存在、普通、非 reparse、位于当前用户 LocalAppData 项目边界内的 receipt parent;installer 不创建或替换 parent。四个目标文件在审批时必须 absent:

  • managed-extension-install-pending.json
  • managed-extension-install-receipt.json
  • managed-extension-install-recovery-receipt.json
  • managed-extension-rollback-pending.json

rollback final/recovery 文件路径也由 install receipt 冻结并在 rollback 前证明 absent。每个操作使用 CreateNew -> FileStream.Flush(true) -> same-volume atomic rename 写文件;不覆盖。

任何公开模式先取得 current-user named mutex:Local\project-info-bili-managed-load-{SHA256(user SID + policy key)前24位},再执行 recovery-before-normal-mode。mutex 防止本工具并发;完整 policy preimage 的最后复算负责识别外部漂移。

6.2 install pending 与 commit

安装 pending 是在 policy 写入前持久化的 immutable intent,exact fields 至少包含:

  • schema=1operation=installphase=PREPARED
  • lower UUID run_id、task、created_at、owner SID hash
  • contract/source/release/install approvals 的 exact bytes/SHA
  • policy key、target name、expected kind=String、expected data hash/length
  • 第7节完整 canonical preimage
  • final receipt path、commit rule=FINAL_RECEIPT_ATOMIC_RENAME

pending 成功落盘后才允许最后一次 preimage 复算和 target-absent 检查,再写 exact policy value。写后必须复算完整 postimage;其他 values 与 preimage 一致,target 是唯一新增项。final install receipt 先写临时文件并 Flush(true),其 atomic rename 到 absent final path 是唯一 commit point。pending 在成功后保留且由 final receipt 绑定,不清理、不改写。

6.3 install reopen 矩阵

每次启动在普通门禁前检查 pending/final:

持久化状态 当前 policy 动作
final exact 存在 exact committed postimage 视为已提交;Install 安全停止,HealthCheck 可继续
pending exact、final absent exact preimage 写 CreateNew recovery receipt=NO_POLICY_MUTATION;不改 registry
pending exact、final absent exact preimage + 本 target exact 仅删除本 target,复算恢复 exact preimage,写 recovery receipt=INSTALL_PREIMAGE_RESTORED
pending exact、final absent target/其他 value/key 任意漂移 SAFETY_STOP/E_RECOVERY_AMBIGUOUS;不覆盖、不删除
final/pending/temp 任一 schema/hash/binding 不明 任意 SAFETY_STOP/E_RECEIPT;保留现场

install recovery 完成后不自动重试。原 approval/receipt 文件名已消费;下一次安装必须由管理员形成新 approval 和全新 absent receipt paths。

6.4 rollback pending、commit 与 reopen

Rollback 在 exact committed install state 下先写 immutable rollback pending,绑定 install receipt、active postimage、目标 value 和 rollback final path;删除目标后验证 policy 恢复 exact install preimage。rollback final receipt atomic rename 是唯一 rollback commit point,pending 同样保留。

持久化状态 当前 policy 动作
rollback final exact exact install preimage(target absent) 视为 rollback 已提交
rollback pending、final absent exact active postimage 写 recovery receipt=NO_POLICY_MUTATION;保持 active
rollback pending、final absent exact install preimage(target absent) 只恢复 exact target,验证 active postimage,写 recovery receipt=ROLLBACK_ACTIVE_PREIMAGE_RESTORED
rollback pending、final absent 任意其他状态 SAFETY_STOP/E_RECOVERY_AMBIGUOUS;不写 registry

外部 drift、target 被改成非 exact data、其他 values 漂移或所有权记录不明时,恢复不得猜测。失败证据只能写入管理员批准的独立 failure root,不能改写 manifest-bound 或正式 receipt。

6.5 crash-reopen 离线验收

Python 测试以 TemporaryDirectory 的 file-registry adapter 启动真实子 PowerShell;在 pending flush、最后 preimage check、value write/delete、postimage verify、final temp flush、final rename 前后各以 marker 同步,然后 Stop-Process -Force。每点重新启动实际入口,断言唯一矩阵、无伪成功 receipt、无自动重试、其他 values bytes 不变。还要覆盖 unknown temp、pending 篡改、target exact/非 exact、其他 value drift 与 recovery receipt 写失败;歧义态必须零 registry mutation。

7. F6:统一 canonical policy preimage

7.1 值编码

install approval、install pending/final、rollback pending/final 和 HealthCheck 共同使用一个 source-controlled canonical 算法。preimage exact keys:

key_exists
target_value_name
target_absent
values
canonical_sha256

values 按 value name 的 ordinal UTF-16 code unit 顺序排列,每项 exact keys 为 {name,kind,data_bytes,data_sha256}。允许 kind 及规范 bytes:

  • StringExpandString:.NET GetValue(..., DoNotExpandEnvironmentNames) 的字符串编码为 UTF-16LE 加一个终止 NUL;
  • MultiString:每项 UTF-16LE+NUL,末尾再加一个 NUL;
  • DWord:4-byte little endian;
  • QWord:8-byte little endian;
  • Binary:原 bytes;
  • Unknown/None 或无法无损规范化的值:E_POLICY_PREIMAGE,不写入。

canonical stream 为:

key_exists ASCII + LF
对每个 value:name UTF-8 + NUL + kind ASCII + NUL + data_bytes decimal ASCII + NUL + lowercase data_sha256 ASCII + LF

最终 SHA-256 用大写十六进制。approval/receipt 不保存其他 value 的 raw data,只保存 name/kind/length/hash;错误输出不得回显 name 之外的数据。

7.2 install approval 修订

V003 第7.2节的“其他 value names 排序哈希”废止。install approval 顶层 exact keys 固定为:

schema
scope
status
task_id
approved_by_role
release_approval
source_approval
policy
policy_preimage
native_host
receipt_paths
approved_at

固定 schema=1scope=install-exact-managed-extension-policystatus=APPROVEDapproved_by_role=project.adminpolicy 精确冻结 key、空闲十进制 target name、kind=String、exact extension ID+official update URL data 的 length/hash;policy_preimage 使用上节完整结构且 target absent;receipt_paths 冻结全部 existing parent 与 absent target paths;native_host 精确绑定已安装 build-005 三文件与 allowed origin。

7.3 race 与并存状态

  • acquire mutex 后、pending 前、pending 后且 policy write/delete 立即前,均复算完整 preimage。
  • 两个本工具进程只能一个持 mutex;后到者在首个释放后看到 pending/final/target,安全停止或进入恢复,不得覆盖。
  • file-registry seam 在最后检查前注入 target 或其他 value 漂移时,必须在写前停止。
  • 写后只接受“preimage + 唯一 exact target”;delete 后只接受 exact preimage。target 为非 exact data 时恢复不得删除,其他 value 漂移时不得覆盖任何值。
  • HealthCheck 同时验证 approval preimage、当前 postimage、pending/final bindings;不能只看 target。

测试至少覆盖 key absent/existing、零/多个其他 values、所有允许 registry kinds、排序、空字符串/MultiString、data hash/length 漂移、同名 target race、两个进程并发、其他 value 在各持久化点改变、rollback 后完整 preimage。所有非目标 values 的规范摘要必须逐项不变。

8. 修订后的文件与验收边界

V003 第4节文件集合保持不变;icon 与 overlay bytes 存入 managed-load-contract.json,不新增原扩展资产文件。实现后 builder ZIP 为9项,source approval 是实现审核后的 reviewer-owned 树外文件,不属于产品源码或 ZIP。

V003 第11节按以下修订:

  • exact-nine upload ZIP、四 PNG parser、overlay-only manifest diff 和 deterministic bytes;旧 five-entry 正例必须失败。
  • source approval 的 production exact schema 与 test-only fixture 隔离。
  • synthetic secret sentinel 端到端不落盘/不输出;合法 cookies API/字段名不误杀。
  • PowerShell terminating/PipelineStopped/kill 三类实际语义。
  • durable install/rollback pending、final commit point、每点 kill/reopen 恢复矩阵。
  • canonical registry preimage、两个进程 mutex、target/other-value race、所有 registry kinds。
  • 原扩展17文件、build-005、installed Host、bridge/runtime hashes 不变;真实 HKCU/Chrome/network/media=0。

性能目标继续是每次纯离线 builder/installer <5s,真实子进程 kill 矩阵和 project regression 不计入单次 CLI 目标。

9. 审核与后续门禁

V003+V004 是唯一组合实施合同。V004 先沿原 reviewer 链做 F1—F6 聚焦设计复审;PASS 前不得创建 managed-load 代码、测试、图标实物或候选 ZIP。

设计 PASS 只授权离线实现与测试。实现审核 PASS 后,reviewer 才能创建第3节 source approval。后续仍依次需要:受权 Web Store upload/publish、exact release evidence/reviewer release approval、project.admin install approval、受控 policy install、正常 Chrome 状态核验和 runtime 单独调度。任何门失败都不得回退非标准加载方式。