Currently my extension opens a web page at
chrome-extension://bpmcncockdffdifceihffkimpfbobjhn/dist/webpage.html
How do I make it so that the webpage.html is omitted, and that the following url:
chrome-extension://bpmcncockdffdifceihffkimpfbobjhn
Immediately points to the webpage?
Chrome extensions pages are treated as direct file URLs, not as server pages, so there is no default handler for directories like index.html.
Persistent background script
If your background script doesn't have "persistent": false in manifest.json you can use webRequest API to redirect such a fake URL into the real one:
manifest.json:
"permissions": ["webRequest"],
"background": {
"persistent": true,
"scripts": ["background.js"]
}
background.js:
chrome.webRequest.onBeforeRequest.addListener(e => {
return {redirectUrl: chrome.runtime.getURL('/dist/webpage.html')};
}, {
urls: [chrome.runtime.getURL('/')],
types: ['main_frame'],
}, ['blocking']);
Event page background script
If your background script has "persistent": false in manifest.json you can use webNavigation API to redirect an error page to the real page. The only nuisance is that there'll be a dummy item in the tab's history and the history back button will be active (but it won't work of course as it'll be redirected again).
manifest.json:
"permissions": ["webNavigation"],
"background": {
"persistent": false,
"scripts": ["background.js"]
}
background.js:
chrome.webNavigation.onErrorOccurred.addListener(({tabId}) => {
chrome.tabs.update(tabId, {url: '/dist/webpage.html'});
}, {
url: [{
urlEquals: chrome.runtime.getURL('/'),
}],
});
There is also declarativeWebRequest but only in Chrome beta/dev/Canary. And just for fun, it's possible to use webRequest API with nonpersistent event pages but it's hacky (you'll have to prevent unloading of the event page by opening a message connection from an iframe inside the background page) and defeats the purpose of event pages so I won't be showing it here.
Related
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.
As the title, when I remove extension on Development mode, the Background Console disapear immediately. It makes hard to debug.
I want to write an event, call to the server if user remove my extension.
Details my code:
manifest.json
"background": {
"scripts": ["bg.js"],
"persistent": false
},
"permissions": [ "management","storage","proxy", "*://*/*" ],
bg.js
chrome.management.onUninstalled.addListener(function (info) {
console.log('Uninstall event caught!');
// I write script here
});
Thanks for any help!
chrome.management.onUninstalled is only fired when other extension is uninstalled.
You could listen to that in another extension.
You can use chrome.runtime.setUninstallURL to do something in the server.
I'm pretty new at chrome extensions and am trying to make a simple one that automatically launches links in my emails. I am going to modify it a bit later on, but for now, this is all I am trying to do. How do I have a chrome extension automatically read the text of the current tab that I am on, or when I open emails if I can get that specific? I have a manifest file set up and currently can make the extension button launch a link, but I'd rather have this happen automatically, as I don't want to hit a button to launch a link when I could just click the link itself.
manifest.json
{
"manifest_version": 2,
"name": "MT task launcher",
"description": "This extension launches Task Links in emails",
"version": "1.0",
"background": {
"scripts": ["task.js"]
},
"browser_action": {
"default_icon": "icon.png",
"default_title": "Email Task Launcher"
},
"permissions": [
"activeTab"
]
}
task.js
chrome.browserAction.onClicked.addListener(function(tab) {
var action_url = "http://www.reddit.com";
chrome.tabs.create({ url: action_url });
});
Take a look at Official Guide, for your purpose, I think you should use content scripts ( which are injected into current web page), then read the DOM and get all the links. To open the links, you can either call window.open() or by passing message then open them via chrome.tabs.create
There are two options to do that, it's either edit the local copy of the extension or to inject the call to the extension.
Inject code as a Content script, use the matching rules as defines in the manifest file
A background page file use the 'chrome.tabs.onUpdated' event. Also, use the 'chrome.tabs.executeScript' method to inject script.
I'm completely new to Chrome Extensions. I want the creation of a bookmark to trigger a xmlhttprequest. Right now, I'm just trying to get a new bookmark event to do a console.log and can't see what I'm missing.
Here is my manifest.json:
{
"manifest_version": 2,
"name": "Booky Desktop Integration",
"description": "Sends New Chrome Bookmarks To Your Booky Desktop.",
"version": "1.0",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"bookmarks",
"http://bookydesktop.com/"
]
}
Here is my js:
chrome.bookmarks.onCreated.addListener(function(id, bookmark) {
console.log("bookmark created");
});
What am I missing?
Your code works perfectly as written. You're probably not viewing the console for your background page. You need to:
Open chrome://extensions/ (or click "Extensions" in Chrome's "Settings" menu)
Ensure "Developer mode" is ticked in the top right
Open the console by clicking "_generated_background_page.html (Inactive)" in the "Inspect views" list under your extension
Each page in Chrome has its own console instance. You were looking at the consoles of ordinary web pages, instead of looking at the console for your background page.
It is a simple extension that invokes Xmlhttprequest to send POST data to a form. I have also added simple message boxes at beginning/end of the js code... The code is being invoked from a background page and correct permissions have been granted in manifest.json.
However when I click on the button for this extension, nothing is happening.
Given below is the js code for the extension-
alert("Beginning of code block");
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST","http://taurusarticlesubmitter.appspot.com/sampleform",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("name=Arvind&description=Test description&email=arvind#taurusseo.com");
alert("End of code block");
Also, I added the following code to background.html--
<script>
// Called when the user clicks on the browser action.
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(
null, {file: "cdr.js"});
});
chrome.browserAction.setBadgeBackgroundColor({color:[0, 200, 0, 100]});
</script>
Finally, given below is my manifest.json--
{
"name": "My Second Extension",
"version": "1.0",
"background_page": "background.html",
"description": "The second extension that I made.",
"browser_action": {
"name": "Data in iframe",
"default_icon": "icon.png"
},
"permissions": [ "tabs",
"bookmarks",
"http://*/*",
"https://*/*",
"unlimitedStorage"
]
}
I assume that your first code block is cdr.js? Then you are not running it from the background page. Instead your background page loads a content script that tries to send a request. Content scripts run with the privileges of the page that they have been injected into. So if that page doesn't have privileges to send a request to taurusarticlesubmitter.appspot.com then the content script won't have the necessary privileges either.
If your content script needs to perform a privileged action (like sending a request to a third-party page) it should send a message to the background page and the background page will have to do it.