A bit of a novice attempting to create my first Chrome extension here.
I've verified my JQuery and html code to be working by running it via opening it in a browser in a normal .html file that calls the .JS file.
However, the Chrome extension with the same code fails to run, seemingly due to CSP issues. (I am calling the ajax library in my html via https)
Refused to load the script
'http://www.reddit.com/r/abandonedporn/.json?jsonp=jQuery111307901595502626151_1438751974832&_=1438751974833'
because it violates the following Content Security Policy directive:
"script-src'self' https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js". send # library.js:5
I've modified my manifest.json file with every last thing that I thought necessary, including:
{"content_security_policy": "script-src 'self' https://ajax.googleapis.com/*; object-src 'self'"},
"permissions": [
"http://www.reddit.com/r/abandonedporn/.json?jsonp=?",
"http://www.reddit.com/*", "https://www.reddit.com/*",
"http://www.reddit.com/r/abandonedporn/",
"https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js/",
"http://www.reddit.com/r/abandonedporn/.json?jsonp=jQuery111309090442832093686_1438671168851&_=1438671168852",
"http://*/*", "https://*/*",
"http://reddit.com/json*",
"http://www.reddit.com/r/abandonedporn/*"],
and
"content_scripts": [
{
"matches": [
"https://www.google.com/*",
"http://www.reddit.com/abandonedporn/*"
],
"js": [
"src/inject/inject.js",
"src/content.js",
"src/override/get_pics.js",
"src/override/get_pics2.js",
"src/override/library.js"
]
}
]
}
Lastly, my actual Jquery script:
(Note that changing ".getJSON" to ".getScript" did not help.)
document.addEventListener('DOMContentLoaded', function () {
$.getJSON("http://www.reddit.com/r/abandonedporn/.json?jsonp=?", function(data) {
$.each(data.data.children, function(i,item){
$("<img/>").attr("src", item.data.url).appendTo("#images");
});
});
});
You can't load external (CDN) script files in chrome extension as per new CSP from google. You need to package all your resources, download jquery and access from your package. "jquery.min.js" instead CDN-URL/jquery.min.js. Here is in detail
Related
I'm having issues utilizing the materialize library within my chrome extension to display a custom modal when a button is clicked. I've already written code (in my content script) to inject a button to the existing web page. In my dialog.html, I have the HTML for my modal (using this template from materialize-css). Now, I'm trying to call $('.modal').modal('open'); inside a function that is called when the button is clicked (I've verified that the onclick is working fine, since console.log() works inside of this function.
However, when I try to run $('.modal').modal('open');, I get this error: Uncaught TypeError: $(...).modal is not a function. (I've also tried running $('.modal').modal(); and the other implementations I found on stackoverflow, but to no avail.
My manifest.json looks like:
{
"manifest_version": 2,
"name": "MyChromeExtension",
"version": "0.1",
"content_scripts": [
{
"matches": ["*://www.messenger.com/*"],
"css": ["/thirdParty/materialize.css"],
"js": ["/thirdParty/jquery.min.js","/thirdParty/materialize.js", "content-final.js"]
}
],
"web_accessible_resources": ["/thirdParty/bootstrap.min.css", "/thirdParty/jquery.min.js", "/thirdParty/bootstrap.min.js", "dialog.html", "/thirdParty/materialize.css", "/thirdParty/materialize.js"],
"permissions": ["tabs", "<all_urls>"],
"background": {
"scripts":["background.js"]
},
"content_security_policy": "script-src 'self' 'unsafe-eval' https://cdn.jsdelivr.net; object-src 'self'"
}
I've saved local copies of my jquery, bootstrap, and materialize files inside my folder thirdParty, but for some reason my code doesn't work. I've also tried installing all of these frameworks via npm and using browserify to combine them into my content-final.js, but this doesn't work either.
Does anyone know why this might be happening?
I'm developing Chrome Extension and I need to load a javascript file to content scripts, but that file is being served via webpack-dev-server. So it's approachable only on localhost.
I tried to change my manifest.json:
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"http://localhost:3000/scripts/content_bundle.js"
],
"run_at": "document_end",
"all_frames": false
}
But then I got an error in Chrome Extensions window:
Only local files can be specified in "content_scripts" section.
Solution:
add "permissions": ["http://localhost:3000/scripts/*", "tabs"] to manifest.json
download the script using XMLHttpRequest (there are many examples) in your background script (or better an event page script) when needed
save it in chrome.storage.local or localStorage (so you can load it on every extension start from the storage without redownloading)
inject the script:
add a tabs.onUpdated listener and inject the script using tabs.executeScript
alternatively use declarativeContent API with RequestContentScript action (despite the warning on the doc page it should be actually supported in the Stable channel but of course do some tests first).
I'm trying to create a chrome extension that interacts with youtube. It loads the content script, which is then supposed to inject the experiment.js script from web_accessible_resources. None of my code from experiment.js works.
I've followed this as reference: Insert code into the page context using a content script
manifest.json
{
"version": "1.0",
"manifest_version": 2,
"permissions": ["tabs", "https://*/*"],
"content_scripts": [{
"js": ["contentscript.js"],
"matches": [ "https://*.youtube.com/*", "http://*.youtube.com/*"]
}],
"web_accessible_resources": ["experiment.js"],
"browser_action": {
"default_icon": "icon.png"
}
}
contentscript.js
var s = document.createElement('script');
s.src = chrome.extension.getURL('experiment.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
experiment.js
alert('loaded');
console.log('loaded');
EDIT: I just used another solution by including the code from experiment.js into contentscript.js in an array and joining each line. The process is referred to as "Method 2" in the reference post I added earlier.
Basically the problem was caused by content scripts limitations. For security reasons (I guess) content scripts can't use variables or functions defined by web pages or by other content scripts. It's called sandboxing.
When you add new script to the page by creating new <script> element you add this script to the page's sandbox. Therefore content script couldn't see the one added to the page, even if it is your extension's code.
Simplest solution is you quick fix. You just need to add the script to the manifest file or using programmatic injection.
Besides their limitations, content scripts can use shared DOM to communicate with the page. In this case you could add script to the page using <script> tag and communicate with content script using window.postMessage.
So I've been trying to send data from a web page to the Chrome Application (not Chrome Extension). Reading stuff around, according to me, this primarily would require the use of url_handlers for invoking Chrome App from a web page, content scripts to inject JS into the web page and/or Messaging for communication between Chrome Application and the web page.
Also, installed App from it's .crx, else loading unpacked directory leads to this error:
"content_scripts is only allowed for extensions and legacy packaged apps, but this is a packaged app."
Now, I tried injecting JS in the required site. However, on inspecting using Chrome Dev Tools, there's no such entry in the Sources->Content scripts section for that site. It simply didn't inject itself when using a Chrome App. It works perfectly with extensions but I want to use Chrome App for other functionalities.
As an alternative, I looked for Messaging examples where its usage is mentioned as:
"... your app or extension can receive and respond to messages from regular web pages."
But, somehow I couldn't get it working.
Any headers on either of the approaches? Other Suggestions?
manifest.json:
{
"name": "App",
"version": "1.0",
"manifest_version": 2,
"minimum_chrome_version": "31",
"app": {
"background": {
"scripts": ["background.js"]
}
},
"permissions": [
{"fileSystem": ["write", "retainEntries", "directory"]},
"storage",
"http://example.com/*"
],
"externally_connectable": {
"matches": ["http://example.com/*"]
},
"content_scripts": [{
"matches": ["http://example.com/*"],
"js": ["content.js"]
}]
}
Indeed, you can't have content scripts in an app.
However, using externally_connectable is valid.
You have already declared that you want to be externally connectable from example.com. (Note: be careful when defining match patterns, for instance this one does not cover www.example.com)
In example.com's own scripts, you can then include the following:
chrome.runtime.sendMessage("idOfYourAppHere", message, function(response) {
/* ... */
});
And in the app (probably its background script) you can catch that with
chrome.runtime.onMessageExternal.addListener(function(message, sender, sendResponse) {
/* ... */
sendResponse(response);
});
This does require you to know the ID in advance. You can pin it by packing your extension and extracting the "key" field from the manifest. See this question for some more details.
I've wrote a Chrome Extension. My background.js file is quite large, so I want to split it to smaller parts and load specified methods when required (some kind of lazy-loading).
I've done this with Firefox:
// ( call for load specified lib )
var libPath = redExt.basePath + 'content/redExt/lib/' + redExt.browser + '/' + libName + '.js';
var service = Components.classes["#mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
service.loadSubScript("chrome://" + libPath);
// ( executing loaded file )
Is there any possiblity to do it similar way in Webkit-based browsers? I've found solutions for how to inject multiple JS files into matching pages (using manifest.json) but cannot find way to include JS file just for extension.
UPDATE : This solution works only if you are using manifest V2.
You can also do this the extremely easy way that is described here:
https://developer.chrome.com/extensions/background_pages#manifest
{
"name": "My extension",
...
"background": {
"scripts": [
"lib/fileone.js",
"lib/filetwo.js",
"background.js"
]
},
...
}
You won't be doing lazy loading, but it does allow you to break your code up into multiple files and specify the order in which they are loaded onto the background page.
If you want to load a javascript file in the context of your background page and want to avoid using eval, you can just add a script tag to your background page's DOM. For instance, this works if your files are present in the lib folder of your extension:
function loadScript(scriptName, callback) {
var scriptEl = document.createElement('script');
scriptEl.src = chrome.extension.getURL('lib/' + scriptName + '.js');
scriptEl.addEventListener('load', callback, false);
document.head.appendChild(scriptEl);
}
You could attempt to use web workers, perhaps. In your background.js, include:
var worker = new Worker('new-script.js');
Web workers can spawn new workers, and even have an importScript("new-script.js") method.
Web workers can tend to be very limited, however. Check here for a great article on Web workers.
I don't know if they would work, however. The other option is using XMLHTTPRequest (AJAX) to dynamically retrieve the script, and eval it. Over a non-HTTPS connection however, this is probably blocked due to man-in-the-middle attacks.
Alternatively, you can force Chrome to eval script from a non-encrypted connection (BUT DON'T DO IT) by adding this to manifest.json:
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"permissions": ["http://badpractic.es/insecure.js"]
See Load remote webpage in background page: Chrome Extension for a more in-depth discussion of the AJAX method.
So your options seem to be limited.
This of course loads them all at once:
{
"name": "My extension",
...
"background": {
"scripts": ["background.js","background2.js","background3.js"] //and so on
},
...
}
Found possible solution. Theres a simple implementation of RequireJS main method require which uses JavaScript callback trace to find event for loading main extension file and binds executes it with extension context.
https://github.com/salsita/browser-require/blob/master/require.js
It seems to work, but this solution has a few cons:
bug reports are reported in "line 1, column 1" because this solution injects code directly to func.call - debugging is very hard
Loaded JS files does not appear in console / chromebug
If current tab uses HTTPS Chrome will disallow evaling scripts, especially this from local context (file:///), so it sometimes just dont work as expected
What I've done isn't lazy loading but I load some files before the others when my chrome extension icon is clicked. In my case, I wanted my util files before the others that utilize them:
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.executeScript(null, {file: "src/utils/utilFunction1.js"});
chrome.tabs.executeScript(null, {file: "src/utils/utilFunction2.js"});
chrome.tabs.executeScript(null, {file: "src/main.js"});
chrome.tabs.executeScript(null, {file: "src/otherFeature.js"});
});
although an old post, i thought i try and share my experiences here, especially as manifest v3 has changed a lot, importScripts
importScripts('foo.js');