Why the extension with specific key declared can access chrome:// pages? - google-chrome-extension

As we know, by default chrome extensions doesn't have access to chrome:// pages such as chrome://extensions and chrome://settings. ( Of course we can change chrome://flags/#extensions-on-chrome-urls flags however the following question is based on that we didn't change the default flags).
Recently I happen to find ChromeVox (offered by chrome.google.com) can work well in all pages including chrome:// pages. I checked the source code for this extension and find as long as we add the following line in manifest.json for any extension, the extension can work well in chrome:// pages.
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEGBi/oD7Yl/Y16w3+gee/95/EUpRZ2U6c+8orV5ei+3CRsBsoXI/DPGBauZ3rWQ47aQnfoG00sXigFdJA2NhNK9OgmRA2evnsRRbjYm2BG1twpaLsgQPPus3PyczbDCvhFu8k24wzFyEtxLrfxAGBseBPb9QrCz7B4k2QgxD/CwIDAQAB"
So it looks like chrome has something like whitelist to allow specific extensions to break the default restrictions. Am I right? Is there official guide to clarify this behavior?
Appendix:
The following is a sample extension, you will find with the key, console will output test even in chrome://extensions pages; however once removing the key, nothing happens.
manifest.json:
{
"manifest_version": 2,
"name": "Test",
"version": "1.0",
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"content.js"
]
}
],
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEGBi/oD7Yl/Y16w3+gee/95/EUpRZ2U6c+8orV5ei+3CRsBsoXI/DPGBauZ3rWQ47aQnfoG00sXigFdJA2NhNK9OgmRA2evnsRRbjYm2BG1twpaLsgQPPus3PyczbDCvhFu8k24wzFyEtxLrfxAGBseBPb9QrCz7B4k2QgxD/CwIDAQAB"
}
content.js:
console.log('test');

"key" property in manifest.json uniquely defines the extension's ID in encrypted form.
Some Google extensions are unfairly(?) whitelisted by ID in the source code of chromium.
In this case, ChromeVox:
scripting_whitelist_.push_back(extension_misc::kChromeVoxExtensionId);
And then this whitelist is checked to see whether an extension can run everywhere in PermissionsData::CanExecuteScriptEverywhere, which is accessed in CheckRestrictedUrls where we can see restricted schemes: chrome://, chrome-extension://, chrome-debugger://

Related

how can i get the local file in chrome extension v3 [duplicate]

I have a Chrome extension that can (if you allow access to file URLs) grab your local pdf file that you have open in chrome and send it on to our API for processing. This is done by fetching the pdf with XMLHttpRequest to file:///Users/user/whatever/testfile.pdf from the background script.
When migrating to manifest v3 for a Chrome extension the background script becomes a service worker. In a service worker only fetch is available, not XMLHttpRequest. Problem is, fetch only supports http and https, not file:// urls. So how can I make the same feature of having the Chrome extension fetching/getting the local file?
EDIT: Things I also tried:
Making the XMLHttpRequest from injected iframe as suggested by answer.
This gives error net:ERR_UNKNOWN_URL_SCHEME when making the request
Making the XMLHttpRequest from injected content script.
This gives error Access to XMLHttpRequest at 'file:///.../testfile1.docx.pdf' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
From what I can understand from a lot of research access to file:// is in general blocked and Chrome extension background scripts used to be an exception to this. Seems to me it was never allowed from content scripts or action popups.
My manifest.json for reference:
{
"manifest_version": 3,
"name": "..",
"version": "0.1",
"icons": {
"16": "assets/icon-16x16.png",
"48": "assets/icon-48x48.png",
"128": "assets/icon-128x128.png"
},
"action": {
"default_title": ".."
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"webRequest",
"activeTab",
"scripting",
"storage",
"unlimitedStorage",
"identity",
"pageCapture"
],
"host_permissions": [
"<all_urls>"
],
"web_accessible_resources": [{
"resources": ["iframe.html"],
"matches": [],
"extension_ids": []
}]
}
The content script is injected programmatically (using webextension-polyfill for promise support)
browser.action.onClicked.addListener(async (tab: Tab) => {
await browser.scripting.executeScript({files: [ "inject.js" ], target: {tabId: tab.id}});
});
Chrome 98 and older can't do it in the background service worker for the reasons you mentioned.
There was also a bug that prevented doing it in a normal visible chrome-extension:// page or iframe. It's fixed in Chrome 91.
Solution
Use fetch in Chrome 99 and newer.
In older versions use the following workarounds.
Workaround 1: File System API, Chrome 86+
A ManifestV3 extension can use the new File System API to read the contents of the file, for example inside the iframe exposed via web_accessible_resources.
Workaround 2. Extension frame, Chrome 91+
Use a content script that runs in the tab with that pdf:
matches in manifest.json should contain <all_urls> or file://*/* and file access should be enabled by the user in
chrome://extensions UI for your extension. Alternatively you can use
activeTab permission and programmatic injection when the user
clicks your extension's icon or invokes it through the context menu.
The content script adds an invisible iframe that points to iframe.html file exposed in web_accessible_resources
The iframe.html loads iframe.js which uses XMLHttpRequest as usual. Since the iframe has chrome-extension:// URL its environment
is the same as your old background script so you can do everything
you did before right there.
Workaround 3. Extension window/tab, Chrome 91+
An alternative solution is to use any other visible page of your
extension like the action popup or options page or any other
chrome-extension:// page belonging to your extension as they can
access the file:// URL via XMLHttpRequest same as before.
Notes
File access should be enabled in chrome://extensions page for this extension.

How to make write a chrome extension which is always enabled for any urls?

I'm writing a chrome extension, to do some modification to the page content, but I have to click on it to make it working on current page.
What I want is: if I click on the extension icon (to enable it), it will always enabled, no matter what new pages/tabs are open, and will work on them?
How to write code to configure it?
Using content script you can achieve this. Content scripts are files that run in the context of web pages so you can modify webpage content.
Add below code in manifest.json
{
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["your-content-script.js"]
}
],
"permissions": [
"tabs", "http://*/*","https://*/*"
]
}
To learn more, read this https://developer.chrome.com/extensions/overview.html#arch

Chrome extensions (and/or tampermonkey scripts) not running on certain websites (like gmail)

I have a very simple chrome extension that refuses to run on some sites like https://mail.google.com. It runs fine on other sites which makes me think something is limiting extensions/scripts from running on some sites. The sample case is quite simple and listed below.
With this sample case I see "Hello world" in the developer console when I navigate to https://about.me. I also see the extension in the Developer Console's Execution Context Selector. However, when I navigate to https://mail.google.com I don't see the log entry or the extension in the Execution Context Selector.
I have tried something similar with tampermonkey and am not seeing that script run on gmail either. Thanks!
manifest.json:
{
"manifest_version": 2,
"name": "Gmail extension test",
"version": "0.1.9",
"description": "Try running inside gmail page",
"content_scripts": [{
"all_frames": true,
"js": ["content.js"],
"matches": [
"https://mail.google.com/*",
"https://about.me/*",
"http://*/*",
"https://*/*"
]
}]
}
content.js:
console.warn("Hello world");
Environment:
Chrome 66.0.3359.117
macOS 10.13.3 (17D102)
As #wOxxOm suggested. I tracked down the problem to the fact that my company has a Chrome policy set against running extensions on the google.com domain. I had no warning entries in the Developer Console or the macOS Console, I just tracked down other folks complaining about in an internal forum.
The policy that applies in this case is ExtensionSettings which is set in a OS/device specific way. To help diagnose this restriction, you can view your active polices in Chrome under chrome://policy/. In my case I had something like the following in my chrome://policy:
{
"*": {
...
"runtime_blocked_hosts": [ "*://*.google.com", ....]
},
I'm not aware of a generic workaround for this at the extension level. Instead I had to work with my company IT department to whitelist the extension.

Google Chrome Extension manifest.json file

I'm developing a Google Chrome Extension and facing a challenge with the background; the browser doesn't load the background picture added in CSS.
I can't seem to find an effective way to declare assets under the web_accessible_resources key in the manifest.json file.
What is the manifest.json file and how does one declare assets in it?
A manifest.json file is required for any Chrome extension. The manifest.json file contains information that defines the extension. The format of the information in the file is JSON.
You can read more about what it contains in Google Chrome developer documentation: Manifest File Format
You will probably also want to read: Overview of Google Chrome Extensions
A relatively simple manifest.json file looks like (source: Getting Started: Building a Chrome Extension):
{
"manifest_version": 2,
"name": "Getting started example",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"https://ajax.googleapis.com/"
]
}
Manifest - Web Accessible Resources:
This is an array of strings assigned to the key web_accessible_resources within your manifest.json file which specifies the assets within your extension that are to be made accessible by webpages. The file/path within manifest.json is relative to your extension's root directory. The webpage can access the resource from a URL that looks like: chrome-extension://[PACKAGE ID]/[PATH].
Example (source:Manifest - Web Accessible Resources):
{
...
"web_accessible_resources": [
"images/*.png",
"style/double-rainbow.css",
"script/double-rainbow.js",
"script/main.js",
"templates/*"
],
...
}
For more information on web_accessible_resources see Google Chrome developer documentation: Manifest - Web Accessible Resources.

How to link to the extension-affected version of a page from within an iframe?

Let me explain. My chrome extension consists of this:
Injecting an html page in an iframe
Inside this html page is another iframe sourced to an external site
This external site is being modified by the extension also
The problem is I am not seeing the effects I should be. How do I specify I want to display the version of my site affected by the extension?
Edit: Here is the exact part of the code that Im working with:
<iframe id="wikiforum" src="http://mudandblood.net/html/modules.php?name=Forums"></iframe>
That url its currently pointing to is also having css and js injected into it by my extension. Everything works how it should when I visit the site directly, but through the iframe it remains unchanged. Thats what I'm trying to fix.
2nd Edit: Yes, I am injecting the content scripts through the manifest. Like so:
{
"name": "MnB2+",
"version": "1",
"manifest_version": 2,
"content_scripts": [
{
"js": ["contentscript.js"],
"matches": ["http://mudandblood.net/mudandblood2.swf","http://www.mudandblood.net/mudandblood2.swf"],
"all_frames": true
},
{
"css": ["style.css"],
"js": ["csforum.js"],
"matches": ["http://mudandblood.net/html/*"]
}
],
"permissions": [
"tabs"
],
"web_accessible_resources": [
"irc.html",
"wiki.html",
"style.css",
"vectors/*.svg"
]
}
So I'm a dolt and a noob, I solved my own problem. Downvote me as you will, I apologize sincerely. Wouldn't have figured it out though if I didn't post here.
The key was I didn't include "all_frames": true in the second content script section. Hope this at least helps another newbie on the way.

Resources