Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome extension - how to access local file:// with manifest v3

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:

  1. Making the XMLHttpRequest from injected iframe as suggested by answer. This gives error net:ERR_UNKNOWN_URL_SCHEME when making the request net:ERR_UNKNOWN_URL_SCHEME

  2. 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. Access to XMLHttpRequest at 'file:///Users/clara.attermo/Downloads/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}});
});
like image 758
Clara Attermo Avatar asked Feb 17 '21 15:02

Clara Attermo


People also ask

Can Chrome extensions access local files?

In Google Chrome, links to local files are disabled, unlike IE. This extension allows you to open a link to a local file by clicking it.

How do I see manifest of Chrome extensions?

You can just use chrome. runtime. getManifest() to access the manifest data - you don't need to GET it and parse it.

How do I view manifest JSON?

First check if manifest. json is applied in the browser. For that open developer window by pressing shortcut F12. In Application tab, click Manifest option and see if it displays information that you have set.

What is manifest in Chrome extension?

The manifest file uses JSON format to describe the important information about the extension. It contains fields that are required and recommended while others are optional depending on the extension you are building. name refers to the name of the extension and should be up to 45 characters.


Video Answer


1 Answers

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:

  1. 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.
  2. The content script adds an invisible iframe that points to iframe.html file exposed in web_accessible_resources
  3. 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.
like image 55
wOxxOm Avatar answered Oct 20 '22 03:10

wOxxOm