1

I have made a programatically injected version of a Chrome extension in order to have the extension working on pages from hosts with different top-level domain names (cfr previous post). Now I would like to add a link to an options page to the popup menu. However I keep getting the following error message:

Unchecked runtime.lastError: Cannot access contents of url "chrome-extension://••••••••••••••••/options.html". Extension manifest must request permission to access this host.

Can anyone tell me how to request such a permission? In background.js, I have also tried chrome.tabs.create({url: "options.html"}); without success.

Note that the options page is displayed ok, but the error message keeps coming.

manifest.json:

{
  "manifest_version": 2, 
  "name": "My Extension",
  "version": "0.5",
  "description": "Does what it does",
  "icons": {"32": "icon32.png",
           "48": "icon48.png",
           "128": "icon128.png"
           },
   "options_page": "options.html",         
  "background": {
              "scripts": ["background.js"],
              "persistent": false
            },
    "browser_action":{
    "default_popup": "popup.html"
  },                   
 "optional_permissions":["tabs","https://*/*"],
 "permissions": ["storage"]      
}

popup.html:

<html>
<head>
</head>
<body>
<ul>
<li id="li_1">Enable My Extension</li>
<li id="li_2">Options</li>
</ul>
<script src="jQuery.js"></script>
<script src="popup.js"></script>
</body>
</html>

popup.js:

jQuery(function($){
  var tabId = 0;
  $(document).ready(function(){
    $("#li_1").click(function(){ // this works
       window.close();
         chrome.permissions.request({
           permissions: ['tabs'],
           origins: ["https://*/*"]
        }, function(granted) {
          if (granted) {
            chrome.runtime.sendMessage("granted");
          } else {
            alert("denied");
          }
       });
    });
    $("#li_2").click(function(){ // this sends request to background.js which then causes error
      window.close();
      chrome.runtime.sendMessage("openOptions");
    });
  });
});

background.js:

chrome.runtime.onMessage.addListener(
  function(message) {
    switch(message){
      case "granted": //this works, please ignore
              var tabId = 0;
              chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
                tabId = tabs[0].id;
                injectScript(tabId);
                chrome.permissions.contains({origins:["https://*/*"]}, function(perm) {
                if (perm) { 
                  chrome.tabs.onUpdated.addListener(function(tabId){
                     injectScript(tabId);
                  });
                }
               });
             });
            
      break;
      case "openOptions": //this does not work – generates error msg
       chrome.runtime.openOptionsPage();
      break;
    }
  return true;
});
danbae
  • 563
  • 2
  • 8
  • 22
  • The error is caused by your injectScript which tries to executeScript into an extension page. This won't work because executeScript is only for web pages. You can either suppress/ignore the error or check the tab url before injecting it. – wOxxOm Dec 18 '20 at 04:55
  • @wOxxOm: Thank you for pointing me in the right direction. However, my attempt at filtering by tab info led to other problems. In the `background.js`'s `function injectScript(tabId)`, I changed to `chrome.tabs.get(tabId, function(thisTab){ //get tab info if(thisTab.title != "My Extension Options"){ //new condition chrome.tabs.executeScript(tabId, { file: "content.js" }); } });` Now, this works but any open `about:blank` tab present will cause an error message. You suggested using the url – how can I retrieve the extensions own url programatically? – danbae Dec 18 '20 at 13:45
  • See the documentation: chrome.tabs.get returns an object that has `url` property. – wOxxOm Dec 18 '20 at 13:50
  • Yes I know but then I must compare that url with the extension's options page url. How do I find that one? – danbae Dec 18 '20 at 13:52
  • This condition seems to work: `if(!thisTab.url.startsWith("chrome-extension") && !thisTab.url.startsWith("about:blank")){ chrome.tabs.executeScript(tab,{ file: "content.js" }); }` Does this seem sound enough for an answer? – danbae Dec 18 '20 at 14:02
  • I would use url.startsWith('http') – wOxxOm Dec 18 '20 at 15:18
  • Yes of course – I was just about to edit my previous reply accordingly :) – danbae Dec 18 '20 at 15:41

1 Answers1

0

As suggested by wOxxOm in a comment above, the error was caused by he extension's attempt to inject the content script into the options.html page. One way to circumvent that would be to insert a condition into the injectScript() function (which was not shown in the question) in background.js, ensuring that only web pages are injected. A working version is shown below.

background.js

function injectScript(tab){
 chrome.tabs.get(tab,function(thisTab){ // get tab info
    if(thisTab.url.startsWith("http")){  // condition: is this a web page?
      chrome.tabs.executeScript(tab,{ // if so, inject scripts
           file: "jQuery.js"
       }); 
      chrome.tabs.executeScript(tab,{
           file: "content.js"
      });
    }
  });   
}

chrome.runtime.onMessage.addListener(
  function(message) {
    switch(message){
      case "granted":
              var tabId = 0;
              chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
                tabId = tabs[0].id;
                injectScript(tabId);
                chrome.permissions.contains({origins:["https://*/*"]}, function(perm) {
                if (perm) { 
                  chrome.tabs.onUpdated.addListener(function(tabId){
                     injectScript(tabId);
                  });
                }
               });
             });
      break;
      case "openOptions":
       chrome.runtime.openOptionsPage();
      break;
    }
  return true;
});
danbae
  • 563
  • 2
  • 8
  • 22