Skip to content

✨ Add @site-access opt-in scripts to the popup#1597

Draft
cyfung1031 wants to merge 5 commits into
scriptscat:mainfrom
cyfung1031:codex/site-access-opt-in
Draft

✨ Add @site-access opt-in scripts to the popup#1597
cyfung1031 wants to merge 5 commits into
scriptscat:mainfrom
cyfung1031:codex/site-access-opt-in

Conversation

@cyfung1031

@cyfung1031 cyfung1031 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Checklist / 检查清单

  • Fixes feature request / 已实现功能请求
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

背景

脚本作者需要声明“默认不在所有站点运行,但允许用户明确选择站点”的脚本。

现有 @match@include@exclude 规则适合描述脚本的原始匹配范围,但不能表达用户主动选择的 opt-in 站点,也不能安全地把 opt-in 规则直接混入原始匹配规则。

因此,本次增加独立的 @site-access opt-in 规则:

// @site-access opt-in
// @site-access +*://github.com/*

其中:

  • opt-in 表示脚本需要额外的站点访问许可;
  • + 开头的规则表示作者声明的初始 / 默认站点;
  • 用户通过 Popup 或设置页面添加的规则保存为自定义 @site-access +<pattern> 元数据。

本次改动

  • 支持作者声明 @site-access opt-in 以及 @site-access +<pattern> 默认站点。
  • 保留作者的默认站点规则,并支持用户在设置页面中新增、编辑、删除和重置自定义站点规则。
  • 在“当前页面运行脚本”和“已启用并运行的后台脚本”之间增加 Opt-in Scripts 区域。
  • 当前页面没有可展示的 opt-in 脚本时隐藏该区域,不改变普通用户的现有 Popup 体验。
  • 支持从 Popup 将当前站点加入 opt-in 许可列表,并在运行时注册更新完成后重新加载当前标签页。
  • 仅当当前页面存在精确的 Popup 生成规则 +*://<host>/* 时显示移除许可操作。
  • 当访问权限来自更宽泛的用户规则或作者默认规则时,不显示会产生误导的精确移除操作。
  • 移除接口返回是否实际修改了规则;无变化时不更新注册信息,也不重新加载当前标签页。
  • 浏览器注册范围使用 site-access 规则进行收窄。
  • 普通脚本、@early-start@unwrap 脚本都在执行边界检查原始 URL 规则与 site-access 规则的交集。
  • 缓存恢复路径使用相同的访问检查,并更新编译资源命名空间以淘汰旧缓存。
  • 为消息队列增加可等待当前环境异步订阅者完成的发布路径,确保 Popup reload 不会早于 chrome.userScripts.update/register
  • 增加服务端、消息队列、运行时、Popup 和 UI 测试,并补充所有支持语言的界面文案。

实现考虑

1. 不修改原始 @match / @include / @exclude 语义

opt-in 站点许可不会覆盖脚本原始 URL 规则。

脚本是否执行必须同时满足:

  1. 原始 @match / @include / @exclude 规则允许当前 URL;
  2. @site-access 的作者默认规则或用户自定义规则允许当前 URL;
  3. 脚本处于启用状态,并且其他运行时条件允许执行。

这样可以避免把用户的 opt-in 设置误认为脚本作者扩大了脚本原始匹配范围。

2. 在浏览器注册和执行载荷两侧同时限制访问范围

仅在页面加载请求中检查 site-access 不足以保护以下路径:

  • @early-start 脚本可能在页面请求之前执行;
  • @unwrap 脚本可能直接执行注册载荷;
  • 普通脚本的编译函数可能被提前暴露到页面环境。

因此实现同时处理:

  • chrome.userScripts 注册范围;
  • 普通脚本的页面载荷;
  • @early-start 预注入载荷;
  • @unwrap 直接执行载荷;
  • 缓存恢复和编译资源路径。

被拒绝的页面不会执行脚本,也不会暴露可直接调用的完整脚本函数。

3. 用户规则使用 additive custom metablock

用户通过 Popup 加入当前站点时,实际保存的是:

@site-access +*://example.com/*

作者声明的 @site-access 内容不会被覆盖,用户规则可以单独编辑、删除或重置。

Popup 的“移除当前站点”操作只删除它自己生成的精确 host 规则。更宽泛的规则需要在设置页面中明确编辑,避免删除操作显示成功但脚本仍因其他规则继续运行。

4. Popup reload 必须等待注册完成

加入或移除站点会触发脚本注册信息更新。

消息队列原有的普通 publish 是异步通知,不等待订阅者完成,因此 Popup 如果立即 reload,可能使用旧的注册规则。现在 Popup RPC 会等待当前 Service Worker 中的异步 install handler 完成,确认注册更新结束后才 reload 当前标签页。

5. 保持 issue 范围清晰

本 PR 实现的是作者控制的 @site-access opt-in 设计。

原始 @match / @include 不匹配当前页面的脚本仍不会因为本功能自动出现在 Popup 中。面向所有未匹配脚本的发现、展示和双向管理属于更广泛的后续范围,本 PR 不改变现有脚本匹配边界。

已知限制

1. 不会自动发现原始规则完全不匹配的脚本

如果脚本的原始 @match / @include 规则完全不匹配当前页面,即使作者声明了 @site-access opt-in,该脚本也不会被本 PR 自动加入 Popup 的候选列表。

2. Popup 只处理精确 host 许可

Popup 的快捷移除操作只处理 +*://<host>/* 形式的用户规则。

以下规则不会通过 Popup 的快捷按钮删除:

+*://*.example.com/*
+*://example.com/tools/*

这些规则需要在脚本设置页面中编辑或删除。

3. 作者默认站点不能通过“移除用户许可”关闭

如果作者默认规则已经允许当前站点,用户删除自己的同站点规则不会阻止脚本运行。因此这种情况下 Popup 不显示误导性的移除许可操作。

建议审查重点

  • @site-access opt-in 是否始终与原始 URL 规则取交集;
  • 浏览器注册范围和普通、@early-start@unwrap 执行载荷是否都执行 site-access 检查;
  • 脚本没有允许站点时是否不会暴露可执行的页面全局函数;
  • Popup reload 是否等待 chrome.userScripts.update/register 完成;
  • 宽泛用户规则、作者默认规则和精确用户规则同时存在时,移除操作是否清晰;
  • RPC no-op 是否不会触发多余的注册更新和标签页 reload;
  • 所有 Popup 和设置页面文案是否已同步支持的语言。

关联

Related to #1590

验证

  • pnpm exec vitest run --no-coverage --reporter=dot --reporter.summary=false:303 个文件,3,285 个测试通过
  • pnpm typecheck:通过
  • Prettier 检查:通过
  • ESLint:通过
  • pnpm build:通过;仅保留现有 Rspack asset-size 和 Monaco 警告

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant