I'm trying to change the variable in a page using a userscript.
I know that in the source code there is a variable
var smilies = false;
In theory I should be able to change it like that:
unsafeWindow.smilies = true;
But it doesn't work. When I'm trying to alert or log the variable to the console without hijacking I get that it's undefined.
alert(unsafeWindow.smilies); // undefined !!!
EDIT: I'm using Chrome if it changes anything...
http://code.google.com/chrome/extensions/content_scripts.html says:
Content scripts execute in a special environment called an isolated
world. They have access to the DOM of the page they are injected into,
but not to any JavaScript variables or functions created by the page.
It looks to each content script as if there is no other JavaScript
executing on the page it is running on.
It's about Chrome Extensions but I guess it's the same story with Userscripts too?
Thank you, Rob W. So the working code for people who need it:
var scriptText = "smilies = true;";
var rwscript = document.createElement("script");
rwscript.type = "text/javascript";
rwscript.textContent = scriptText;
document.documentElement.appendChild(rwscript);
rwscript.parentNode.removeChild(rwscript);
In Content scripts (Chrome extensions), there's a strict separation between the page's global window object, and the content script's global object.
To inject the code, a script tag has to be injected.
Overwriting a variable is straightforward.
Overwriting a variable, with the intention of preventing the variable from being overwritten requires the use of Object.defineProperty Example + notes.
The final Content script's code:
// This function is going to be stringified, and injected in the page
var code = function() {
// window is identical to the page's window, since this script is injected
Object.defineProperty(window, 'smilies', {
value: true
});
// Or simply: window.smilies = true;
};
var script = document.createElement('script');
script.textContent = '(' + code + ')()';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
Related
Below is my code.
It is resulting in unexpected behaviour.
It navigates to bing.com but it does not fill in the text field. Also, I have noticed that the console get cleared after navigating to a new webpage.
window.location = "https://www.bing.com";
window.onload = function(){
var editSearch = document.getElementById("sb_form_q");
editSearch.value = "Quux";
}
You are binding the onload function to the existing window object.
When the browser loads the new page, it will make a new window object which won't have your property set on it.
JavaScript run in one page (even when you are running it through developer tools) can't persist variables onto a different page.
(Storage mechanisms like localStorage and cookies are available, but you would need code in the subsequent page to look for them).
JavaScript is only valid for the current page you are on. When you are executing code from DevTools console, you are executing code on that page itself. So, when you navigate to another page using window.location you loose the onload handler you have defined.
To add handlers to a different page, it must be connected to your page (the parent) in some way, like an iframe or a popup.
ifrm = document.getElementById('frame');
ifrm.src = 'http://example.com';
ifrm.contentWindow.onload = function () {
// do something here with
// ifrm.contentWindow.document.getElementById('form')
}
As #Quentin said.
But you can do another way like ..
var keyword = "Quux";
window.location = "https://www.bing.com/search?q="+keyword;
I have the following code in my content script which is calling a function in the webpage's javascript
var actualCode = '(' + function() {
functionInMyWebPage();
}
+ ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
This is working and it fires the functionInMyWebPage() function.
Now I need to get the returned value of this functionInMyWebPage() and call another function which defined in the content script itself. If I call it in the above script block it will complain as it has not defined.
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.
More info Content script execution environment
tl;dr Can I execute un-trusted scripts on an iframe safely?
Back story:
I'm trying to make secure JSONP requests. A lot of older browsers do not support Web Workers which means that the current solution I came up with is not optimal.
I figured I could create an <iframe> and load a script inside it. That script would perform a JSONP request (creating a script tag), which would post a message to the main page. The main page would get the message, execute the callback and destroy the iframe. I've managed to do this sort of thing.
function jsonp(url, data, callback) {
var iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
var iframedoc = iframe.contentDocument || iframe.contentWindow.document;
sc = document.createElement("script");
sc.textContent = "(function(p){ cb = function(result){p.postMessage(result,'http://fiddle.jshell.net');};})(parent);";
//sc.textContent += "alert(cb)";
iframedoc.body.appendChild(sc);
var jr = document.createElement("script");
var getParams = ""; // serialize the GET parameters
for (var i in data) {
getParams += "&" + i + "=" + data[i];
}
jr.src = url + "?callback=cb" + getParams;
iframedoc.body.appendChild(jr);
window.onmessage = function (e) {
callback(e.data);
document.body.removeChild(iframe);
}
}
jsonp("http://jsfiddle.net/echo/jsonp/", {
foo: "bar"
}, function (result) {
alert("Result: " + JSON.stringify(result));
});
The problem is that since the iframes are on the same domain, the injected script still has access to the external scope through .top or .parent and such.
Is there any way to create an iframe that can not access data on the parent scope?
I want to create an iframe where scripts added through script tags will not be able to access variables on the parent window (and the DOM). I tried stuff like top=parent=null but I'm really not sure that's enough, there might be other workarounds. I tried running a for... in loop, but my function stopped working and I was unable to find out why.
NOTE:
I know optimally WebWorkers are a better isolated environment. I know JSONP is a "bad" technique (I even had some random guy tell me he'd never use it today). I'm trying to create a secure environment for scenarios where you have to perform JSONP queries.
You can't really delete the references, setting null will just silently fail and there is always a way to get the reference to the parent dom.
References like frameElement and frameElement.defaultView etc. cannot be deleted. Attempting to do so will either silently fail or throw exception depending on browser.
You could look into Caja/Cajita though.
tl;dr no
Any untrusted script can steal cookies (like a session id!) or read information from the DOM like the value of a credit card input field.
JavaScript relies on the security model that all code is trusted code. Any attempts at access from another domain requires explicit whitelisting.
If you want to sandbox your iframe you can serve the page from another domain. This does mean that you can't share a session or do any kind of communication because it can be abused. It's just like including an unrelated website. Even then there are possibilities for abuse if you allow untrusted JavaScript. You can for instance do: window.top.location.href = 'http://my.phishing.domain/';, the user might not notice the redirect.
I'm new to javascript. How do I anonymize Google Pagespeed?
Here is the original code:
http://pastebin.com/xRbTekDA. It works when I load the page
Here is the anonymize code: http://pastebin.com/fj9rP7FM. It shows a javascript error every time I load the page. It says "ReferenceError: runPagespeedCallbacks is not defined" because I anonymized it.
How do I anonymize that original code?
The problem you are having is the method the code is expecting to call is not in scope. So if you modify the code slightly this should rid you of the error. This code should fix the issue. http://pastebin.com/RrQ2848j
Notice i'm just returning the callback function and assigning it as a variable. There are other approachs you can take but there needs to be something in the global scope to call.
The reason for this is a script block is being created to get script and data, because an AJAX(XHR) request would violate the same-origin policy trying to reach out to google.com while executing on yourdomain.com . When the script is downloaded, it's going to expect to call a function in the global scope to pass some data into it. That function is named on the query string of the SRC attribute when creating the script block as shown here:
function runPagespeed() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
var query = [
'url=' + YN_URL,
'callback=runPagespeedCallbacks',
'key=' + API_KEY
].join('&');
s.src = API_URL + query;
document.head.insertBefore(s, null);
}
The only difference between the two is that the second is wrapped in an immediately invoked function expression (IIFE). The IIFE encapsulates the code so that the free variables are not globally visible. Normally this is a good thing, but if other services rely on that code, it will not be visible.
I've got some banner zones set up on advertisespace.com - I'm trying to load the script tags using jquery so they load after the page has loaded. However its not working. Here is my code to do this.
Here is the function I use to include the script tag:
function jsinclude(file, dom) {
if (document.createElement && document.getElementsByTagName) {
if(dom=='undefined')
var dom = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', file);
script.setAttribute('charset',"utf-8");
dom.appendChild(script);
} else {
alert('Your browser can\'t deal with the DOM standard. That means it\'s old. Go fix it!');
}
}
ANd here is how I am calling the function:
$(function(){
jsinclude('http://ads.advertisespace.com/somethingsomething.js', document.getElementById('location-of-banner-1'));
jsinclude('http://ads.advertisespace.com/somethingsomething.js', document.getElementById('location-of-banner-2'));
})
The result is that the script tag is inserted in the correct place but the banners doesn't show i.e the code in the script file referred to is never executed. How can I fix this.
You tagged your question with jquery so why not make use of its advantages.
The dom is not the head element, and doing dom == 'undefined' checks whether the variable dom is equal to the string 'undefined'. You must have set that explicitly and that's probably not the case. Anyway, there is one head element so it's not necessary to pass it to the function - the function can handle that itself.
Also, checking for DOM functions is not applicable these days. We live in 2011, all browsers have these functions included.
function jsinclude(file) {
var script = $("<script>", { type: 'text/javascript',
src: file,
charset: 'utf-8' });
$('head').append(script);
}