リモートホスト型コード違反に対処する

リモート ホスト型コード(RHC)とは、Chrome ウェブストアで、拡張機能の独自のファイル以外の場所から読み込まれ、ブラウザによって実行されるものを指す用語です。JavaScript や WASM などです。データや JSON、CSS などのものは含まれません。

RHC が許可されなくなったのはなぜですか?

Manifest V3 拡張機能では、使用するすべてのコードを拡張機能自体にバンドルする必要があります。以前は、ウェブ上の任意の URL からスクリプトタグを動的に挿入できました。

拡張機能に RHC があると言われました。どうしましたか?

審査中に Blue Argon エラーが発生して拡張機能が不承認になった場合、審査担当者は、拡張機能がリモートでホストされているコードを使用していると判断しています。これは通常、拡張機能がリモート リソース(拡張機能に含まれるファイルではなく、オープン ウェブから)を含むスクリプトタグを追加しようとした場合、またはリソースを取得して直接実行しようとした場合に発生します。

RHC を見つける方法

RHC は、何を探すべきかがわかれば、それほど見つけるのが難しいものではありません。まず、プロジェクトで「http://」または「https://」という文字列を探します。RHC 違反がある場合は、その検出結果を見つけることで、違反の場所を特定できる可能性があります。完全なビルドシステムがある場合や、npm などのサードパーティ ソースの依存関係を使用している場合は、ストアで評価されるのはコードのコンパイル済みバージョンであるため、そのバージョンを検索していることを確認してください。それでも問題が見つからない場合は、One Stop Support にお問い合わせください。具体的な違反内容と、拡張機能をできるだけ早く公開するために必要な対応について説明します。

ライブラリからコードをリクエストされた場合の対応

コードの出所に関係なく、RHC を使用することはできません。これには、作成したコードだけでなく、プロジェクトで依存関係として使用しているコードも含まれます。Firebase を使用している一部のデベロッパーは、Firebase Auth で使用するためにリモートコードを含めているときに、この問題が発生しました。これはファーストパーティ(Google 所有)のライブラリでしたが、RHC には例外は認められませんでした。RHC を削除するか、プロジェクトを更新してコードを最初から含めないようにコードを構成する必要があります。RHC を読み込んでいるのが自分のコードではなく、使用しているライブラリであるという問題が発生した場合は、ライブラリの作成者に連絡するのが最善の方法です。この問題が発生していることを伝え、回避策またはコードの更新を依頼して問題を解決します。

ライブラリの更新を待てない場合

ライブラリによっては、通知後すぐにアップデートがリリースされますが、ライブラリが放棄されたり、問題の解決に時間がかかったりすることもあります。違反の内容によっては、ブロックが解除されて審査が完了するまで待つ必要がない場合があります。迅速に復旧して運用を再開するためのオプションはいくつかあります。

コードを監査する

リクエストの原因となっているコードが必要であることを確認してください。削除するだけでよい場合や、原因となっているライブラリを削除できる場合は、そのコードを削除すれば完了です。

または、同じ機能を提供する別のライブラリはありますか?npmjs.com、GitHub などのサイトで、同じユースケースを満たす他のオプションを確認してみてください。

ツリー シェイキング

RHC 違反の原因となっているコードが実際には使用されていない場合は、ツールによって自動的に削除される可能性があります。webpack、Rollup、Vite などの最新のビルドツールには、ツリーシェイキングという機能があります。ビルドシステムでツリー シェイキングを有効にすると、未使用のコードパスが削除されます。これにより、コードの準拠バージョンだけでなく、より効率的で高速なバージョンも作成できます。すべてのライブラリがツリー シェイクできるわけではありませんが、多くのライブラリはツリー シェイクできます。Rollup や Vite などの一部のツールでは、ツリー シェイキングがデフォルトで有効になっています。webpack で有効にするには、構成が必要です。拡張機能の一部としてビルドシステムを使用していないが、コード ライブラリを使用している場合は、ワークフローにビルドツールを追加することを強くおすすめします。ビルドツールは、より安全で信頼性が高く、保守しやすいプロジェクトの作成に役立ちます。

ツリーシェイキングの実装方法は、プロジェクトによって異なります。Rollup の簡単な例を挙げると、プロジェクト コードをコンパイルするだけでツリーシェイキングを追加できます。たとえば、Firebase Auth にのみログインするファイル(main.js)があるとします。

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

browser.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 からライブラリ import Y を取得する場合、ローカル ソースから読み込むように更新する必要があります。最新のビルドシステムでは、リモート参照を抽出してコードに直接インライン化するプラグインを簡単に作成できます。

つまり、次のようなコードが与えられた場合、

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

小さな rollup プラグインを作成できます。

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 URL が検出されます。

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

ファイルを手動で編集する

最も簡単な方法は、RHC の原因となっているコードを削除することです。お好みのテキスト エディタで開き、違反している行を削除します。一般的に、この方法は脆く、忘れられる可能性があるため、あまり推奨されません。「library.min.js」というファイルが実際には library.min.js でない場合、プロジェクトのメンテナンスが難しくなります。生のファイルを編集する代わりに、patch-package などのツールを使用する方が、保守しやすい方法です。これは、ファイル自体ではなく、ファイルへの変更を保存できる非常に強力なオプションです。これは、パッチファイル上に構築されています。これは、Git や Subversion などのバージョン管理システムを支えるものと同じです。違反しているコードを手動で変更し、差分ファイルを保存して、適用する変更で patch-package を構成するだけです。チュートリアルの全文は、プロジェクトの README で確認できます。プロジェクトにパッチを適用する場合は、プロジェクトに連絡して、変更をアップストリームで行うようリクエストすることを強くおすすめします。patch-package を使用するとパッチの管理が大幅に容易になりますが、パッチを適用する必要がないのが一番です。

コードが使用されていない場合の対処方法

コードベースが大きくなると、依存関係(または依存関係の依存関係など)によって、使用されなくなったコードパスが保持されることがあります。これらのセクションのいずれかに RHC を読み込んで実行するコードが含まれている場合は、そのコードを削除する必要があります。使用済みかどうかは関係ありません。使用されていない場合は、ツリーシェイキングするか、ライブラリをパッチして削除する必要があります。

回避策はありますか?

通常、RHC は許可されていません。ただし、ごく一部のケースでは許可されています。これは、他のオプションではほぼ不可能な場合に限られます。

User Scripts API

ユーザー スクリプトは、通常はユーザーが提供する小さなコード スニペットで、TamperMonkey や Violentmonkey などのユーザー スクリプト マネージャーを対象としています。これらのマネージャーはユーザーが記述したコードをバンドルできないため、User Script API はユーザーが提供したコードを実行する方法を公開します。これは、browser.scripting.executeScript やその他のコード実行環境の代わりになるものではありません。ユーザーが何かを実行するには、デベロッパー モードを有効にする必要があります。Chrome ウェブストアの審査チームが、この機能が本来の目的以外の方法で使用されている(ユーザーが提供したコードなど)と判断した場合、拡張機能が拒否されたり、ストアから削除されたりする可能性があります。

browser.debugger

browser.debugger API を使用すると、拡張機能は Chrome Devtools Protocol を操作できます。これは、Chrome の Devtools や他の多くのツールで使用されているプロトコルと同じです。これにより、拡張機能はリモートコードをリクエストして実行できます。ユーザー スクリプトと同様に、browser.scripting の代わりにはならず、ユーザー エクスペリエンスが大幅に向上します。使用中は、ウィンドウの上部に警告バーが表示されます。バナーを閉じるか閉じると、デバッグ セッションが終了します。

「Debugger Extension started debugging this browser」というメッセージが表示された Chrome のアドレスバーのスクリーンショット
「Debugger Extension started debugging this browser」というメッセージが表示された Chrome のアドレスバーのスクリーンショット

サンドボックス化された iframe

文字列をコードとして評価する必要があり、DOM 環境(拡張機能の Service Worker ではなく、コンテンツ スクリプトなど)にいる場合は、サンドボックス化された iframe を使用することもできます。拡張機能は、安全対策として、デフォルトで eval() などの機能をサポートしていません。悪意のあるコードは、ユーザーの安全性とセキュリティを危険にさらす可能性があります。しかし、コードが既知の安全な環境(ウェブの他の部分からサンドボックス化された iframe など)でのみ実行される場合、これらのリスクは大幅に軽減されます。このコンテキストでは、eval の使用をブロックする Content Security Policy を解除して、有効な JavaScript コードを実行できます。

対象外のユースケースがある場合は、chromium-extensions メーリング リストを使用してチームに連絡し、フィードバックを得るか、One Stop Support に新しいチケットを開いてガイダンスをリクエストしてください。

判決に同意できない場合の対応

ポリシーの適用は複雑な場合があり、審査には手動入力が伴います。そのため、Chrome ウェブストア チームが審査結果の変更に同意することがあります。審査に誤りがあったと思われる場合は、One Stop Support を使用して不承認に対する再審査を請求できます。