Repository navigation
Conversation
2 of 3 tasks
chrome.userScripts 与 Firefox(134+)对 matches 和 includeGlobs 取并集:网址命中任一即注入。 getApiMatchesAndGlobs 原先按「matches 之后再用 includeGlobs 过滤」设计,遇到 @include glob 或 正则就把 matches 放宽成 *://*/* 再指望 includeGlobs 收回,结果所有带 @include 的脚本代码都挂到了 每个 http(s) 页面(执行仍由 service worker 的匹配把关,但源码对页面可见)。 - matches 只放脚本真正的 match pattern;只有 glob 时用 *://scriptcat.invalid/* 占位(API 要求 matches 非空) - glob 不以 * 结尾时补一条 #* 变体:浏览器拿带 hash 的完整网址匹配 glob,脚本猫匹配前会去掉 hash - 能抽出 scheme://网域 的正则转成小写的网域级 glob;抽不出的仍全站注册,并以 regexUnbounded 标记 - 修改 CompiledResourceNamespace,让已保存的旧注册信息失效重建
能抽出 scheme://网域 的正则已转成网域 glob 精确注册;抽不出的(如没有 scheme 的局部正则)只能全站注册, 脚本代码仍会挂到所有页面。这类脚本改为不预注册:service worker 在 pageLoad 匹配命中后,把挂载 window[flag] 的注入代码放进 TScriptInfo.code 下发,scripting 转交给 content 环境,content 沿用旧版 createElementNS 插入 <script> 的写法注入页面,执行环境照常通过 flag 接手。 content 运行在 USER_SCRIPT world,其 CSP 放行内联脚本,插入页面的 <script> 不受页面 CSP 与 Trusted Types 限制(github.com、youtube.com 实测);scripting 所在的 ISOLATED world 做不到,所以不能由它注入。 仍全站预注册的例外:early-start 需在页面脚本前同步挂载、unwrap 注入即执行,都等不了 pageLoad; Firefox 的 USER_SCRIPT world 插入的 <script> 受页面 CSP 限制。 新增 e2e/include-injection-scope.spec.ts:glob(含带 #hash 的网址)与收不窄的正则脚本在各自目标页执行 (正则目标页下发 script-src 'none'),且不在无关页面留下 window[flag]。该用例在 origin/main 上失败。
CodFrm
force-pushed
the
fix/include-injection-scope
branch
from
November 2, 2026 03:51
c2ef01a to
91f93aa
Compare
Collaborator
|
SC机制不一样 SC用 API 先在浏览器层面注册 还是会在 DevTools 看到的 |
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.
Checklist / 检查清单
背景
#1803 中,在不匹配的页面(如起点)的 DevTools 里能看到只该在抖音/B站运行的脚本源码,
window['#-<uuid>']上挂着完整代码。脚本没有执行(执行由 service worker 的匹配把关),但任何网站都能枚举出用户装了哪些脚本并读取源码,每个页面也要多解析这些代码。根因:
chrome.userScripts(Firefox 134+ 同样)对matches与includeGlobs取并集,网址命中任一即注入。getApiMatchesAndGlobs原先按「先 matches 再用 includeGlobs 过滤」设计,遇到@includeglob 或正则就把matches放宽成*://*/*,再指望includeGlobs收回范围,结果所有带@include的脚本都被注入到了每个 http(s) 页面。在 Chrome 148 上实测:
matches: ["https://nomatch.invalid/*"]加includeGlobs: ["*example*"]会在 example.com 注入;matches: ["*://*/*"]加includeGlobs: ["*douyin*"]同样会在 example.com 注入;excludeMatches/excludeGlobs正常生效;matches不能为空。本次改动
1. 按并集语义注册(
01d121d7)matches只放脚本真正的 match pattern。只有 glob 时用*://scriptcat.invalid/*占位(.invalid是保留域名,API 要求matches非空),注入范围完全由includeGlobs决定。scheme://网域的正则@include转成小写的网域级 glob。正则默认忽略大小写,glob 区分大小写。*的 glob 补一条<glob>#*:实测 Chrome 拿带#hash的完整网址匹配 glob,而 SW 匹配前会先去掉 hash。CompiledResourceNamespace,旧的注册信息在升级后失效并重建。addMatchesToGlobs、extractMatchPatternsFromGlobs。2. 正则收不窄的脚本改由 pageLoad 下发代码(
c2ef01a9)/foo\.com/),getUserScriptRegister标记deliverOnPageLoad,这类脚本不预注册。window[flag]的注入代码放进TScriptInfo.code。scripting把它转交给 content,content 沿用旧版createElementNS插入<script>的写法注入页面,inject 照常通过 flag 接手。scripting:content 运行在 USER_SCRIPT world,其configureWorldCSP 放行内联脚本,插入页面的<script>不受页面 CSP 和 Trusted Types 限制(在 github.com、youtube.com 实测)。scripting所在的 ISOLATED world 插入的脚本会被拦。@early-start(需在页面脚本之前同步挂载)、@unwrap(注入即执行),以及 Firefox(其 USER_SCRIPT world 插入的<script>受页面 CSP 限制)。实现考虑
chrome.userScripts.execute:它需要 Chrome 135+,而 content 注入在 Chrome 120+ 都能用,也不需要剥页面 CSP。已知限制
@early-start/@unwrap脚本,以及 Firefox 上的这类脚本,代码仍会挂到所有页面(维持原状)。?结尾的网址(如/page?)不会注入:SW 视其为匹配,Chrome 不视为匹配,属罕见情况。src/app/service/agent/service_worker/dom.test.ts改写chrome.permissions后未还原,在isolate: false下导致后续文件的 setup 失败;e2e/drive.mjs的sw命令在页面注册了自己的 Service Worker 时会拿错 worker。建议审查重点
src/pkg/utils/url_matcher.ts的getApiMatchesAndGlobs:确认注册范围始终不比 SW 匹配窄,尤其是网域 glob 转换和#*变体。src/app/service/service_worker/runtime.ts:deliverOnPageLoad的脚本在批量注册、单脚本变更(需撤销旧注册)和 pageLoad 三条路径上的处理是否一致。url_matcher.test.ts大部分期望值按新契约重写(旧期望写死了 AND 语义下的*://*/*),可对照新旧 diff 确认没有遗漏原有分支。关联
Close #1803
验证
以下结果绑定 base
e88d0eb6(含 #1815 的 Playwright 1.64.1)、head91f93aa9。本 PR 先基于eecd34a2开出,#1815 合并后 rebase,无冲突。91f93aa9):Lint、单元测试两个分片、Run tests、Runtime smoke、E2E 四个分片全部通过。rebase 前 Runtime smoke 的失败,是因为 ubuntu 26.04 runner 不支持 Playwright 1.60,由 ⬆️ 升级 @playwright/test 到 1.64.1,修复 ubuntu 26.04 runner 上的 CI 失败 #1815 修复。@include的脚本在 example.com 上挂着window['#-<uuid>'];只有纯@match的对照脚本没有。e2e/include-injection-scope.spec.ts:在origin/main(eecd34a2)的构建上 1 failed / 1 passed,无关页面泄漏了 2 个#-uuid;在本分支上 2 passed。pnpm exec playwright test e2e/runtime-bootstrap.spec.ts e2e/popup-matching-regressions.spec.ts e2e/gm-api.spec.ts e2e/include-injection-scope.spec.ts:18 passed,其中 gm-api 页内自测 138 项通过、0 失败(含严格 CSP 页面)。pnpm exec vitest run --no-coverage src/pkg/utils src/app/service/service_worker src/app/repo src/app/service/content:79 个文件、1805 条全部通过。pnpm run typecheck通过。pnpm test不可靠,origin/main原样运行也有 79–140 个文件失败,且每次数量不同。原因是高负载下超时,以及dom.test.ts的 mock 泄漏。全量结果以上面 CI 的两个分片为准。git grep核对。git diff e88d0eb6...91f93aa9共 12 个文件,均属于两项改动、对应测试和执行路径文档。