Get chrome extension activeTab permission from javascript with out a real click - google-chrome-extension

write an extension get the mediastream from current tab by using chrome.tabCapture.capture
In content-script.js, i send a message to background.js
$("video").bind('play',function(event){
port.postMessage("get-stream");
});
In background.js handle the message
function portOnMessageHanlder(message) {
chrome.tabCapture.capture(config,function(stream){...});
}
but got an error
Unchecked runtime.lastError while running tabCapture.capture: Extension has not been invoked for the current page (see activeTab permission)
In manifest file grants the access permssion as follows:
"permissions": [
"tabs",
"activeTab",
"tabCapture",
]
also check the chrome extension document , it says need to get active tab by browserAction,so i add setIcon when handler the message from content-script.js
function portOnMessageHanlder(message) {
if(message != 'get-stream'){
if(message == "set-icon"){
chrome.browserAction.setIcon({
path: 'recordRTC-progress-1.png'
});
}
return;
}
chrome.tabCapture.capture(config,function(stream){
if(!stream){
return port.postMessage('PermissionDeniedError');
}
port.postMessage({stream:stream});
});
return;
}
but still got the permission deny error.
any advice ? thanks

Related

Can a webpage that is iFramed into a Chrome Extension page message communicate with the background script?

Problem: I'm trying to have my webapp communicate with the background script of my chrome extension. However, when I invoke chrome.runtime.sendMessage() from my webapp, in order to send a message to the background.js script in my extension, the response callback never gets invoked. It also appears that background.js isn't receiving the message. Is what I'm trying to do possible? If so, given the information below, can anyone help me?
Background
My browser extension has a Newtab page, that I've configured to load my webapp. It does so by loading the webapp in an iframe:
<html>
<body style="margin:0px;padding:0px;overflow:hidden;">
<iframe src="https://www.example.com" frameBorder="0" style={{height:"100vh", width:"100vw", overflow: "hidden"}} height="100%" width="100%"/>
</body>
</html>
I have set the content-security-policy in manifest.json to allow this to happen:
"content_security_policy": {
"extension_pages": "object-src 'none'; child-src https://www.example.com https://example.com; frame-src https://www.example.com https://example.com; script-src 'self'"
}
I have enabled connectivity between my extension and my webapp using the externally_connectable manifest.json key:
"externally_connectable": {
"matches": [
"http://localhost:3000/*",
"https://*.example.com/*",
"https://example.com/*"
]
}
In my webapp (example.com), I have a script that tries to send a message to the background.js service worker. This script executes without any errors reported in the console. Note: this script is running on a webpage that is inside an iFrame in a page bundled with the extension.
function sendMessageToExtension() {
console.log("I got called");
if (chrome && chrome.runtime) {
console.log("Sending message to extension"); // this code is executed
chrome.runtime.sendMessage(
"extension_id",
{ type: "example.message.type"},
{includeTlsChannelId : true},
function(rsp) {
if(arguments.length === 0) {
console.log(chrome.runtime.lastError);
}
console.log(rsp.message)
} // this call back never gets invoked.
);
} else {
// TODO: need to detect this in production.
console.log("no chrome.runtime");
}
}
My background code to handle the message looks like this:
chrome.runtime.onMessageExternal.addListener(
(request, sender, sendResponse) => {
console.log("onMessageExternal invoked") // never gets called
if (request.type === "example.message.type") {
sendResponse({message: "message received by background worker."});
}
}
)
Other Notes: This doesn't appear to work even when I load the webpage by navigating to it in the URL bar, so I'm not entirely sure what's going on.
The answer to my question is yes you can! And as it turns out, the code I posted is exactly how you would do it.

How to make chrome extension 'optional permissions' dialog pop up locally?

I'm trying to get this
optional permission dialog to pop up locally while testing
I've been following this official tutorial:
https://developer.chrome.com/docs/extensions/reference/permissions/
In my case, the optional permission dialog should ideally activate when the button of class '.cbtn' is clicked on my website.
Here is chrome.permission.request part of my background.js file
document.addEventListener("DOMContentLoaded", function(event) {
document.querySelector('.cbtn').addEventListener('click', function(event) {
console.log('now activating prompt!!');
chrome.permissions.request({
permissions: ["bookmarks"]
}, function(granted){
// The callback argument will be true if the user granted the permissions.
if (granted) {
// doSomething();
console.log('Access granted');
} else {
// doSomethingElse();
console.log('Access denied');
}
});
});
});
Note: My manifest.json doesn't contain permission for bookmarks.
In the chrome://extensions/?errors for my unpacked extension, i see an error message-
"Uncaught TypeError: Cannot read property 'addEventListener' of null"
I don't know if that is because it's trying to find .cbtn on the chrome://extensions/ page itself instead of on my particular website where a button with class .cbtn actually exists,
Will appreciate any help, pointers on this

chrome.tabs.onupdated.addlistener doesn't work on cached pages

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (tab.url.indexOf('http') == '0' && changeInfo.status == 'complete') {
alert(JSON.stringify(changeInfo));
}
});
i have such background.js it nearly works always %99 but not %100
whenever i restart my browser and enter an already accessed web page when browser loads all contents from cache it doesn't fire this chrome.tabs event
but the interesting part is when i click same website from dial speed it doesn't load from cache and calls the "tabs." action
According to the docs https://developer.chrome.com/extensions/webNavigation
Not all navigating tabs correspond to actual tabs in Chrome's UI,
e.g., a tab that is being pre-rendered. Such tabs are not accessible
via the tabs API nor can you request information about them via
webNavigation.getFrame or webNavigation.getAllFrames. Once such a tab
is swapped in, an onTabReplaced event is fired and they become
accessible via these APIs.
and
If a navigation was triggered via Chrome Instant or Instant Pages, a
completely loaded page is swapped into the current tab. In that case,
an onTabReplaced event is fired.
Try using the chrome.webNavigation.onTabReplaced event to catch this:
chrome.webNavigation.onTabReplaced.addListener(function (details) {
chrome.tabs.get(details.tabId, function(tab) {
console.log(tab.url);
});
});
Note: You'll need the "webNavigation" permission in the chrome extension manifest:
{
"name": "My extension",
...
"permissions": [
"webNavigation"
],
...
}
I tested this with 25 open tabs using:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
console.log("update: "+JSON.stringify(changeInfo));
});
On restarting my browser I received 25 "loading" events, but only 23 "completes".
On restarting my browser a second time I received 25 "loading" events, but only 22 "completes".
I don't think changeInfo.status == 'complete' will always follow a pageload, especially after restarting.
consider using chrome.tabs.query() right after your extension loads instead.
chrome.tabs.query({}, function(tabs) {
for(var i=0;i<tabs.length;i++){
if (tabs[i].url.indexOf('http') == '0') {
dostuff();
}
}
});

Message Passing Example From Chrome Extensions

I'm using the example from the Google tutorial and finding it difficult to pass a simple message to the content script from the popup.
Can you provide some suggestions on how to pass a simple message and view it either in the console log or alert?
manifest.json
{
"manifest_version": 2,
"name": "msg-test",
"description": "message test",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [{
"matches": ["http://*/*","http://www.site.com/*"],
"js": ["content.js"],
"run_at": "document_end"
}],
"permissions": [
"tabs",
"http://*/*"
]
}
background.js
chrome.runtime.onConnect.addListener(function(port){
port.postMessage({greeting:"hello"});
});
content.js
var port = chrome.runtime.connect({name:"content"});
port.onMessage.addListener(function(message,sender){
if(message.greeting === "hello"){
alert(message.greeting);
}
});
popup.js
window.onload = function() {
document.getElementById('btn2').onclick = function() {
alert("button 2 was clicked");
};
document.getElementById('btn1').onclick = function() {
alert("button 1 was clicked");
};
}
*Note: In this example the content script will fire when the page matches manifest.json and the alert box will show.
First, I wouldn't message pass between your popup and your content script. I would message pass between your Background page and your content scripts. Your popup page should only be used to show some ui to interact with your app.
With that being said, I will show you the way to pass messages between your background and your content script.
In your content script:
//This line opens up a long-lived connection to your background page.
var port = chrome.runtime.connect({name:"mycontentscript"});
port.onMessage.addListener(function(message,sender){
if(message.greeting === "hello"){
alert(message.greeting);
}
});
In your background page(possibly your popup? but I don't recommend it)
chrome.runtime.onConnect.addListener(function(port){
port.postMessage({greeting:"hello"});
});
Here is the sequence of events that will take place:
Your application will inject your content script into the page
Your content script will open up a port to communicate with the background script.
Your background script will be notified that a port was open, allowing it to send a message to it, or attach a message listener to it.
In the background script or the content script, you can listen for messages by using port.onMessage.addListener(). provided that port is in scope. Using ports is much easier to grasp and allows for simple, two way communication!
Edit:
If you would like to pass messages to your background page from your popup script, use the exact same method:
var port = chrome.runtime.connect({name: "popup-port"});
port.postMessage({status:"poppedup"});
Edit 2:
To navigate your user to a new page, do this:
function navigateToPage(url){
chrome.tabs.query({url: url}, function(tabs) {
var tab = tabs[0];
return tab ? chrome.tabs.update(tab.id, {active:true}) : chrome.tabs.create({url: url});
});
}
});
What this function does is, it checks to see if there is a tab with the url you want to go to, if there is, switch to it, else, create a tab with that url and navigate to it.

message passing happens twice if "run_at" : "document_start" is used in chrome extension

In my extension, I am passing a message from background.js to contentScript.js.
The issue is that when I use
"run_at" : "document_start"
in my manifest.json, the message from background.js to contentScript.js is called twice and sometimes even more than that.
Message passing more than once is a bit expensive in my case as I'm sending a call to server and the processing the same values at the server multiple times is expensive.
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
chrome.tabs.sendMessage(tab.id, {type: "get-url", url: tab.url});
});
contentScript.js
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
switch(message.type) {
case "get-url" : someFunction(message.url);
break;
// other cases
}
});
Is there a way to solve this?
chrome.tabs.onUpdated is called multiple times in the tab-update cycle (e.g. when the tab starts loading the new page, when the tab completes loading the new page, when the favicon is fetched etc).
The best option is to checj for when the tab has completed loading:
chrome.tabs.onUpdated.addListener(function (tabId, info, tab) {
if (info.status === 'complete') {
/* Now it is safe to send the message */
chrome.tabs.sendMessage(tabId, {
type: 'get-url',
url: tab.url
});
}
});
BTW, when injecting programmatically (not in manifest.json), the property's name is runAt, not run_at (docs).

Resources