0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プロキシをON/OFFするChrome拡張を作ってみた

Last updated at Posted at 2024-09-08

プロキシを設定できるChrome拡張はすでに高機能なものがいくつかあるが、Chromeウェブストアでは「ベスト プラクティスに沿わないため、まもなくサポートされなくなる可能性があります。」などと警告が表示されているものもある。

使用できなくなると困るので念のため自前で作成することにした。

Chrome拡張のManifest V2は廃止が決定しており、警告が表示されているのはManifest V2を使用したままのためと思われる。
なお、この記事のコードはManifest V3の仕様で作成している。

Google Developers Japan: Manifest V2 の段階的廃止を開始 - https://developers-jp.googleblog.com/2024/06/manifest-v2-phase-out-begins.html

Chrome拡張でプロキシを設定するには

そもそもなぜChrome拡張でプロキシを設定できるのか謎だが、chrome.proxyのリファレンスを見るとたしかに設定できると書いてある。

設定を変更するにはchrome.proxy.settings.setメソッドを呼び出す。

background.js
async function setProxySettingsFixedServer() {
    // 省略

    let config = {
        mode: "fixed_servers",
        rules: {
            singleProxy: {
                host: "proxy.example.com",
                port: 8080
            },
        }
    };

    await chrome.proxy.settings.set({ value: config });
}

valueにはmoderulesを指定する必要がある。
プロキシサーバーのホスト名を自前で設定するならmodeにはfixed_serversを指定する。
rulesにはプロキシサーバーのホスト名などを指定する。
単に設定するならsingleProxyhostを設定する。
必要に応じてschemeportも指定する。

プロキシサーバーを使用したくない場合はmodedirectを指定することもできる。

プロキシサーバーがhttpとhttpsで分かれている場合はそれぞれ指定することもできるらしい。
(今時サーバーをわけるメリットはあまりないと思われるが)

// プロキシサーバーがhttpとhttpsで分かれている場合はたぶんこんな感じ(動作未確認)

let config = {
  mode: "fixed_servers",
  rules: {
    proxyForHttp: {
      scheme: "http",
      host: "proxy.example.com"
    },
    proxyForHttps: {
      scheme: "https",
      host: "proxy2.example.com"
    }
  }
};

設定したプロキシの設定を元に戻すにはchrome.proxy.settings.clearを呼び出す。

background.js
async function clearProxySettings() {
    await chrome.proxy.settings.clear({ scope: 'regular' });
}

なお、chrome.proxyを使用するにはmanifest.jsonpermissionsproxyの指定が必要である。

manifest.json
    "permissions": [
        "proxy",
        "storage",
        "tabs"
    ]

ここではchrome.storagechrome.tabsも使用するのでstoragetabsも指定している。

Chrome拡張のアイコンをクリックしたときの処理

アイコンをクリックしたときの処理を受け取るにはmanifest.jsonactionの指定が必要になる。

manifest.json
    "action": {}

actionの指定は空でよいが必要
消してはいけない。

ようやくメインのコードだが、アイコンがクリックされるとchrome.action.onClickedのイベントが呼ばれるのでaddListenerで処理を追加しておく。
プロキシ設定を有効にしたかのフラグはchrome.storage.sessionから取得・保存しておく。
proxyEnableの値を反転して、値によりプロキシの設定をするか、設定をクリアするか切り替える。

background.js
chrome.action.onClicked.addListener(async () => {
    chrome.storage.session.setAccessLevel({ accessLevel: 'TRUSTED_AND_UNTRUSTED_CONTEXTS' });

    let data = await chrome.storage.session.get('proxyEnable');
    let proxyEnable = !data.proxyEnable;

    if (proxyEnable) {
        await setProxySettingsFixedServer();
    }
    else {
        await clearProxySettings();
    }

    await chrome.storage.session.set({ "proxyEnable": proxyEnable });
});

chrome.storage.sessionを使用するには先にsetAccessLevelを呼び出す必要がある。

ブラウザを閉じたときの設定クリア

実はchrome.proxy.settings.setメソッドで設定した内容はブラウザを閉じても残っている。(終了時に自動で破棄されるような設定はみあたらなかった) 
このため、ブラウザを再度開いた際に「Chrome拡張をクリックしてないのにプロキシがONになってるぞ??」という事態になってしまう。
これを避けるため、ブラウザを閉じたときに設定をクリアしておく。

ブラウザを閉じたかの判定はchrome.tabs.onRemovedremoveInfo.isWindowClosingをチェックすればよい。
ここではremoveInfo.isWindowClosingがセットされていたらプロキシ設定をクリアする。

background.js
chrome.tabs.onRemoved.addListener((_tabId, removeInfo) => {
    if (removeInfo.isWindowClosing) {
        clearProxySettings();
    }
});

ソースコード

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?