Search code examples
google-chrome-extensionchrome-extension-manifest-v3

Prevent popup if current tab url is not permitted in manifest v3


I'm writing a chrome extension and I want to either disable the popup entirely, or present a message if the url of the current tab is not permitted via the v3 manifest's host_permissions property.

This is for a dev support tool and we don't want it enabled for the production url. So if I set:

"host_permissions": [
  "http://localhost:3000/",
  "https://*.dev.some-site.com/",
  "https://www.uat.some-site.com/"
]

...Then if the user is on www.some-site.com (or anywhere else), I want the popup to be disabled.

I can obtain the relevant url easily enough:

let [currentTab] = await chrome.tabs.query({ active: true, currentWindow: true });
const { url } = currentTab;
const cookieUrl = url.match(/https?:\/\/[^/]+\//)?.[0];

...and I can obtain the array of permitted file patterns with

chrome.runtime.getManifest().host_permissions

But how can I use this or anything else to prevent the popup? Also, converting that wild-card into a genuine regex will be a bit of a pain. Isn't there some out-of-the-box method to do all this??


Solution

  • Use chrome.declarativeContent API to enable the action popup for sites in host_permissions and disable it everywhere else by default.

    When disabled, the icon becomes grayed out. Clicking it will show the built-in context menu, chrome.action.onClicked won't be triggered. The name of the extension in the puzzle-piece menu is also grayed out.

    manifest.json:

      "action": {"default_icon": "icon.png"},
      "permissions": ["declarativeContent"],
    

    background script:

    chrome.action.disable();
    
    chrome.runtime.onInstalled.addListener(() => {
      chrome.declarativeContent.onPageChanged.removeRules(() => {
        chrome.declarativeContent.onPageChanged.addRules([{
          conditions: chrome.runtime.getManifest().host_permissions.map(h => {
            const [, sub, host] = h.match(/:\/\/(\*\.)?([^/]+)/);
            return new chrome.declarativeContent.PageStateMatcher({
              pageUrl: sub ? {hostSuffix: '.' + host} : {hostEquals: host},
            });
          }),
          actions: [new chrome.declarativeContent.ShowAction()],
        }]);
      });
    });
    

    For simplicity, I don't limit PageStateMatcher's schemes.