I am making a chrome extension and I would like to make use of a third party API but I am running into some issues and I've been stuck on this problem for a while...
Problem:
I cannot make use of the functions in the API even though the chrome Dev tool says that the API was loaded successfully.
I've tried to load the API at different times to see if that would make a difference but it doesn't seem to.
I've used the API successfully in a basic web page. But I cannot seem to get it working in the content script of the extension.
Here's the code to load the API:
(function() {
var scr = document.createElement('script');
scr.type = 'text/javascript';
scr.src = 'someurl';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(scr, s);
})();
Manifest:
"content_security_policy": "script-src 'self' someurl; object-src 'self'"
I've also done the tutorial that Google offers on how to use Google Analytics within an extension because I thought it would be relevant. But no luck. Any guidance would be appreciated.
You are injecting the API into the context of the webpage when you append a script tag; your content script remains isolated from it.
To circumvent that, one possible solution is to also append some of your code, that would then talk to your extension, either through DOM or through external messages
Related
I have a heavy JavaScript file on the server (> 3MB). I want to load the page fast and show a loading progress bar to the user. Currently, I am using fetch and WritableStream to download the data and to track the download progress as:
let resource = await fetch('heavy_file.js')
resource.clone().body.pipeTo(new WritableStream({
write(t) { on_receive(t.length) }
}))
And then I am using the Function to evaluate it. This has several problems. How can I:
Load the script preferably using fetch (I'm using the same method to load WASM files, I want to track their download progress as well, and the WebAssembly.compileStreaming API requires the usage of fetch).
Track the download progress in a way that would work across modern browsers nowadays.
Be able to use this solution without enabling script-src 'unsafe-eval' in Content-Security-Policy?
PS.
Of course, currently, we need to use script-src 'wasm-eval' in Chrome when loading WASM files until the bug is fixed.
Option 1
If you can calculate the hash of the script you're loading in advance (if it's not something generated dynamically), then a simple option to avoid
enabling script-src 'unsafe-eval' in Content-Security-Policy
would be to add only a hash of that specific script into the CSP header - this will still ensure that you're not executing any untrusted code, while allowing you to load and execute script manually.
MDN has some more examples of implementing such CSP policies here.
As for loading itself, you have two different paths from here:
Option 1.1
Combine the hash with a CSP3 policy unsafe-hashes which will allow you to keep using Function or eval like you currently, while still limiting code only to trusted.
For example, if you have a script like
alert('Hello, world.');
then your CSP header should contain
Content-Security-Policy: script-src 'unsafe-hashes' 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
Unfortunately, CSP level 3, or, at least, this option is supported only in Chromium at the moment of writing.
Option 1.2
Instead of using Function or eval, you can dynamically create a script tag from JavaScript, populate its textContent with your response content and inject it into the DOM:
let resource = await fetch('heavy_file.js')
resource.clone().body.pipeTo(new WritableStream({
write(t) { on_receive(t.length) }
}));
resource.text().then(res => {
let s = document.createElement('script');
s.textContent = res;
document.head.appendChild(s);
});
In this case you only need to add the hash of the script to the CSP and it will work across all browsers:
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
Option 2
If you do want to support dynamically generated scripts, then your only option might be to move your progress-tracking code to a Service Worker, and then use Client.postMessage to communicate progress to a script on the page.
This will work for any content served from your origin, but only once Service Worker is installed - usually on a subsequent page load, and so might not help you if the large script you're loading is part of the page user visits first on your website.
Google Chrome started implementing Blocking the load of cross-origin, parser-blocking scripts inserted via document.write in the main frame on slow networks, which causes the following error:
A Parser-blocking, cross-origin script, http://example.org/script.js, is invoked via document.write. This may be blocked by the browser if the device has poor network connectivity.
However, my web page requires loading a third party script synchronously, using document.write('<script src="..."></script>'). How to circumvent that blockade?
More about that change:
Design document
Longer document
Web Incubator CG issue
Chrome Issue
According to Google Developers article, you can:
Use asynchronous script loading, using <script src="..." async> or element.appendChild(),
Submit the script provider to Google for whitelisting.
#niutech
I was having the similar issue which is caused by Rocket Loader Module by Cloudflare.
Just disable it for the website and it will sort out all your related issues.
Don't use document.write, here is workaround:
var script = document.createElement('script');
script.src = "....";
document.head.appendChild(script);
i am new here and i have a javascript tracking code
var _trackingCode = '5sulid5e';
(function() {
var wa = document.createElement('script');
wa.type = 'text/javascript';
wa.async = true;
wa.src = '//cdn.8digits.com/automation.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wa, s);
})();
i want to customize that for work on another website.
it works on vestel.com.tr but it doesnt work on mavi.com .
How can i customize that script for mavicom.
Thanks for your help.
Perhaps, you can hack this by writing a proxy, as some vendors may bind tracking IDs with a specific domain.
Forward the ajax from the vendor's JS code to your proxy server. In your proxy server modify the origin request header as the registered header i.e. vestel.com.tr .For this you will need to modify the JS code provided by vendor located at cdn.8digits.com/automation.js and then in script tag of your website provide the script source as your hacked JS, NOT the actual one.
PS you can't modify the origin header in the browser's AJAX itself due to security restriction by browsers.
I was trying to create a bookmarklet in chrome (I was using the console). I got the following error:
Refused to load the script 'https://code.jquery.com/jquery-1.6.1.min.js' because
it violates the following Content Security Policy directive: "script-src
https://*.facebook.com http://*.facebook.com https://*.fbcdn.net
http://*.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net
*.google.com 127.0.0.1:* *.spotilocal.com:*
chrome-extension://lifbcibllhkdhoafpjfnlhfpfgnpldfl 'unsafe-inline'
'unsafe-eval' https://*.akamaihd.net http://*.akamaihd.net".
My code was
var jQueryLib = document.createElement("script");
jQueryLib.src = "https://code.jquery.com/jquery-1.6.1.min.js";
document.body.appendChild(jQueryLib);
Does this mean creating bookmarklets is no longer possible? What I wanted to do was like a bunch of new comments on my Facebook group and thought a bookmarklet would be a good idea.
Any advice?
From that error message it is not having an issue with the Bookmarklet itself. The problem is that is that Facebook has declared a list of domains in which scripts may be run from. When you try to inject the jQuery script it sees that the domain (jquery.com in this case) is not on the allowed list and refuses to run it.
As an alternative you could copy and paste the entire jQuery file into console. This would bypass the content restriction. You could also turn the entire jQuery library into a bookmarklet to make it easier to add to a page.
Yes Javascript Bookmarklets are allowed in Chrome. For example, copy and paste the code below into a bookmark. Change the title to whatever you want, but paste the code below into the URL section. Then press it.
javascript:alert("See, it works");
I'm working on a project where i have to use dojo (i'm doing a custom widget) and the google map api (v3)
For some technical reason, i have to include the google map api through my js file and not through my html file, so i can't use
<script type='text/javascript' src='http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places'></script>
The load have to be done synchronously.
I've tried some things, first adding the script using
document.write("<script type='text/javascript' src='http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places'></script>");
But that's not working, i get a blank page instead, using firebug i can see that the panel "Network" is clearing and the page make an infinite loading of google map api script.
I think i can't do it using dojo.io.script (which allow to make cross domain request), because we can't make synchronous request with dojo.io.script
Any help will be appreciated ;)
Well, solution was to use google map callback :
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&callback=mapLoaded";
document.body.appendChild(script);
Then make the function "mapLoaded" which execute the code
Thanks for those who taked time to answer me
You should still be able to use dojo.io.script. It does not have to be synchronous. The maps API takes a c