chrome.tabs.executeScript bug on F5? - google-chrome-extension

Background page:
chrome.tabs.create({ url: 'http://google.com' }, tab => {
chrome.tabs.executeScript({ code: '2+2;' }, (r) => {
console.log(`url: ${tab.url}, result: ${r[0]}`);
});
});
I open background page to see output:
url: http://google.com/, result: 4
Looks good, but now I press F5 or Ctrl+F5:
Unchecked runtime.lastError while running tabs.executeScript: Cannot access contents of url "chrome-devtools://devtools/bundled/inspector.html?&remoteBase=https://chrom…om/serve_file/#e8926f681fbb840b4f389e7e692343d4505722ce/&dockSide=undocked". Extension manifest must request permission to access this host.
at Object.callback (chrome-extension://laaoiaaacchfpefjhklpmnfjbeamjfli/background.js:2:15)
In 'manifest.json' I have <all_urls> permission.

When the first parameter, tabId, of chrome.tabs.executeScript is omitted the code is injected into the active tab of the active window. In your case the active window is the devtools debugger of the background page and it doesn't allow injection of code.
Specify tabId explicitly: chrome.tabs.executeScript(tab.id, { code: .......

Related

"Scroll to Text" not working in Extension

I've built a Chrome Extension (pop-up) and one of the primary functions is opening different web pages when the user clicks on a link. Sometimes I want to focus on specific text on the new page so I'm trying to use the "scroll to text fragment" feature through my extension.
Unfortunately, when the page loads, this feature (scroll to text) fails. I have tested the exact same link manually and it works fine, but when I inject this link into the browser through my extension, nothing happens except the page loading as normal.
Here are a few more details that might help:
The problem I'm having is using Chrome.tabs.update() which is triggered by a user clicking a link in my popup
We are using manifest v2 not v3
The exact command from the popup javascript is (not tab id as it defaults to current tab):
chrome.tabs.update({ url: "http://example.com/#:~:text=example", })
In the manifest, we do not have the "tabs" permission.
Is there a special permission needed to use this feature in my extension? Is there something I need to do in my extension code to make this work as expected? I'm at a loss for next steps.
This is the exact feature I'm referring to: https://chromestatus.com/feature/4733392803332096
And here's an example of the feature in action:
https://chromestatus.com/feature/4733392803332096#:~:text=Motivation-,Navigating%20to%20a%20URL,-today%20will%20load
Any help would be greatly appreciated. Thank you.
There's no special permission so apparently it's a bug in Chrome: crbug.com/1241508
A simple workaround is to use chrome.tabs.create and close the original tab, but it flickers in the tab strip and loses the tab's back/forward history, sessionStorage, and so on.
function navigate(url) {
chrome.tabs.query({active: true, currentWindow: true}, ([tab]) => {
chrome.tabs.remove(tab.id);
chrome.tabs.create({ url, index: tab.index });
});
}
Another workaround is to set the hash part of the URL in the content script, but it requires host permissions for the navigated site in manifest.json like *://example.com/
async function navigate(url) {
if (await setUrlInContentScript(url)) {
return true;
}
const [base, hash] = url.split('#');
await onTabReceivedUrl(await new Promise(resolve => {
chrome.tabs.update({ url: base }, resolve);
}));
return setUrlInContentScript('#' + hash, 'hash');
function setUrlInContentScript(url, part = 'href') {
return new Promise(resolve => {
chrome.tabs.executeScript({
code: `location.${part}=${JSON.stringify(url)}`,
runAt: 'document_start',
}, () => resolve(!chrome.runtime.lastError));
});
}
function onTabReceivedUrl(tab) {
return new Promise(resolve => {
chrome.tabs.onUpdated.addListener(function onUpdated(tabId, info) {
if (tabId === tab.id && info.url) {
chrome.tabs.onUpdated.removeListener(onUpdated);
resolve();
}
});
});
}
}
In my case I discovered, that one of the characters ~ was encoded. You need the real characters to get Scroll to Text working.

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 extension message passing between extension-inner page and background script

I use a extension inner page(chrome-extension://) to request permission, and send result to background.
in extension inner page:
btn.addEventListener('click', function(event) {
event.preventDefault();
chrome.permissions.request({
permissions: permissions,
origins: origin
}, function(granted) {
chrome.runtime.sendMessage({route: '/permissionRequest', data: {command: 'Response', result: granted}}, function(){});
});
}, false);
It looks well.But when I click the button, it open a new tab, url like chrome-extension://.../authorizehtml?undefined. The message send.
I don't know why it open a new tab like that.
And the, I found, if I change the key name 'data' to other name, it never open new tab.The official document don't talk about it.
I hava no idea about it.

Safari does not reopen page after Facebook authentication on iPhone

I'm working on a responsive website that require the user to authenticate with Facebook.
I've set up the Facebook JS SDK, and the login and login-success callback. The setup I have works great on desktop, but on iPhone (seems to work on iPad!) I'm having an issue I am yet to resolve.
When tapping the Login button, the user is brought to a new tab that asks the user to log in. After the user has entered his/her credentials, the tab is closed, but Safari does not reopen my page. Instead, Safari sits in the "tab selection" screen with my page highlighted. The user has to explicitly re-open my page by tapping the tab. When tapping the tab, it doesn't seem to fire the authResponseChange consistently.
Please note that if I make sure that Safari on iPhone has no tabs open except my page, then I am automatically directed back to it (as expected by the Safari app's design) and the site functions correctly.
<div id="fb-root"></div>
<script>
$(document).ready(function() {
$.ajaxSetup({ cache: true });
$.getScript('//connect.facebook.net/en_US/all.js', function() {
FB.init({
appId : 'xxx',
xfbml : true,
status : true,
cookie : true
});
});
});
$("#login_button").bind("vclick", function() {
// Require explicit login
FB.Event.subscribe("auth.authResponseChange", function(response) {
if (response.status === "connected") {
// Perform API calls and display more of the page ...
// $.get("https://graph.facebook.com/me/friends?access_token=")
// FB.api("/me/friends", function(data) {});
}
});
FB.login(function(response) {}, {scope: 'email,friends_birthday,friends_hometown'});
});
</script>

Message isn't passed between background.html and popup.html

I'm trying to pass data that is saved in sessionStorage from background.html to popup.html
background.html:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
data = sessionStorage.getItem(request.tabId);
alert(data);
sendResponse({ data: data });
});
and in popup.html:
chrome.tabs.getSelected(null, function(tab) {
chrome.extension.sendRequest({ tabId: tab.id }, function(response) {
alert(response.data);
});
});
The popup is opened by a pageAction button, when I click the button I get an alert box with "null" on the popup and then an alert box with the data that I stored in sessionStorage on the background!
Any ideas how to fix this?
You don't need to use message/request APIs. I think this response may help you.
You also don't need sessionStorage, just store your data in a global variable of the background page. It will persist until the browser is closed or until the extension is restarted.
So, here is how I would rewrite your code:
background.html:
var data = {}; // Object storing data indexed by tab id
and in popup.html:
chrome.tabs.getSelected(null, function(tab) {
alert(chrome.extension.getBackgroundPage().data[tab.id]);
});
Note that chrome.tabs.getSelected is deprecated since Chrome 16, so popup code should be:
chrome.windows.getCurrent(function(win) {
chrome.tabs.query({'windowId': win.id, 'active': true}, function(tabArray) {
alert(chrome.extension.getBackgroundPage().data[tabArray[0].id]);
});
});
Well, I've done something dumb.
I inspected the background page by opening chrome-extension://[extension-id]/background.html in a tab instead of clicking on "inspect active views: background.html" in the extensions management page. This caused the tab to catch the request and call sendResponse, but the popup expected the REAL background page to call sendResponse (and if I understand Google's documentation regarding message passing, the fact that sendResponse was called twice is root of the problem, because the first call clears the request object)

Resources