4

I have created a Chrome extension that, as part of it's operation, opens a new tab with a specified url.

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if( request.message === "open_new_tab" ) {
      chrome.tabs.create({"url": request.url});
    }
  }
);

(Full code available on GitHub)

This works fine on tabs with webpages, but I cannot get it to work on empty tabs, for example: chrome://apps/ To clarify, if I have a tab open and it is on stackoverflow.com, then when I click on my extension button it opens a new tab loading a generated url. When I am on a new tab, or a tab where the url begins with chrome:// then the extension does not work.

What permissions do I need to include to allow the extension to open in ANY tab? Including new tabs and any chrome:// tab?

Manifest.json:

{
  "manifest_version": 2,

  "name": "MyMiniCity Checker",
    "short_name": "MyMiniCity Checker",
  "description": "Checks what your city needs most and redirects the browser accordingly.",
  "version": "0.2",
    "author":"Richard Parnaby-King",
    "homepage_url": "https://github.com/richard-parnaby-king/MyMiniCity-Checker/",
    "icons": {
      "128": "icon-big.png"
   },

    "options_page": "options/options.html",

  "browser_action": {
    "default_icon": "icon.png"
  },
    "permissions": ["tabs","storage","http://*.myminicity.com/","http://*/*", "https://*/*"],
    "background": {
    "scripts": ["background.js"],
    "persistent": false
    },
    "content_scripts": [ {
    "matches": [ "http://*/*", "https://*/*"],
    "js": [ "jquery-1.11.3.min.js" ]
  }]
}

Background.js:

//When user clicks on button, run script
chrome.browserAction.onClicked.addListener(function(tab) {
    chrome.tabs.executeScript(null, { file: "jquery-1.11.3.min.js" }, function() {
    chrome.tabs.executeScript(null, { file: "contentscript.js" });
    });
});

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if( request.message === "open_new_tab" ) {
      chrome.tabs.create({"url": request.url});
    }
  }
);

It appears as though the background.js file is not being executed. I suspect this to be a permissions. What permissions do I need in order to run this extension in every tab?

Richard Parnaby-King
  • 14,703
  • 11
  • 69
  • 129
  • Your question is quite unclear. I can _guess_ what you mean (some OTHER code of yours does not work in `chrome://apps/`), but for instance this code will open `chrome://apps/` in a tab if requested. I will not answer unless you improve the question. – Xan May 15 '15 at 12:48
  • If I am on a tab that has loaded stackoverflow.com, clicking my extension button will execute the code and a new tab will be opened with a url generated by the extension. When I am on a new tab, or a tab beginning with `chrome://` the extension button does not appear to work when clicked on. – Richard Parnaby-King May 15 '15 at 13:41
  • Then you're not showing the code that's actually not working. This piece is just fine - it's not being invoked. To help, I need to know what the rest of your code does. – Xan May 15 '15 at 13:42
  • I have included the code in my manifest and background files. I suspect this is a permissions issue. – Richard Parnaby-King May 15 '15 at 13:49
  • as Xan wrote, you cannot inject content scripts on internal pages. There is a exclusive situation on new tab page if Google or Bing are set as search engines. Then you can inject scripts into that tabs, but if any other engine is set, I think it's not possible (those two works with iframes in which you can inject something, that's my my personal experience, maybe there is some other mechanism). Btw. your button code will work on any page, maybe you can create logic based on that (if tab.url *chrome://something* inform user) – Wolf War May 15 '15 at 14:45
  • I have tried putting an `alert` at the top of my background.js file on a new tab and it does not fire. Thanks for the suggestion, though :) – Richard Parnaby-King May 15 '15 at 14:57
  • @RichardParnaby-King I just tested it with my old extension that uses browserAction button. Alert fires on internal pages [example](http://prntscr.com/75iskm) ...and I don't have any permissions in manifest EDIT: forgot to say, fires also on new tab page – Wolf War May 15 '15 at 15:58
  • @RichardParnaby-King I missed the obvious again. You meant it doesn't fire on msg from content script?... [it does too](https://www.youtube.com/watch?v=L5eIeEgKFv0&feature=youtu.be) this content script fires my app with message passing trough background script... from new tab... (some example video that I made recently for discussion on Opera blog) – Wolf War May 15 '15 at 16:32
  • @WolfWar I have migrated all the content script code into the background.js file. As I am not accessing/manipulating the DOM there is no need for the code to be there. I don't know why the alert did not fire before, but it does now and the extension works as intended now :) – Richard Parnaby-King May 18 '15 at 08:56

2 Answers2

7

Well, this message is supposed to come from a content script you're trying to inject into the current tab.

The widest permission you can request is "<all_urls>", however, there are still URLs that are excluded from access.

  1. You can only normally access http:, https:, file: and ftp: schemes.

  2. file: scheme requires the user to manually approve the access in chrome://extensions/:

<code>file:</code> access

  1. Chrome Web Store URLs are specifically blacklisted from access for security reasons. There is no override.

  2. chrome:// URLs (also called WebUI) are excluded for security reasons. There is a manual override in the flags: chrome://flags/#extensions-on-chrome-urls, but you can never expect it to be there.

  3. There is an exception to the above, chrome://favicon/ URLs are accessible if you declare the exact permission.

All in all, even with the widest permissions you cannot be sure you have access. Check for chrome.runtime.lastError in the callback of executeScript and fail gracefully.

Xan
  • 74,770
  • 16
  • 179
  • 206
5

As I was wanting this to run on EVERY page it meant I could not have the code in the content script. I moved all the code into the background script:

chrome.browserAction.onClicked.addListener(function(tab) {
        //... 
        chrome.tabs.create({"url": newTabUrl});
        //...
});

So when I click on my button the above code is called, using the enclosed jquery script.

Richard Parnaby-King
  • 14,703
  • 11
  • 69
  • 129
  • What's the point of trying to inject something if you're immediately navigating away? More to the point - if that's supposed to work on every page, what kind of code you have in the content script? – Xan Sep 01 '16 at 09:20
  • I don't have any code in the content script. It's been removed. The purpose of the plugin is when the user clicks on the button to perform an ajax call getting an xml response, process the response and open a tab to another page based on the result. None of which requires access to the tab content. Originally, the user clicked on the button which executed the content script which did the ajax bit and processing, then sent a message back to the background script which was the new tab url to open. Now it's all contained in the background script. – Richard Parnaby-King Sep 01 '16 at 09:29
  • So why is there still an attempt to inject jQuery? – Xan Sep 01 '16 at 09:30
  • jQuery is included in the plugin and is loaded as part of the manifest. The `chrome.tabs.executeScript` bit is running jQuery in the background so the rest of the code can work. I shall remove that bit from my answer as it is not really part of the solution... – Richard Parnaby-King Sep 01 '16 at 09:33
  • "The chrome.tabs.executeScript bit is running jQuery in the background" No, it doesn't! Calling it with null tries to inject it in the current tab, not in the background. That's what I'm trying to do, fix a (conceptual) mistake I accidentally caught a glimpse of. – Xan Sep 01 '16 at 09:34