Chrome Extension: Injecting external script - javascript

I'm creating a Chrome extension that appends a script tag to a page, and then uses code defined in that external script:
$('body').append('<script src="..."></script><script>console.log(SomeObject)</script>');
SomeObject is defined in the external script, so I should be able to access it, right? Well, I can't, as I get an "undefined" error.
I even tried using head.js to load the external script and execute a function after the script is loaded, to no avail.
If I open the Chrome console, I can access the damn object just fine!!!
I tried both a content script and executeScript inside a background page to no avail. On both, if I use console.log(window), I can inspect the window object in the console, and SomeObject is nowhere to be found. If I inspect the window object on the Chrome console, there it is!
Are injected scripts sandboxed somehow or what gives?
Thanks!

This is what finally worked:
var script = document.createElement('script');
script.src = "...";
script.addEventListener('load', function() {
// SomeObject is available!!!
});
document.head.appendChild(script);
I wonder why none of the other methods worked...

I bet the script just isn't loaded when you call it right away, does this work:
<script src="..."></script><script>setTimeout(function() {console.log(SomeObject)}, 3000)</script>

So it seems the answer is you can't, due to security restrictions :(
I had to hack my way around it by using an iframe (oddly, the iframe can access its parent document).

Related

Why does browser.runtime.getBackgroundPage() resolve to null in a page action script?

In the following code
browser.runtime.getBackgroundPage().then(bgp=>{
document.querySelector("button").addEventListener("click", e=>{
alert(bgp);
});
});
bgp turns out to be null. I searched around and suggestions are most of the time for Chrome extensions, suggesting adding a "background" permission, which is not valid for Firefox. I also tried adding a background page explicitly, although one should be always created for me but it did not work either.
runtime.getBackgroundPage() provides access to the background script, not an HTML document.
This provides a convenient way for other privileged extension scripts
to get direct access to the background script's scope. This enables
them to access variables or call functions defined in that scope.
"Privileged script" here includes scripts running in options pages, or
scripts running in browser action or page action popups, but does not
include content scripts.
For example, the following code logs <unavailable> to the console.
browser.runtime.getBackgroundPage().then(bg => console.log(bg));
The window object can be seen in the debug console.

JS function works on chrome console but not when load from plugin

So I have a webpage with a function applaud. When I call it from the console, I get the normal return:
applaud(3004,1935);
undefined
However, if I use CTG plugins (simple plugin to run a js script), with that code
applaud(3004,1935);
I get the following error in console:
3VM5444:1 Uncaught ReferenceError: applaud is not defined
at <anonymous>:1:1
(anonymous) # VM5444:1
and function isn't working.
Do you know how I can use it?
Thanks.
I know this is a bit outdated, but I can answer this. (I made the extension in question.)
Chrome Extensions by default insert scripts into a webpage in a different context than the rest of the page. This is for security reasons. If you'd like to run code in the context of the webpage, you'd need to use a little workaround.
In the script that the Chrome Extension injects, have that inject a <script> tag into the body of the page. Then that script will be loaded and be able to execute the functions like you can in the console.
Here's a demo of code that can do what I'm talking about:
//Create a new script element.
var script = document.createElement("script");
//Get the function you want to inject as a string and add it to the script.
script.innerHTML = injection.toString();
//Add a call to that injection function so it'll automatically execute once it's injected.
script.innerHTML += "injection();";
//Inject that newly created script into the body of the page.
document.body.appendChild(script);
//The contents of this script will be run inside the same context as the webpage.
function injection(){
applaud(3004, 1935);
}

Does Google Apps block code from the Chrome console?

I noticed the Chrome console gave an error when the following was typed:
$("body").hide();
Is there a solution to modify HTML elements when working with Google Apps?
Jquery can't be accessible in browser console directly, because it's a external library file & doesn't come inbuilt within browser.
So to access the Jquery from console, you can run below line in console;
var jqlib = document.createElement('script');
jqlib.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
document.getElementsByTagName('head')[0].appendChild(jqlib);
Here we get the script tag of current page & injecting JQuery library into it.
After running above lines, you can execute your code;
$(body).hide();

Unable to load script from another server - Content Security Policy issue?

I have been trying to turn a bookmarklet into a small development environment that I can use for testing some javascript and sending commands easily on the fly and updating the code on my server quickly to see the result. This has half way worked using method's I have found in this site and google however it doesn't seem to work very well and sometimes randomly doesn't work. The end goal is to have a bookmarklet that I can click on from any page and it loads a javascript file I have saved on my server. I have created the following two bookmarklets to try and get this working:
Failed Method 1:
javascript:
var s = document.createElement('script');
s.type='text/javascript';
document.body.appendChild(s);
s.src='//smewth.com/test.js';
void(0);
Method 1 in one line bookmarklet form: javascript: var s = document.createElement('script'); s.type='text/javascript'; document.body.appendChild(s); s.src='//smewth.com/test.js'; void(0);
Failed Method 2:
javascript:(
function(){
var imported = document.createElement('script');
imported.type='text/javascript';
imported.src = 'https://smewth.com/test.js';
document.head.appendChild(imported);
})();
Method 2 in one line bookmarklet form: javascript:( function(){ var imported = document.createElement('script'); imported.type='text/javascript'; imported.src = 'https://smewth.com/test.js'; document.head.appendChild(imported); })();
I got method 1 by decomposing the kickass bookmarklet from (http://kickassapp.com/). The actual one I got from their site works fine on my browser no problems. I even did a direct substitution from the URL they were using to load with my URL. The second method I found while searching on this site and this actually worked for a small while and stopped working for some unknown reason (maybe different browsers). I tried appending this script object to the head and the body on each of them with no improved results.
I created the test.js script just for this post and it contains a simple alert box statement:
$$ [/]# cat test.js
alert("hi");
$$ [/]#
NOTE: When I do this with the code embedded within the the bookmarklet itself without appending it to a head/body object then it works fine such as this:
javascript:%20alert("hi");
I did notice that with both of these methods, the code is actually getting injected into the page however I am not seeing the code is ever executed when I click the bookmark. Does anyone know which method is the best or something similar to do this so I can have javascript load through a page which I update on a remote server (reliably)? Maybe I need to attach the to a different object?
Thank you for your help.
-Jeff
UPDATE: I am showing this works while this site is loaded but it doesn't work when your at a site like google.com. Not sure what the difference is or how to accomodate this, google.com has a head and a body object too. I am showing this works in some sites and in some it doesn't.
I figured this out. There were two things occurring which accounts for the intermittent symptom of this issue. The first issue was that the site which was hosting the code was on a self-signed certificate. I began to notice the issue was occurring only when trying to run this from within secure sites. Then in Chrome I saw a error show up in the console. It would be nice if Firefox gave me a error on the console or something as this was the root of the issue. The second thing I had to do was disable OCSP in Firefox as I used a free certificate for testing purposes.
I also had to use method 1 as described above. Firefox and Chrome both did not like the anonymous function call for some reason. From now on I will refer to Chrome to look for errors in the console as Firefox has proven itself not very useful for this.

Why is chrome.runtime undefined when running JS inside a page from a content script?

I am creating a Google Chrome extension (my first one) and I want to send messages from the extension to the current tab.
I am following the documentation:
https://developer.chrome.com/apps/runtime#event-onMessage
The extension loads a small external JS into the tab's HTML, which contains the following code:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(request)
}
);
As soon as the JS is loaded I get the following error:
Uncaught TypeError: Cannot read property 'onMessage' of undefined.
Opening console and typing chrome, I can see that the runtime is not a property of chrome.
It looks like I am doing something wrong, but what? Do I need to add something to the manifest.json file?
Chrome Version 39.0.2171.71 m
Thank you.
If you're inserting JavaScript into a page with a <script> tag, it executes in the page's context.
Sometimes it is desirable: that's the only way to access page-level JavaScript objects.
But in your case it means that the code does not have access to Chrome APIs, as it is "the same" as the page's code.
You need to look into communicating between page-level and content scripts, or between page-level and background (spoiler, in most cases needs a context script proxy anyway).
or it could just be a Heisenbug which only appears under certain circumstances. in my case, closing the chrome://extensions tab and refreshing my target caused chrome.runtime to be available again. Why is chrome.runtime undefined in the content script?

Categories