处理远程托管代码违规行为

远程托管代码 (RHC) 是指 Chrome 应用商店由从扩展程序自身文件以外的位置加载的浏览器执行的任何内容。例如 JavaScript 和 WASM。它包含数据以及 JSON 或 CSS 等内容。

为什么不再允许使用 RHC?

使用 Manifest V3 扩展程序,现在需要捆绑它们在扩展程序本身中使用的所有代码。过去,您可以从网络上的任何网址动态注入脚本代码。

我被告知我的扩展程序具有 RHC。这是怎么回事?

如果您的扩展程序在审核过程中因 Blue Argon 错误而被拒绝,我们的审核人员会认为您的扩展程序使用的是远程托管代码。这通常是由于扩展程序尝试添加带有远程资源的脚本标记(即从开放网络,而不是扩展程序中包含的文件)或获取资源以直接执行的结果。

如何识别 RHC

当您知道要探寻的环境后,发现 RHC 并不是特别困难。首先,检查您的项目中是否存在字符串“http://”或“https://”。如果您有 RHC 违规情况,则可以通过查找相应信息找到它们。如果您拥有完整的构建系统,或使用来自 npm 或其他第三方来源的依赖项,请确保您搜索的是经过编译的代码版本,因为存储区正在评估的内容。如果您仍无法找到问题,下一步就是联系一站式支持团队。他们将能够概述具体违规行为,以及尽快发布该扩展程序需要执行哪些操作。

如果库请求代码,该怎么办?

无论代码来自何处,RHC 都不得存在。这包括您没有编写,但恰好在项目中用作依赖项的代码。当包含远程代码以在 Firebase Auth 中使用时,使用 Firebase某些开发者会遇到此问题。尽管这是第一方(即 Google 自有)库,RHC 也不例外。您需要将代码配置为移除 RHC,或者将项目更新为不包含起始代码。如果您遇到加载 RHC 的不是您的代码,而是您使用的库,那么最好的做法是与库的作者联系。请告知对方发生了这种情况,并要求他们寻求解决方法或代码更新来将其移除。

如果等不及库更新,该怎么办?

有些库会在收到通知后立即发布更新,但其他库可能会弃用或需要一些时间才能解决问题。根据具体违规行为的情况,您可能不需要等待他们解除屏蔽状态并成功完成审核。您可以通过多种方式快速恢复并运行。

审核代码

确定需要引发请求的代码吗?如果只是可以删除代码,或者导致问题的库可以被移除,则删除该代码,工作就完成了。

或者,是否有其他库提供相同的功能?请尝试在 npmjs.com、GitHub 或其他网站上查看满足相同用例的其他选项。

摇树

如果实际并未使用导致 RHC 违规的代码,那么该工具可能会自动删除这些代码。WebpackRollupVite(仅列举几例)等现代构建工具均具有一项名为摇树优化的功能。在构建系统中启用摇树优化功能后,应移除所有未使用的代码路径。这意味着您不仅拥有更合规的代码版本,而且还能实现更精简、更快速的代码!请务必注意,并非所有库都支持摇树优化,但许多库都能够执行摇树优化。某些工具(例如 Rollup 和 Vite)默认启用摇树优化。需要配置 webpack 才能启用。如果您未在扩展程序中使用构建系统,但使用了代码库,则强烈建议您考虑在工作流中添加构建工具。构建工具可帮助您编写更安全、更可靠且更易于维护的项目。

如何实现摇树优化的细节取决于您的具体项目。但举一个简单的例子,使用 Rollup 时,只需编译项目代码即可添加摇树优化功能。例如,如果您有一个仅登录 Firebase Auth 的文件,名为 main.js:

import { GoogleAuthProvider, initializeAuth } from "firebase/auth";

chrome.identity.getAuthToken({ 'interactive': true }, async (token) => {
  const credential = GoogleAuthProvider.credential(null, token);
  try {
    const app = initializeApp({ ... });
    const auth = initializeAuth(app, { popupRedirectResolver: undefined, persistence: indexDBLocalPersistence });
    const { user } = await auth.signInWithCredential(credential)
    console.log(user)
  } catch (e) {
    console.error(error);
  }
});

然后,您只需告诉 Rollup 输入文件、加载节点文件 @rollup/plugin-node-resolve 所需的插件及其生成的输出文件的名称。

npx rollup --input main.js --plugin '@rollup/plugin-node-resolve' --file compiled.js

在终端窗口中运行该命令时,您将收到生成的 main.js 文件版本,它全部编译到名为 compiled.js 的单个文件中。

汇总操作可能很简单,但也非常可配置。您可以添加各种复杂的逻辑和配置,只需查看相关文档即可。添加此类构建工具会生成更小且更高效的代码,在本例中,这解决了我们的远程托管代码问题。

自动编辑文件

远程托管代码进入代码库的一种越来越常见,就是作为所包含库的子依赖项。如果库 X 想要从 CDN 中 importY,您仍然需要对其进行更新,使其从本地来源加载。借助现代构建系统,您可以轻松创建用于提取远程引用的插件,并将其直接内嵌到代码中。

这意味着指定的代码如下所示:

import moment from "https://unpkg.com/moment@2.29.4/moment.js"
console.log(moment())

您可以创建一个小型汇总插件。

import { existsSync } from 'fs';
import fetch from 'node-fetch';

export default {
  plugins: [{
    load: async function transform(id, options, outputOptions) {
      // this code runs over all of out javascript, so we check every import
      // to see if it resolves as a local file, if that fails, we grab it from
      // the network using fetch, and return the contents of that file directly inline
      if (!existsSync(id)) {
        const response = await fetch(id);
        const code = await response.text();

        return code
      }
      return null
    }
  }]
};

使用新插件运行构建后,系统会发现每个远程 import 网址,无论该网址是我们的代码、子依赖项、子依赖项还是其他位置。

npx rollup --input main.js --config ./rollup.config.mjs --file compiled.js

手动修改文件

最简单的方法是删除导致 RHC 的代码。在所选的文本编辑器中打开该文件,并删除违规行。通常不建议这样做,因为它很脆弱并且可能会被忘记。如果名为“library.min.js”的文件实际上并非 library.min.js,则会更难维护项目。一种维护性更强的选择是使用 patch-package 之类的工具,而不是修改原始文件。这是一个超级强大的选项,可让您将修改内容保存到文件,而不是文件本身。它是基于补丁文件构建的,类似于为 GitSubversion 等版本控制系统提供支持的功能。您只需手动修改违规代码,保存 diff 文件,然后使用您要应用的更改配置补丁软件包。您可以阅读有关项目的自述文件的完整教程。如果您正在修补某个项目,我们非常鼓励您与该项目联系,请求在上游进行更改。虽然补丁软件包可以大大简化补丁的管理,但没有需要修补的内容会更好。

如果代码未使用,该怎么办

随着代码库不断发展壮大,依赖项(或某个依赖项的依赖项,或...的依赖项)可以保留不再使用的代码路径。如果其中某个部分包含用于加载或执行 RHC 的代码,则必须将其移除。无论设备已废弃还是未使用,都无关紧要。如果未在使用,则应将其移除,方法是通过摇树优化或修补库来将其移除。

是否有任何临时解决方案?

一般来说,不可以。不允许使用 RHC。但少数情况下,允许使用这种方式。这些情况几乎都是其他选项都做不到的。

用户脚本 API

用户脚本是通常由用户提供的小代码段,适用于 TamperMonkeyViolentmonkey 等用户脚本管理器。这些管理器无法捆绑用户编写的代码,因此 User Script API 提供了一种执行用户所提供代码的方法。这不能替代 chrome.scripting.executeScript 或其他代码执行环境。用户必须启用开发者模式才能执行任何操作。如果 Chrome 应用商店审核团队认为相关内容的使用方式不符合预期(即用户提供的代码),则可能会遭到拒绝或将商品详情从商店中下架。

chrome.debugger

chrome.debugger API 让扩展程序能够与 Chrome 开发者工具协议互动。Chrome 开发者工具与许多其他工具使用的协议相同。有了它,扩展程序就可以请求和执行远程代码。就像用户脚本一样,它不能替代 chrome.scripting,并且能够提供更加出色的用户体验。 使用该 API 时,用户会在窗口顶部看到一个警告栏。如果横幅关闭或关闭,调试会话将终止。

Chrome 中地址栏的屏幕截图,其中显示“Debugger Extension started debugging this browser”消息
Chrome 中地址栏的屏幕截图,其中显示“Debugger Extension started debugging this browser”

沙盒化 iframe

如果您需要将字符串作为代码进行求值,并且处于 DOM 环境(例如内容脚本,而不是扩展程序 Service Worker),那么另一种方案是使用沙盒化 iframe。出于安全方面的考虑,扩展程序默认不支持 eval() 之类的功能。恶意代码可能会给用户安全带来风险。但是,如果代码仅在已知的安全环境(例如已与网络的其余部分沙盒化的 iframe)中执行,则可大大降低此类风险。在这种情况下,您可以取消阻止使用 eval 的内容安全政策,从而运行任何有效的 JavaScript 代码。

如果其他用例未涵盖在内,请随时通过 chromium-extensions 邮寄名单获取反馈,或提交新工单以向一站式支持团队请求指导

如果您对判定有异议,应该怎么做

政策的执行可能会有细微差别,审核过程涉及手动输入,这意味着 Chrome 应用商店团队有时可能会同意更改审核决定。如果您认为审核结果有误,可以使用一站式支持对遭拒提出申诉