I have a piece of code that requests a new permission for my chrome extension. The new permission I try to get is nativeMessaging. I get my popup where chrome asks to grant the new permission, now here is where the trouble begins.
According to chrome.permissions.getAll and chrome.permissions.contains I have the permission I requested. But when I check chrome.runtime, for example connectNative doesn't show up.
Also when I try to get the permission manually on the extension background page, I get the popup, according to getAll and contains I have the permission but still I get the error, that connectNative is not available.
As a workaround for now I just reload the extension with chrome.runtime.reload() and it works. but I would like to have it without release.
Is there a case, where the chrome object is not updated after you acquired new permissions?
found out what happened. after you accessed chrome.runtime once, it is no longer possible to update it.
here is an example to trigger the problem:
bg.js:
chrome.runtime;
chrome.browserAction.onClicked.addListener(() => {
chrome.permissions.request({
permissions: ['nativeMessaging'],
}, granted => {
console.log(chrome);
const type = typeof chrome.runtime.connectNative;
alert((type === 'function' ? 'GOOD' : 'BAD') + ': ' + type);
});
});
manifest.json
{
"name": "Native Messaging Example",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts": ["bg.js"]
},
"browser_action": {},
"optional_permissions": [
"nativeMessaging"
]
}
comment the line 'chrome.runtime;' and it works again.
Related
Here is my background script;
/**
* CSS to hide everything on the page,
*/
const hidePage = `body > : {
display: none;
}`;
/**
* When a tab is loaded, check if the plugin is on. If the plugin is on, check if the url matches the page.
* If it does, block it
*/
browser.tabs.onActivated.addListener(function (activeInfo) {
browser.storage.local.get("onOff")
.then((result) => {
if (Object.entries(result).length === 0 || !result.onOff.value) {
return;
}
browser.tabs.query({ currentWindow: true, active: true }).then((tabs) => {
let tab = tabs[0];
console.log(tab.url);
browser.tabs.insertCSS({code: hidePage})
}, console.error)
});
});
and here is my manifest.json
{
"manifest_version": 2,
"name": "Beastify",
"version": "1.0",
"description": "Adds a browser action icon to the toolbar. Click the button to choose a beast. The active tab's body content is then replaced with a picture of the chosen beast. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#beastify",
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify",
"icons": {
"48": "icons/beasts-48.png"
},
"permissions": [
"tabs",
"activeTab",
"storage"
],
"browser_action": {
"default_icon": "icons/beasts-32.png",
"default_title": "BlockIt",
"default_popup": "popup/blockit.html"
},
"background": {
"scripts": ["background_scripts/blocker.js"]
},
"web_accessible_resources": [
"beasts/frog.jpg",
"beasts/turtle.jpg",
"beasts/snake.jpg"
]
}
There is some superfluous stuff there because I am building my add-on from a Firefox extension tutorial.
The exact code that is causing the
Uncaught (in promise) Error: Missing host permission for the tab is
browser.tabs.insertCSS({code: hidePage})
line 23 of blocker.js
I believe I do have the correct permissions to insert css from this background script, so I cannot figure out why this error is occurring. I also tried to execute a content script instead of running the line above that is throwing the error, but that failed with the same error.
activeTab works only when the user explicitly invokes your extension as described in the documentation for WebExtensions and Chrome extensions). Evidently, its name is highly misleading: it should have been something like activeTabWhenInvoked.
In order to access any tab without prior interaction with your extension you'll have to add broad host permissions in manifest.json:
"permissions": ["<all_urls>"],
Now there's no need for activeTab, but you may still want to keep tabs permission for Firefox older than 86, see the note in the documentation.
P.S. It's better to remove the listener altogether when onOff is false so the extension doesn't run in vain. You can do it by using a global named function for the onActivated listener and observing the changes to onOff via browser.storage.onChanged event.
Sorry for my poor English, i hope you can understand the issue.
I'm new to chrome extension development,and for sure in my code there are a lot of
thing to change or optimize;
anyway i've written a simple code that, (seems) works at least from my chrome.
The code clicks a button every X minutes in specific page, then wait and parse the result in page.
I've :
a content script (loaded from manifest.json) which "inject" some button and text Input box in page, so user can sets some "filter params" before click a "start button"; the start button then sendMessage() to background.js to set Alarm Event for the click ;
an eventPage (which is set persistent true in actually ) which handle the request from tabs and set a countdown alarm for each tab; when X min are passed fire a message to the interested tab;
I also have a popup.html e popup.js not important here (i think).
I've to distribuite this extension manually, so i would distribuite a zip that user can load with "developer mode ".
*Now the issue is: why the code was working only on my Chrome ? *
I've tested with others 2-3 laptop with Chrome, the background script is loaded (i can see the background page printint console log)
but in webpage the contents.js seems no way executed .
In my chrome works well: i can see in console some initial output (i print the name of dir extension to check) and
the dynamic created element (button,input box ect.) in page.
And all is working, i can fire the start button and receive results of parsing.
During the development i've never run the extension on other machine. Yesterday i've succssfully tested on 2-3 laptop.. then i made only few change but nothing serious.
Today i can run only in my chrome.
In other pc nothing, neither the simple console.log output first line of script.
I can read in console log :
"Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist."
but this also in my working istance in my laptop chrome .
The zip file is the same and the extraction is good, in fact i can actually load the extension and i see the background page debug console.log() sentences
In some case, in laptop where it dosen't work, i've received a message relative jQuery and the fact that chrome.runtime.sendMessage() is not defined; and it points to code in webpage, not mine.
I've see that in webpage code there is something like:
var extid = "mcmhdskbnejjjdjsdkksmeadjaibo";
var extVer = "1.5";
var extStatus = 0;
$(document).ready(function () {
///...
chrome.runtime.sendMessage(extid, {message: "version"},
function (reply) {
if (reply) {
if (reply.version) {
if (reply.version == extVer) {
if (reply.gminfo != 'OK') {
extStatus = 1; /// ...
Seems that chrome.runtime is undefined, and the webpage can't call the sendMessage().
EDIT: this undefined occurs only when my extension is loaded
Maybe there is some conflict when i load my extension? But in my chrome browser works...
Can some expert indicate in where direction i've to investigate?
Thanks a lot for any suggestions.
My Manifest.json :
{"manifest_version": 2,
"name": "myAlarm",
"description": "This extension alerts.",
"version": "0.1",
"permissions": [
"alarms",
"system.cpu",
"storage",
"tabs",
"webNavigation",
"https://www.mytargetsite.com/subUrl/"
],
"web_accessible_resources": [
"icon.png",
"vanillaSelectBox.css"],
"content_scripts": [
{
"matches": ["https://www.mytargetsite.com/subUrl/"],
"css": ["vanillaSelectBox.css"],
"js": ["jquery-3.3.1.min.js","vanillaSelectBox.js","taffy-min.js","content.js"],
"run_at": "document_end"
}
],
"background": {
"scripts": ["eventPage.js"],
"persistent": true
},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"icons": {
....
}
}
My contents,js (stripped):
chrome.runtime.onMessage.addListener(
function(request, sender) {
// here i parse message "time'up" from background js
});
window.addEventListener('load', function() {
var pt=chrome.runtime.getURL('filterOff.wav');
var p=pt.split("/");
console.log("[myAlarm v0.1] started" );
console.log("[myAlarm v0.1] folder : ("+p[2]+")");
// here i start an active wait for the presence in page of button with ID= btntarget_id
waitForElementToDisplay("#btntarget_id", 500); //when function find button then create and add button and input text to webpage
});
My eventPage.js :
var curr_alarms =[];
chrome.extension.onMessage.addListener(function(request, sender)
{ /// here receive start countdown message from content.js and set alarm ...
}
chrome.alarms.onAlarm.addListener(function(alarm) {
/// here i manage each alarm for each tab
});
chrome.tabs.onRemoved.addListener(function(tabid, removed) {
// ...
});
chrome.tabs.onUpdated.addListener(function
(tabId, changeInfo, tab) {
//
});
edit : in browser where it dosen't work i can read also :
Access to XMLHttpRequest at 'https://mytargetsite.com/suburl/grid.php' (redirected from 'https://mytargetsite.com/suburl/grid.php') from origin 'https://mytargetsite.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
The fact that the declared content script runs or not, should be verified by inspecting in devtools => sources sub-tab => content scripts sub-sub-tab. If it really doesn't run, there can be just two explanations: the URL is different (for example not https) or extensions are blocked by their domain admin via runtime_blocked_hosts which you can see in chrome://policy.
Your development mode extension's id will be different on a different machine unless you pin it by adding a "key" in manifest.json
To use chrome.runtime to send messages to your extension from a webpage code (not from a content script!) your extension's manifest should declare "externally_connectable" and use a different event onMessageExternal, see also sending messages from web pages.
The CORS error may be irrelevant to your code (you can investigate the source of the error by expanding the error's call stack in devtools console).
I am working on an extension for Google Chrome. This allows our users to submit support tickets from our online product directly from the page they are on.
I have been using page rules to limit the extension to only our products pages. Some of our users are experiencing an issue were they popup no longer works.
This is what some of our users are seeing when they are one our products pages. Also the extensions icon is in full colour when the user sees this. Not sure if that is useful information.
I am having trouble recreating the issue. Most of our users are remote making is difficult to diagnose.
To recreate the issue I have tried force quitting chrome and reopening. Also a restart of my computer didn't recreate it.
It does seem that removing the extension and reinstalling it fixes the issue.
This is the code that I am using to enable/disable the extension.
const PAGE_RULE = [{
id: 'DISPLAY_RULE_SS',
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: {hostSuffix: '.localhost.com', pathPrefix: '/app/'},
}),
],
actions: [new chrome.declarativeContent.ShowPageAction()],
},]
chrome.runtime.onInstalled.addListener(function() {
chrome.tabs.onActivated.addListener((activeInfo) => {
chrome.declarativeContent.onPageChanged.getRules(['DISPLAY_RULE_SS'], (rules) => {
if(rules.length !== 0){
return;
}
chrome.declarativeContent.onPageChanged.addRules(PAGE_RULE);
});
});
});
This is my manifest.
{
"name" : "Support App",
"version" : "0.0.3",
"description" : "Fill in a brief description of your issue, along with a few details, and our support team will be notified immediately.",
"manifest_version" : 2,
"icons": {
"128" : "./img/murmuration_square_transparent.png"
},
"background" : {
"scripts" : ["./backgrounds/default_background.js"],
"persistent" : false
},
"permissions" : [
"history",
"tabs",
"declarativeContent",
"activeTab",
"https://*.localhost.com/*",
],
"page_action" : {
"default_icon" : "./img/murmuration_square_transparent.png",
"default_popup" : "../default_interface.html"
},
"web_accessible_resources": [
"src/default_index.js"
]
}
I suspect that the issue is related to the fact that all the logic is within chrome.runtime.onInstalled.addListener(function() {...} but I'm unsure.
Any help is appreciated.
I have returned to this after some downtime and found the solution in the Google documentation. The documentation on this page state
Listeners must be registered synchronously from the start of the page.
which is exactly what I was doing when setting the page rules.
I also found on this page that
Rules are persistent across browsing sessions. Therefore, you should
install rules during extension installation time using the
runtime.onInstalled event. Note that this event is also triggered when
an extension is updated. Therefore, you should first clear previously
installed rules and then register new rules.
So I have updated my background script to run the following
chrome.runtime.onInstalled.addListener(details => {
chrome.declarativeContent.onPageChanged.removeRules(undefined, () => {
chrome.declarativeContent.onPageChanged.addRules(PAGE_RULE);
});
});
Which is what is recommended in the documentation. This seems to have solved the issue we were encountering.
I'm new to Chrome extension development. I am currently looking to make a Chrome extension to dismiss notifications. I want the extension to be activated once via shortcut keys.
Before looking at the code below, I want to let it be known that the alert does show up... but the Chrome Extensions page shows the error:
"Error in event handler for commands.onCommand: TypeError: Cannot read property 'getAll' of undefined"
on the line:
chrome.notifications.getAll((items) => {
The chrome.notifications object is somehow undefined, so it seems that Chrome thinks that there are no current notifications being displayed...which is strange because there indeed are, as the image shows.
Would anyone please help by shedding some light on this situation?
manifest.json:
{
"name": "ClearAll",
"version": "1.0",
"description": "Clear notifications!",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"commands": {
"clear": {
"suggested_key":{
"default": "Alt+Shift+S"
},
"description": "Executes clear"
}
},
"manifest_version": 2
}
background.js:
chrome.commands.onCommand.addListener(function(command) {
if (command == 'clear') {
alert("testing");
chrome.notifications.getAll((items) => {
if (items)
for (let key in items)
chrome.notifications.clear(key);
});
}
});
Error:
You might already have figured this out, but for anyone who stumbles upon this question in the future: it's not possible to write an extension that dismisses all notifications on Chrome because it is not possible for any extension to get access to a user's browser-wide notifications; the notifications permission in the manifest.json lets you create and clear notifications created by your extension. Indeed, it would be a privacy violation if any extension was allowed to do this!
From https://developer.chrome.com/apps/notifications#method-getAll,
Retrieves all the notifications of this app or extension (emphasis mine.)
You need to add the notifications permission to your manifest
{
"name": "ClearAll",
"permissions": ["notifications"],
.......
}
I'm trying to write a chrome extension that works with YouTube and need to access some of YouTube's cookie information. I cant seem to get my extension to see any cookies. (Even though I can see them under resources in the "Inspect Element" developer portion of Chrome).
I'm pretty sure I've set up permissions correctly in the manifest 2 file because when I take out the "cookies" permission just to test it I get an error saying "Cannot call method 'getAll'". My current problem is just that no cookies are returned by the callback function.
{
"manifest_version": 2,
"name": "YouTube Viewer",
"description": "This extension is for YouTube videos.",
"version": "1.7",
"icons": {
"128": "ytblack.png"
},
"permissions": [
"cookies",
"https://www.youtube.com/",
"http://www.youtube.com/",
"tabs",
"storage"
],
"background": {
"scripts": ["bootstrap.js"],
"persistent": false
},
"page_action": {
"default_title": "YT View",
"default_icon": "ytblack.png",
"default_popup": "popup.html"
}
}
My manifest calls the bootstrap.js. Inside bootstrap.js there is a call to another file ytview.js but I'm not concerned with that. The code in that is working fine. But inside bootstrap.js my cookies.length is returning as 0 when I look at my "background page" console. The log for "Callback for cookies came in fine." fires correctly. But then it says "cookies.length=0". Like I said, I know the cookies exist because I can see them in the resources.
chrome.tabs.onUpdated.addListener(function(id, info, tab){
// decide if we're ready to inject content script
if (tab.status !== "complete"){
console.log("not yet");
return;
}
if (tab.url.toLowerCase().indexOf("youtube.com/watch") === -1){
console.log("you are not on a YouTube video");
return;
}
chrome.cookies.getAll({domain: "www.youtube.com"}, function(cookies) {
console.log('Callback for cookies came in fine.');
console.log('cookies.length=' + cookies.length);
for(var i=0; i<cookies.length;i++) {
console.log('cookie=' + cookies[i].name);
}
});
chrome.tabs.executeScript(null, {"file": "ytview.js"});
});
Any ideas why no cookies are being returned? Maybe something with "domain" in the .getAll statement? I've tried lots of combinations like www.youtube.com, youtube.com, https://www.youtube.com with no luck.
for future users:
youtube.com use ".youtube.com" as cookie domain to allow the site to share cookies across all youtube subdomains so in your example you should use domain name without 'www' subdomain for example:
chrome.cookies.getAll({domain: "youtube.com"}, function(cookies) {
//...
});
you can clearly see cookies domain using default chrome developer tools
I figured it out. In my manifest I was asking for permission on www.youtube.com but the cookies I was trying to read were on simply youtube.com without the www. Adding the plain youtube.com to the permissions in manifest fixed it.