DEV-PROJECT-INFO-BILI-AUTHENTICATED-SESSION-DOWNLOAD-20260805-001REQ-BILI-DYNAMIC-COLLECTOR-20260804-001青枫浦上Q / BV1HA3o6oEJJCODE-DESIGN-PROJECT-INFO-BILI-AUTHENTICATED-SESSION-EXTENSION-INGRESS-V001.md=22418/665DDDFE4247DEFEE69B6DD1E0CBBD128EDD75B8A32BA609C90C718AC7C97C71DEV-AUDIT-PROJECT-INFO-BILI-AUTHENTICATED-SESSION-EXTENSION-INGRESS-V001-DESIGN-20260805-001 / HOLD/4F1—F4。V001 已通过的 exact BVID、二次用户点击、无通用下载、无外部消息/loopback/token 文件、内存 Cookie、页面/DRM/multi-P/live/preview 门禁、冻结 accept-browser-file 和 offline-only 边界全部保留。项目扩展身份不再由安装器接收任意合法格式 ID。V002 固定以下值:
com.project_info.bili_auth_ingress2project-info-bili-auth-ingress/1.0.0+20260805.v002project-info-bili-auth-native-host/1.0.0+20260805.v002E83C2B2AF3CF011543FBA13FBC524D1122EEA68548F9F27B9F7A82B5D594666Coidmclckpdmpabbfedplkbdplmfcenbbchrome-extension://oidmclckpdmpabbfedplkbdplmfcenbb/manifest 固定 key:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt2dT1HGYaI0DXM7zZwOTNBWXTKlMBJMpyDVjRUc+v6bUotmLyoraC+ay2scy9UQluSZVYq0tS8qvQNNvuZOlc5w2bOExm4TH2IIKvaVO8nVthHBnNz2kXdiM8ItN0vPZEmS+8gpTCI1+6wPTuUglMoXpqYBYhii8fJ5RkENRF3PRJBBigGt8soqdBFRY1QZUmpQv9dYw4dRq4L2C4QtBgClUg4bQpuCppiVZ9LHbePi9IAjc9r9R93KLzpaBuXdJpfVRE5w/6YHnxP8ovXxBdl7XktmrdH3xj7mWT7Q7ZBxkDNwn2RkruD45XgDD3yuNxOYSkLFMkseN+Ua69gSS4wIDAQAB
该 public key 由一次内存 RSA 生成,仅保留 public SPKI;private material 未写文件、未记录且已释放。Chrome ID 按 public DER SHA-256 前 128 bit 的 nibble a..p 映射复算,必须得到上述 expected ID。
安装器只允许操作者提供 Chrome UI 观察到的 ObservedExtensionId,并执行比较,不用它生成身份:
key,复算 DER hash 与 extension ID;两者必须等于冻结值。ObservedExtensionId 必须逐字等于 pinned ID;不接受其他 32 位 ID、通配符或第二 origin。allowed_origins 必须是只含 exact origin 的单元素数组。Native Host 启动时把 Chrome 传入的首个 origin argv 与 exact origin 常量逐字比较;只允许额外的 Chrome --parent-window=<decimal> 参数,其他参数失败。origin 失败时在读取 native stdin、创建 worker、读取秘密或触发文件/网络前退出。扩展和 host 先交换 build identity;任一方不一致不得发送 Cookie。
131072 bytes;host 到 Chrome 的帧上限=16384 bytes。schema 必须为 integer 2;target 必须为 BV1HA3o6oEJJ;canonical_url 必须为 https://www.bilibili.com/video/BV1HA3o6oEJJ。start 的 cookies[].value 外,任何协议响应、状态或错误均不得含秘密或第三方文本。扩展连接后必须先发送:
{
"schema": 2,
"type": "hello",
"extension_build": "project-info-bili-auth-ingress/1.0.0+20260805.v002",
"target": "BV1HA3o6oEJJ"
}
host 只返回固定 host_build、phase 和 target。随后只允许:
{"schema":2,"type":"status","target":"BV1HA3o6oEJJ"}
{"schema":2,"type":"cancel","target":"BV1HA3o6oEJJ","task_nonce":"<32 lowercase hex>"}
task_nonce 由 background 在页面校验前用 CSPRNG 生成 16 bytes,仅用于绑定本次用户点击和取消,不是认证秘密;长度和字符集固定。过期、非当前 nonce 或任务已终态的 cancel 不产生外部动作。
page_proof exact keys、类型与范围:
| 字段 | 类型与范围 | 规则 |
|---|---|---|
target |
string | exact BVID |
canonical_url |
string | exact canonical URL |
task_nonce |
string | 32 lowercase hex,与 start/cancel 一致 |
observed_at_unix_ms |
integer | 0 < value < 2^53;host 接收时不早于 60 s、不晚于 host 时钟 5 s |
observed_duration_ms |
integer | 与 3133950 差值不超过 3134 ms |
video_width |
integer | 1..7680 |
video_height |
integer | 1..4320 |
ready_state |
integer | 1..4 |
eme_present |
boolean | 必须 false |
background 只投影上述原始标量,不传 DOM、文本、HTML、媒体对象、URL 列表或页面异常。页面 hostname/path 校验、可见 52:14/充电中 提示及 V001 门禁不变。
start exact keys:
{
"schema": 2,
"type": "start",
"extension_build": "project-info-bili-auth-ingress/1.0.0+20260805.v002",
"target": "BV1HA3o6oEJJ",
"canonical_url": "https://www.bilibili.com/video/BV1HA3o6oEJJ",
"cookie_store_id": "0",
"page_proof": {},
"cookies": []
}
cookie_store_id 为 ASCII [0-9]{1,8}。background 调用 chrome.cookies.getAllCookieStores(),要求 active tab ID 恰好属于一个 store;使用该 store ID 读取/投影 Cookie,所有 record 必须同值。cookies 数量=1..128;整个 start frame 不超过 131072 bytes。READY_PLUGIN_DISABLED 前不把 start 的 secret 部分写入 worker。每个 record exact keys:
{
"name": "synthetic-name",
"value": "synthetic-value",
"domain": ".bilibili.com",
"host_only": false,
"path": "/",
"secure": true,
"http_only": true,
"same_site": "unspecified",
"session": true,
"expiration_unix": null,
"store_id": "0",
"partition_key": null
}
字段规则:
name=1..256 UTF-8 bytes,value=1..4096 UTF-8 bytes;均禁止 NUL/TAB/CR/LF/control。禁止空值 record。domain 只允许:host_only=true 时 exact www.bilibili.com;host_only=false 时 exact .bilibili.com。大小写、尾点、IDN、其他子域和其他站点均拒绝。path=1..1024 UTF-8 bytes,必须以 / 开始、无控制字符,且必须是 canonical target path /video/BV1HA3o6oEJJ 的 RFC cookie-path prefix;不做文件路径解析。secure/http_only/session 必须是 boolean。same_site 仅允许 no_restriction|lax|strict|unspecified。store_id 必须逐字等于 top-level cookie_store_id。partition_key 必须显式为 null。Chrome 返回任何 partitioned cookie 时 fail-closed;不把分区 Cookie 降级为非分区 Cookie。session=true 时 expiration_unix 必须为 null;转换为 Netscape expiry 0。session=false 时 expiration_unix 必须是 1..2^53-1 integer,且大于 page proof 秒级时间;转换为相同整数。过期、float、bool、二者不一致均拒绝。Netscape text 只在 worker 内的 io.StringIO 形成:header 固定;domain column 使用 canonical domain,http_only=true 时只在内存中加 #HttpOnly_ 前缀;include-subdomains=FALSE iff host_only,否则 TRUE;path/secure/expiry/name/value 按上述已验证值写 TAB 分隔行。转换后禁止任何文件名、Cookie 临时文件或 browser profile 入口。
V001 的单进程 host 改为最小 broker/worker 两进程:
--worker 模式。argv 只含非秘密 mode 与继承 handle 数字;start JSON/Cookie 经专用匿名 stdin pipe 传入,不进入 argv/env。NUL。只有 broker 的 protocol writer 能写复制 handle。因此 yt-dlp CookieJar 的 direct write_string、Python warning、真实包 stdout/stderr、FFmpeg stdout/stderr 和 traceback 都只能进入不持久化 NUL sink,不能污染 Chrome 协议 stdout,也不形成日志文件。
worker 的启动顺序固定:
NUL。YTDLP_NO_PLUGINS=1,该环境不含任何 Cookie/token/URL。import yt_dlp。yt_dlp.globals.plugin_dirs.value=[];调用冻结插件初始化后断言:plugin_dirs.value==[]、plugins.directories()==[]、plugin_ies.value=={}、plugin_pps.value=={}、plugin_ies_overrides.value 为空。E_PLUGIN_BOUNDARY 并退出;broker 不发送 start secret。READY_PLUGIN_DISABLED,broker 才把 start payload 写入 worker stdin。这同时阻断默认 plugin_dirs=['default']、旧兼容插件目录和用户插件在秘密进入进程后执行。实现固定 yt-dlp 2026.07.04 包 hash 清单;版本或相关模块 hash 漂移须重新实现审核。
实现审核前用冻结真实包而非仅 fake logger 执行:
YoutubeDL,断言 marker 不出现且 plugin maps/directories 为空。YoutubeDLCookieJar 从 io.StringIO 分别加载合法和畸形 synthetic Cookie,触发正常、解析 warning、close/save 路径;sentinel 不得进入 broker protocol、父 stdout/stderr、临时树、配置、异常或证据。ffmpeg helper,把 sentinel 写 stdout/stderr/异常后退出;broker protocol 只可收到固定错误码,磁盘日志为 0。同一个冻结 YoutubeDL 实例只执行一次:
processed_info = ydl.extract_info(CANONICAL_URL, download=False, process=True)
随后:
processed_info 执行 exact id、single video、duration、live、multi-P、DRM、AV、availability 和 format 基线门禁。_get_formats、build_format_selector("bestvideo+bestaudio/best") 和 _select_formats 取得唯一 selected format;数量不为 1 即失败。download_info = ydl._copy_infodict(processed_info); download_info.update(selected_format)。download_info 及其 requested_formats 逐叶验证下节合同。ydl.extract_info 替换为“调用即 E_SECOND_EXTRACT” guard,再把同一个 download_info object 直接交给 ydl.process_info(download_info)。禁止调用 ydl.download(url)、第二次 extract_info、按 URL 的 process_ie_result 或重新取得 metadata/formats。测试记录 extractor invocation count 必须恒等于 1,并证明被验证 object identity 与交给 process_info 的 object identity 相同。
逐个实际叶 format 校验:
requested_formats 存在,必须恰好 2 个:一个 vcodec!=none/acodec=none,一个 vcodec=none/acodec!=none;顶层必须同时有 AV 合并语义。vcodec!=none 且 acodec!=none,进入 4.4 单文件 remux。has_drm 必须 false/absent;URL scheme 必须 https;protocol 只允许 https 或 http_dash_segments。get_suitable_downloader(leaf, ydl.params) 计算实际 class;只允许 exact HttpFD 或 DashSegmentsFD。FFmpegFD、HlsFD、任何 ExternalFD、m3u8/m3u8_native/rtmp/rtsp/mms/ism、未知协议、多个 manifest、缺失 URL 或额外 subtitle/data format 全部在首个媒体字节前失败。fragment_retries、HTTP headers 和签名 fragment URL只由 worker 内置 downloader 消费;不导出、不转成任何子进程 argv。worker 在 yt-dlp import 后、任何子进程前注册 Python audit hook,拦截所有 subprocess.Popen:
://、-headers、-cookies、authorization、cookie:、referer:、user-agent:,禁止含本任务任一 Cookie value/name、signed URL/header synthetic/real value。-i 值和输出必须是固定 run directory 下通过重解析点检查的本地普通文件;禁止 pipe/network/protocol input。NUL;child 必须属于第 5 节 Job Object。audit hook 在 CreateProcess 前抛出安全异常,因此禁止值不得短暂出现在 Windows process command line。真实 dispatcher 测试要求 https -> HttpFD、http_dash_segments -> DashSegmentsFD PASS,m3u8 -> FFmpegFD 被产品门禁拒绝且实际 FFmpeg spawn=0。
merge_output_format="mkv",yt-dlp 只在两份本地文件完成后调用 FFmpeg stream-copy merger;argv 必须通过 4.3。best fallback:下载器只产生本地完整 AV 文件;host 不把原容器视为最终结果,使用 pinned FFmpeg 固定本地命令 -nostdin -i <local> -map 0:v:0 -map 0:a:0 -c copy -map_metadata -1 -f matroska <exclusive-stage>.mkv。remux、AV 或 MKV 验证失败即清理并 fail-closed。.mkv;原单文件或双流中间件在 MKV 验证成功后删除。任何其他媒体候选、未知 sidecar 或 partial 残留失败。离线合成门禁使用真实 FFmpeg 生成短 AV fixture,分别覆盖双叶合并和单叶 remux;验证 MKV、音视频、无转码语义、唯一候选、argv 全为本地路径。无需网络或业务媒体。
status/cancel。EOF、坏帧、origin/session disconnect 设置同一个 cancel event。yt-dlp/host 值固定为:
| 项目 | 上限 |
|---|---|
| socket/read timeout | 20 s |
| extractor retries | 1 |
| HTTP retries | 2 |
| fragment retries | 2 |
| file access retries | 1 |
| retry sleep | 每次 1 s,最大 3 s |
| metadata phase | 120 s |
| download+merge 总墙钟 | 7200 s |
| frozen bridge 子进程 | 900 s |
| graceful cancel | 3 s |
| TerminateJobObject 后 wait | 5 s |
| reader/control join | 各 5 s |
达到任一阶段或总墙钟,coordinator 设置 cancel;3 秒后 worker 仍存活则调用 TerminateJobObject,5 秒后仍不能确认 PID 全灭则返回 E_PROCESS_OWNERSHIP 并退出,绝不继续后半程或发布。没有无限重试、无限 join 或断点续传。
每个 task 在接收 secret 前创建独立 Windows Job Object,设置 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE。broker 使用 Win32 CreateProcessW 的 CREATE_SUSPENDED|CREATE_NO_WINDOW 启动同一 host executable 的 worker 模式,继承句柄 allowlist 只含 worker input、sanitized control 和 cancel event:
AssignProcessToJobObject 加入 task job。ResumeThread;失败则 terminate suspended worker、关闭 handles,并在 secret 写入前停止。若当前 Windows/Chrome job 策略不允许该所有权链,任务在 Cookie 读取/worker secret/网络前以 E_JOB_OBJECT fail-closed,不回退到普通 Popen 或仅 PID 递归清理。
seek(0)/truncate(0)/close() Cookie stream,control pipe 只返回 cookie_stream_closed=true;broker 不记录内容。实现审核使用真实 Win32 process,不只 fake child:
KeyboardInterrupt、SystemExit、下载墙钟超时、broker TerminateProcess 模拟 host kill。OpenProcess/WaitForSingleObject 验证 worker/child/grandchild handle 全部 signaled、无 PID 存活;grace 与 kill/join 时间均不超冻结值。download_info object identity相同;第二解析 guard非真空。-i 在 CreateProcess 前拒绝。V002 复审前仅新增本设计并追加既有开发账本/私有 worklog。以下保持冻结:
dev/project-dev/bili_video_download_bridge.py=28500/749FC486B0F42315BD463F11771FE2A7C71CAB53DD9AC2E411CE82E1175DFF13dev/project-dev/test/test_bili_video_download_bridge.py=22553/80D8C94DF6922820AA4643984E91209C16046364C20A6A04F6ADA22C8DC36C8Bdev-doc/project-doc/B站完整视频下载桥接工具.md=6931/8103EA6F2077BF6BB30B31BCDFB3786B057306A747C18286E2622D19F8393687F:\video 和正式 ana-data。真实 Cookie/token/signed URL、Chrome、扩展安装、Native Host 注册、network、download、real media、F:\video、formal ana-data、implementation/test/config actions 全部保持 0。
请 dev.reviewer.project 只复审 F1—F4 是否闭环以及 V001 已通过边界是否回退,返回一次完整 PASS/0 或精确 HOLD。V002 PASS 只授权在冻结文件边界内创建最小离线实现、合成媒体测试和真实 sleeping-child 测试;不授权读取真实 Cookie、安装 Chrome/扩展/host、注册 HKCU、联网下载、读取隔离预览、写 F:\video/正式 ana-data 或启动转写。