Is Chrome blocking access to the webstore url?
I would like to make an extension that displays a like button beside the +1 button, but it looks like that content scripts are not working on https://chrome.google.com/webstore/*
Is that true?
TL;DR The webstore cannot be scripted by extensions, and the flag that previously allowed you to do that (--allow-scripting-gallery) has been removed in Chrome 35.
Chrome extensions cannot execute Content scripts / insert CSS the Chrome Web Store. This is explicitly defined in the source code, at function IsScriptableURL (click on the previous link to see the full logic).
// The gallery is special-cased as a restricted URL for scripting to prevent
// access to special JS bindings we expose to the gallery (and avoid things
// like extensions removing the "report abuse" link).
// TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
// against the store app extent?
GURL store_url(extension_urls::GetWebstoreLaunchURL());
if (url.host() == store_url.host()) {
if (error)
*error = manifest_errors::kCannotScriptGallery;
return false;
}
manifest_errors::kCannotScriptGallery is defined here:
const char kCannotScriptGallery[] =
"The extensions gallery cannot be scripted.";
The error can be viewed in the background page's console when you use chrome.tabs.executeScript to inject a script in a Web Store tab. For instance, open https://chrome.google.com/webstore/, then execute the following script in the background page of an extension (via the console, for live debugging):
chrome.tabs.query({url:'https://chrome.google.com/webstore/*'}, function(result) {
if (result.length) chrome.tabs.executeScript(result[0].id, {code:'alert(0)'});
});
Related
I have a Chrome Manifest V3 web extension that needs to inject javascript into a webpage on page load of every page (not fussy as to exactly when the javascript is run).
This is so that javascript on the webpage can optionally call the function defined by the web extension.
According to the docs at https://developer.chrome.com/docs/extensions/reference/scripting/, the chrome.scripting.executeScript will do what I need:
You can use the chrome.scripting API to inject JavaScript and CSS into websites.
The chrome.scripting.executeScript function takes a tabId as a mandatory parameter, but nothing in the docs indicates where to get the tabId from. The docs make reference to an unspecified function getTabId(), but otherwise say nothing.
In addition, the docs do not say where the chrome.scripting.executeScript function is to be run. In the content script? In theory that won't work as the tab ID is not accessible. In the background service worker? What happens if the service worker is not running when the page is loaded?
Note that the following questions are not related to this question:
How would I inject code from my Chrome extension into a webpage? (closed, no reference to Manifest v3)
Use a content script to access the page context variables and functions (opposite question)
How to access the webpage DOM rather than the extension page DOM? (nothing to do with the DOM)
To get the tabId --
In Manifest V3, you pass it as a value.
chrome.action.onClicked.addListener((tab) => {
if(!tab.url.includes("chrome://")) {
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: reddenPage
});
}
});
Check out Google's Chrome Extension example "Page Redder" for the full code
I just updated my Chrome browser (Version 50.0.2661.75) and have found that the chrome://downloads page has changed such that my automated tests can no longer interact with it. Previously, I had been using Watir-Webdriver to clear the downloads page, delete files from my machine, etc, without too much difficulty.
It looks like Google is using Polymer on this page, and
there are new (to me) elements like paper-button that Watir-Webdriver doesn't recognize
even browser.img(:id, 'file-icon').present? returns false when I
can clearly see that the image is on the page.
Is automating a page made with Polymer (specifically the chrome://downloads page) a lost cause until changes are made to Watir-Webdriver, or is there a solution to this problem?
Given that the download items are accessible in Javascript and that Watir allows Javascript execution (as #titusfortner pointed out), it's possible to automate the new Downloads page with Watir.
Note the shadow root elements (aka "local DOM" in Polymer) can be queried with $$.
Here's an example Javascript that logs the icon presence and filename of each download item and removes the items from the list. Copy and paste the snippet into Chrome's console to test (verified in Chrome 49.0.2623.112 on OS X El Capitan).
(function() {
var items = document
.querySelector('downloads-manager')
.$$('iron-list')
.querySelectorAll('downloads-item');
Array.from(items).forEach(item => {
let hasIcon = typeof item.$$('#file-icon') !== 'undefined';
console.log('hasIcon', hasIcon);
let filename = item.$$('#file-link').textContent;
console.log('filename', filename);
item.$.remove.click();
});
})();
UPDATE: I verified the Javascript with Watir-Webdriver in OS X (with ChromeDriver 2.21). It works the same as in the console for me (i.e., I see the console logs, and the download items are removed). Here are the steps to reproduce:
Run the following commands in a new irb shell (copy+paste):
require 'watir-webdriver'
b = Watir::Browser.new :chrome
In the newly opened Chrome window, download several files to create some download items, and then open the Downloads tab.
Run the following commands in the irb shell (copy+paste):
script = "(function() {
var items = document
.querySelector('downloads-manager')
.$$('iron-list')
.querySelectorAll('downloads-item');
Array.from(items).forEach(item => {
let hasIcon = typeof item.$$('#file-icon') !== 'undefined';
console.log('hasIcon', hasIcon);
let filename = item.$$('#file-link').textContent;
console.log('filename', filename);
item.$.remove.click();
});
})();"
b.execute_script(script)
Observe the Downloads tab no longer contains download items.
Open the Chrome console from the Downloads tab.
Observe the console shows several lines of hasIcon true and the filenames of the downloaded items.
Looks like Google put the elements inside the Shadow-Dom, which isn't supported by Selenium/Watir/WebDriver spec (yet). There might a way to obtain the element via javascript (browser.execute_script(<...>)), but it is experimental at best still.
Attempting to automated a Polymer page, I found I was able to access the web elements by asking Polymer to use the shady dom by adding ?dom=shady in the URL. Like in the example on this page https://www.polymer-project.org/1.0/docs/devguide/settings:
http://example.com/test-app/index.html?dom=shady
Adding the dom parameter to request Polymer to use the shady dom may be worth a try.
I've recently been contributing to the Enhanced Steam extension and I've found that a link fetched with chrome.extension.getURL simply opens about:blank and not the link described.
I do not believe it's actually a problem with the extension, but rather a problem in chrome. The link it supplies is valid (chrome-extension://pimjhgjngccknempdnehdeaihcjbajod/options.html) and navigating directly works correctly.
I tried chrome.tabs.create, but found that I am not allowed to use it due to the script modifying pre-existing content.
Any help or work arounds would be appreciated.
I put all my required files into "web_accessible_resources", it solved my problem. See this in #4 https://bugs.chromium.org/p/chromium/issues/detail?id=310870#c4
It is Chrome's previous problem which is not secure. In build 31.0.1650.57, Chrome fixed this which is to force to put required files in "web_accessible_resources". In Chrome extension, lots of samples don't use "web_accessible_resources", those are the bugs, those samples will have this "chrome-extension:// links open about:blank" problem in build 31.0.1650.57.
Actually my chrome extension MarkView was facing this issue and I had to update its manifest.json to make it work for this Chrome update. By the way, MarkView is tool to read and write Awesome Markdown Files, it provides features including Content Outline, Sortable Tables and code block syntax highlight with line number.
Looks like a bug in Chrome to me. If you don't have too many pages like this to change then could you try using message passing to pass the page you want to open to the background page? Then use either window.open or chrome.tabs.create within the background page. Example code shown below:
//CONTENT SCRIPT
chrome.runtime.sendMessage({greeting: "OpenPage", filename:"somepage.html", querystring:"?aValue="+someVal}, function(response) {});
Then in your Background page
//BACKGROUND PAGE
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "OpenPage"){
open_page(request.filename, request.querystring)
}
});
function open_page(filename, querystring){
var pageUrl = chrome.extension.getURL(filename)+querystring;
chrome.tabs.create({'url': pageUrl }, function(tab) {
// Tab opened.
});
}
Is Chrome blocking access to the webstore url?
I would like to make an extension that displays a like button beside the +1 button, but it looks like that content scripts are not working on https://chrome.google.com/webstore/*
Is that true?
TL;DR The webstore cannot be scripted by extensions, and the flag that previously allowed you to do that (--allow-scripting-gallery) has been removed in Chrome 35.
Chrome extensions cannot execute Content scripts / insert CSS the Chrome Web Store. This is explicitly defined in the source code, at function IsScriptableURL (click on the previous link to see the full logic).
// The gallery is special-cased as a restricted URL for scripting to prevent
// access to special JS bindings we expose to the gallery (and avoid things
// like extensions removing the "report abuse" link).
// TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
// against the store app extent?
GURL store_url(extension_urls::GetWebstoreLaunchURL());
if (url.host() == store_url.host()) {
if (error)
*error = manifest_errors::kCannotScriptGallery;
return false;
}
manifest_errors::kCannotScriptGallery is defined here:
const char kCannotScriptGallery[] =
"The extensions gallery cannot be scripted.";
The error can be viewed in the background page's console when you use chrome.tabs.executeScript to inject a script in a Web Store tab. For instance, open https://chrome.google.com/webstore/, then execute the following script in the background page of an extension (via the console, for live debugging):
chrome.tabs.query({url:'https://chrome.google.com/webstore/*'}, function(result) {
if (result.length) chrome.tabs.executeScript(result[0].id, {code:'alert(0)'});
});
I'd like to make a very simple extensions that slightly alters how the Downloads page looks. Changing the History page might be interesting too, but that's for later.
Is there a way to do that?
I tried making a Content Script extension, with "chrome://downloads" as match in manifest.json. Chrome won't allow that and responds with an error when packaging the extension.
Is there another simple way? It has to be simple, because changes would be simple, because all chrome:// pages are built with HTML, JS and CSS.
edit
After trying with background scripts a little...
I can't get chrome.tabs.executeScript to work! I added in background.html:
chrome.browserAction.onClicked.addListener(function(tab) {
alert(this.document.body.innerHTML);
alert(chrome.tabs.executeScript(null, {
code : "document.body.style.backgroundColor = 'red';"
}));
});
And I added this in manifest.json to add a (invisible) 'browser action button':
,"browser_action": {
/* "popup": "background.html",*/
"name": "Alter page"
}
The onClicked event fires both alerts (first is background.html's body, second is undefined). But the code (a string with document.body.style.backgroundColor = 'red';) doesn't execute! And ofcourse there's no debugging for extensions like this =)
Any tips anyone? I'm trying to get a hold of the tab's window.document (not background.html's window.document!). An injected script (that's what chrome.tabs.executeScript is supposed to do) should do that.
PS
I'm stealing from make_page_red/manifest and make_page_red/background.html
The 'extension' I have so far: http://hotblocks.nl/js/downloads.rar
EDIT
I found out what I want to achieve is possible with just CSS. I don't need to inject javascript. Does that make it easier? Does that make it possible? =)
According to this documentation, chrome:// URLs are an invalid scheme so they won't be matched:
A match pattern is essentially a URL that begins with a permitted scheme (http, https, file, or ftp), and that can contain '*' characters.
I would look into using override pages instead.
As requested, here's my extension that can at least load when chrome://downloads is loaded, although as I said, I don't think you can modify the page even if you know that's the page you're viewing.
manifest.json
{
"name": "Test",
"version": "0.0.1",
"background_page": "background.html",
"permissions": [
"tabs"
]
}
background.html
<script>
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab)
{
if (tab.status == "complete")
{
alert(tab.url);
// should alert 'chrome://downloads' on that page. You can
// check for this url here and then do whatever you want
}
});
</script>
Update: Since Chrome 31 there is an API for extensions that allows access to Chrome's downloads: https://developer.chrome.com/extensions/downloads
There's also an API that allows access to list and manage other installed extensions: https://developer.chrome.com/extensions/management
(Previous Answer)
Unfortunately, there's not currently an API for Chrome extensions to access information about a user's downloads. It's a widely requested feature, though, and there's some discussion among Chrome developers here: http://code.google.com/p/chromium/issues/detail?id=12133
Star the issue if it's a feature that you'd like to see, and you'll receive email updates.
As this page shows, there is no API to override the downloads page... However, there is a way to make a file you have made replace the chrome://downloads/ page whenever it is loaded using javascript in your background page...
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
if(changeInfo.status === "loading"){
if(tab.url === "chrome://downloads/"){
chrome.tabs.update(tab.id, {url: "REPLACEMENT.html"});
}
}
});
Essentially what this does is - As soon as the page chrome://downloads begins loading (using the tabs.onUpdated API), the page is redirected to REPLACEMENT.html (Using tabs.update API)... There is no visible delay in the tab update
as this script is run before the chrome://downloads page begins loading... You can use a similar code in your file by pressing CTRL + U on the downloads page to view and copy its source code