Are Bookmarklets Possible in Chrome? - javascript

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");

Related

How to make use of jsPDF library specifically for a Chrome extension?

For my Chrome extension, I want to give users an option to download a PDF that displays and formats their data for them. The idea is that a user press a button on the extension popup, the extension generates the pdf, and the browser downloads the pdf.
To little avail, so far I've tried using jsPDF (https://github.com/parallax/jsPDF). I followed their procedure to load from CDN in a script tag — <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> — in my popup HTML file (popup.html), and wrote the associated import statement import {jsPDF} from "jspdf"; in my popup script (popup.js).
When I run the extension, I get two errors.
Refused to load the script 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
A comment in different post (Chrome Extension "Script-src" error (self-learning)) suggested to address this by adding "content_security_policy":"script-src 'self' https://example.com; object-src 'self'" as a new key in the manifest file. I tried this — and was sure to change the url to the one mentioned earlier, in the script tag — yet the error persisted.
Uncaught SyntaxError: Cannot use import statement outside a module
One suggestion to address this was made in another post (Chrome Extension "Script-src" error (self-learning)); upon implementing this change, the error I received was: Uncaught TypeError: Cannot destructure property 'jsPDF' of 'window.jspdf' as it is undefined.
I have looked extensively online for references explaining how to use libraries like jsPDF with Chrome extensions. Most explain in detail how to use such libraries with Node. But few include details for browser usage and, in particular, Chrome extension usage.
add this to the top of your javascript file:
const { jsPDF } = window.jspdf;

How to handle CSP for dynamically generated page

I have a chrome extension which has started having problems due to CSP changes on the target page.
The extension has content-script which creates a new window using window.open - let's call it report window. This window houses a dynamically generated and downloadable report. User's activity on the target page generates content on the report window - similar to an activity log which shows the headline as an anchor and on clicking the anchor, it toggles the display of a details <section> to make it visible/invisible, using code similar to below
Data #1
Data #2
Data #3
The required functions are dynamically added to the document using code similar to below
let script = document.createElement('script');
script.text = code.join('\n');
doc.head.appendChild(script);
There are many such entries in the report window and they are not generated at once, but in response to user's activity.
This all works fine and dandy. But recently the website implemented CSP restrictions on inline javascript code.
Content-Security-Policy: script-src 'sha256-6gLjSWp3GRKZCUFvRalksdfkahsdfX5aGHtECD1wVRg=' 'unsafe-inline' ...
Due to this, my detail section does not open up when the user clicks the anchor tag headline and shows the below error on the console
Refused to run the JavaScript URL because it violates the following Content Security Policy directive...
This is what I want to know
Is it possible to relax or reset the CSP in a newly created child window? If yes, then how? I know meta tags cannot relax it but only restrict it more.
How can I comply with this new CSP directive, given that the report is a dynamically generated DOM. Also, I need this report to be downloadable, currently, I can easily download the DOM of the document into an html, to provide a report. Seems like I might have to provide an mht report, if the scripts has to be put in a separate document. I am not even sure how to provide the script in a separate document, given that this is a chrome extension

How to prevent an external JS request

I'm using a service that automatically constructs and hosts launch pages. In the body of their code, they have a call to jquery:
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js?cache=2015-09-22-09">
Unfortunately, since I'm in China, googleapis.com is blocked and the page has to wait for this code to timeout before it will render. This portion is autogenerated as part of the template and I can't change it. However I can insert custom javascript in the head and the body.
Are there any ways I can prevent this code from making the request to googleapis.com or to force it to abort after it has already made the request?
-EDIT-
Here's a screen cap of the network tab when I try to load the page. As you can see, the call to googleapis.com hangs for 1.4 mins until it times out, at which point DomContentLoaded triggers and the entire page loads.
Right, if you are able to put html in the head of the document, not just execute javascript you could use a meta tag to block external script loading:
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
From the Mozilla Content-Security-Policy Meta Tag Docs:
Authors are strongly encouraged to place meta elements as early in the document as possible, because policies in meta elements are not applied to content which preceds them. In particular, note that resources fetched or prefetched using the Link HTTP response header field, and resources fetched or prefetched using link and script elements which precede a meta-delivered policy will not be blocked.
So the meta tag will only work in the head, certainly before the script which loads jQuery. You can whitelist URL's in the tag by adding them into the content parameter in the meta tag too.
If you can only execute javascript, you can add the meta tag dynamically. Unfortunately it is likely the browser has probably decided on it's policies by the time it is added. Nevertheless, it can be added with
var meta = document.createElement('meta');
meta.httpEquiv = "Content-Security-Policy";
meta.content = "script-src 'self'";
document.getElementsByTagName('head')[0].appendChild(meta);
More Interesting reading material homework for solving the 'Prevent an external js request' mystery:
Use JavaScript to prevent a later `<script>` tag from being evaluated?
Good Luck!
Consider using a Content Security Policy. It would be an unusual use case, but with the CSP you can tell the browser that it is not allowed to access googleapis.com before your government even gets a say in the matter. In this way, the browser won't even try to load it, and the page will not hang.
Yeah. #Niet's suggestion seems nice. To add to his answer, here's how you can block rendering of googleapi domain using CSP:
Content-Security-Policy: script-src 'self';
This code would instruct the browser to only execute YOUR own domain's scripts.
If you have access to the web server and its windows you could add an entry in the Hosts file to redirect the google address to the local server web application to download the javascript from there? (if you match the folder structure of the javascript link)
c:\windows\system32\drivers\etc\hosts
ajax.googleapis.com 127.0.0.1

How to check if site has allowed me to inject Javascript with my bookmarklet?

I have a bookmarklet that injects Javascript into a page and opens up an iframe with an HTML page I have created that allows a user to subscribe to a page directly from my bookmarklet.
Issue is, certain domains (Twitter and Facebook being two) do not allow me to inject Javascript, so I have to pop up a window instead.
Javascript console when on Facebook:
Refused to load the script script name 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 *.atlassolutions.com".
Right now in my bookmarklet I am just checking to see if the URL matches those domains before I try to inject JS, and if it does, I pop open a new window. For obvious reasons, this is not a good practice.
What is a good method of checking if a Javascript function was allowed to run on the current page or not, and if not, to open a new window?
There is no way to know with absolute certainty that an external script failed to load. Even when there is no security policy, an external script could fail to load because of other problems. The only One thing you can really do is set a timeout and if the script hasn't completed some action before the timeout expires, assume it has failed to load.
EDIT: I stand corrected by Sean below. His suggestion also worked in Chrome and Firefox on Windows. The solution is something like this:
newScript.addEventListener('error', function(){ console.log('script failed to load') });
For the specific question of how to check if the page header returns a Content Security Policy which will block your external script, the only solution I know of is to check the HTTP header using AJAX.
Here is some example code. I've tested this on Facebook.
req = new XMLHttpRequest;
req.onreadystatechange = function(){if (req.readyState==4) console.log(req.getResponseHeader('content-security-policy'))};
req.open("HEAD", document.location.href);
req.send();
Bookmarklets should be allowed to run whatever the security policy is. If not, it is a browser bug - at least if I understand this correctly. But the bookmarklet may be forbidden to do some things. If you use try-catch you can find out if an action was allowed or not.

Is it possible to bypass CSP when injecting js in the page from a Firefox plugin?

I have a firefox plugin that used to interact with github's web app by injeting some javascript in the page (by creating a element under the head element, and setting its innerHTML value to the javascript to be executed).
However, it just stopped working lately. I then saw the following warning:
Timestamp: 8/21/13 5:45:42 PM
Warning: CSP WARN: Directive inline script base restriction violated
Source File: https://github.com/login
Line: 0
Source Code:
myjscode();...
Github returns the following header:
X-Content-Security-Policy: default-src *; script-src 'self' https://github.global.ssl.fastly.net https://jobs.github.com https://ssl.google-analytics.com https://collector.githubapp.com https://analytics.githubapp.com; style-src 'self' 'unsafe-inline' https://github.global.ssl.fastly.net; object-src 'self' https://github.global.ssl.fastly.net
I was aware that Firefox started supporting CSP through the X-Content-Security-Policy header, but I thought some mechanism would be in place to prevent code injection from plugins to brake.
Does anyone know if the extension API has any specific mechanism for injecting javascript in the page in a and bypass the CSP settings? Rationale is - if the user has the plugin installed, he/she trusts it, and there should be a way to bypass CSP.
It's a script that interacts with some form elements, like filling up text inputs and clicking buttons. Pretty straightforward stuff.
I'd look into either SDK page-mod, or for non SDK add-ons just listen to load events and do your manipulations in the event handler using the regular DOM API.
Using the SDK with page-mod is likely the closest thing that resembles chrome.tabs.executeScript and chrome extensions in general, so I'd go with that.
You can do this in firefox, although not recommended.
Open the page, about:config
and set security.csp.enable to false (restart may be required).

Categories