|
|
(60 intermediate revisions by 13 users not shown) |
Line 1: |
Line 1: |
| {{lowercase}} | | {{DISPLAYTITLE:unsafeWindow}} |
| {{security}} | | {{security}} |
| __NOTOC__
| |
| {{Greasemonkey Manual TOC}}
| |
|
| |
|
| == Description == | | == Description == |
|
| |
|
| This [[API_reference|API]] object allows a [[User script]] to access "custom" properties--variable and functions defined in the page--set by the web page. The unsafeWindow object is shorthand for <code>window.wrappedJSObject</code>. It is the raw window object inside the XPCNativeWrapper provided by the Greasemonkey [[sandbox]]. | | This object allows a [[User script]] to access "custom" properties set by the web page. |
| | The user script is otherwise isolated from these properties. |
|
| |
|
| :*'''USE OF UNSAFEWINDOW IS INSECURE, AND IT SHOULD BE AVOIDED WHENEVER POSSIBLE.''' | | :*'''USE OF UNSAFEWINDOW IS INSECURE, AND IT SHOULD BE AVOIDED WHENEVER POSSIBLE.''' |
|
| |
|
| unsafeWindow bypasses [[Greasemonkey]]'s [[XPCNativeWrapper]]-based [[security]] model, which exists to make sure that malicious web pages cannot alter objects in such a way as to make greasemonkey scripts (which execute with more privileges than ordinary Javascript running in a web page) do things that their authors or users did not intend. User scripts should therefore avoid calling or in any other way depending on any properties on unsafeWindow - especally if if they are executed for arbitrary web pages, such as those with <code>@[[Include and exclude rules|include]] *</code>, where the page authors may have subverted the environment in this way. | | unsafeWindow bypasses [[Greasemonkey]]'s security model, which exists to make sure that malicious web pages cannot alter objects in such a way as to make user scripts (which execute with more privileges than ordinary JavaScript running in a web page) do things that their authors or users did not intend. |
| | User scripts should therefore avoid calling or in any other way depending on any properties on unsafeWindow - especially if they are executed for arbitrary web pages, such as those with <code>@[[Include and exclude rules|include]] *</code>. |
|
| |
|
| [[User script]] authors are '''strongly''' encouraged to learn how [[XPCNativeWrapper]]s work, and how to perform the desired function within their security context, instead of using unsafeWindow to break out.
| | == Examples == |
| | |
| [[#Examples|Examples]] | [[#Alternatives_to_unsafeWindow|Alternatives to unsafeWindow]] | [[#Notes|Notes]]
| |
| | |
| == Syntax == | |
|
| |
|
| '''unsafeWindow''' | | <pre class='sample-bad'> |
| | |
| :Value: Object
| |
| :Returns: Variant
| |
| :Compatibility: [[Version_history#0.5_beta|Greasemonkey 0.5b+]]
| |
| | |
| [[#top|top]]
| |
| | |
| == Examples ==
| |
| <code><pre>
| |
| unsafeWindow.SomeVarInPage = "Testing"; | | unsafeWindow.SomeVarInPage = "Testing"; |
| </pre></code> | | </pre> |
|
| |
|
| <code><pre>
| | <pre class='sample-bad'> |
| unsafeWindow.SomeFunctionInPage("Test"); | | unsafeWindow.SomeFunctionInPage("Test"); |
| </pre></code> | | </pre> |
|
| |
|
| <code><pre>
| | <pre class='sample-bad'> |
| var oldFunction = unsafeWindow.SomeFunctionInPage; | | var oldFunction = unsafeWindow.SomeFunctionInPage; |
| unsafeWindow.SomeFunctionInPage = function(text) { | | unsafeWindow.SomeFunctionInPage = function(text) { |
| alert("Hijacked! Argument was " + text + "."); | | alert('Hijacked! Argument was ' + text + '.'); |
| return oldFunction(text); | | return oldFunction(text); |
| }; | | }; |
| </pre></code> | | </pre> |
| | |
| :For issues with [[GM_getValue]], [[GM_setValue]] and [[GM_xmlhttpRequest]], see see [[0.7.20080121.0_compatibility]].
| |
| | |
| <code><pre>
| |
| window.addEventListener(
| |
| "DOMTitleChanged",
| |
| function() {
| |
| var redirectURL = window.name;
| |
| },
| |
| false
| |
| );
| |
| | |
| var sGetter = document.createElement("script");
| |
| sGetter.type = "text/javascript";
| |
| sGetter.innerHTML =
| |
| "function uXHR(url) {" +
| |
| " var xhr = new XMLHttpRequest();" +
| |
| " xhr.onreadystatechange = function() { " +
| |
| " if (xhr.status == 301 || xhr.status == 302) {" +
| |
| " window.name = xhr.getResponseHeader('Location');" +
| |
| " document.title = document.title;" +
| |
| " }" +
| |
| " };" +
| |
| " xhr.open('HEAD', url, true);" +
| |
| " xhr.send(null);" +
| |
| "}";
| |
| | |
| document.body.appendChild(sGetter);
| |
| | |
| unsafeWindow.uXHR(url);
| |
| | |
| </pre></code>
| |
| | |
| [[#top|top]]
| |
|
| |
|
| == Alternatives to unsafeWindow == | | == Alternatives to unsafeWindow == |
|
| |
|
| [[#Events|Events]] | [[#Functions_defined_in_the_page|Functions defined in the page]] | [[#Attach_script_to_page | Attach script to page]]
| | ''Sometimes'', you just can't get around using unsafeWindow. |
| | | Most of the time, however, you can! |
| === Events ===
| | See [[:Category:Coding Tips:Interacting With The Page]] for details on various methods to interact with the page that do '''not''' use unsafeWindow. |
| | |
| :Event listeners never need to be created on unsafeWindow. Rather than using
| |
| | |
| <code>unsafeWindow.onclick = function(event) { /* some code */ };</code>
| |
| | |
| use:
| |
| | |
| <code><pre>window.addEventListener("click", function(event) { /* some code */ }, false);</pre></code>
| |
| | |
| :See also [http://developer.mozilla.org/en/docs/DOM:element.addEventListener addEventListener at MDC]
| |
| | |
| [[#top|top]] | [[#Alternatives_to_unsafeWindow|back]]
| |
| | |
| === Functions defined in the page ===
| |
| | |
| :If a user script must execute a page function, it can use the '''[[location hack]]''' to call it safely. This involves setting location.href to a <code>javascript:</code> URL, which is like using a bookmarklet. For example:
| |
| | |
| :<code><pre>location.href = "javascript:void(pageFunc(123));";</pre></code>
| |
| | |
| :Larger blocks of code independent of the Greasemonkey context/APIs can also be executed this way:
| |
| | |
| :<code><pre>location.href = "javascript:(" + encodeURI(uneval(function() { /* some code */ })) + ")();";</pre></code> | |
| | |
| :This code will run in the page context without leaking the [[sandbox]]. This code is completely separate from the rest of the script scope, sometimes limiting its usefulness. For example, data cannot be returned by the function. | |
| | |
| :Another drawback is that this technique is rather ugly. Still, it is preferred over unsafeWindow.
| |
| | |
| [[#top|top]] | [[#Alternatives_to_unsafeWindow|back]]
| |
| | |
| === Attach script to page ===
| |
| | |
| ==== Attach Method 1 ====
| |
| <code><pre>
| |
| function myScript() {
| |
| for (var x in document) {
| |
| // some code with x
| |
| }
| |
| // some code
| |
| }
| |
| | |
| // attach script to page; script can therefore reference variables on the page, but likewise
| |
| // cannot use Greasemonkey API methods
| |
| | |
| document.body.appendChild(document.createElement("script")).innerHTML="(" + myScript + ")()";
| |
| </pre></code>
| |
| | |
| [[#top|top]] | [[#Alternatives_to_unsafeWindow|back]]
| |
| | |
| ==== Attach Method 2 ====
| |
| Place this line at the very beginning of the script to inject the entire script into the page
| |
| using the location hack. Like Attach Method 1, this will give the script access to variables
| |
| on the page, but not access to Greasemonkey API methods.
| |
| <code><pre>if(window.wrappedJSObject){location.href="javascript:("+arguments.callee.toSource()+")();";return;}</pre></code>
| |
| | |
| [[#top|top]] | [[#Alternatives_to_unsafeWindow|back]]
| |
| | |
| ==== Attach Method 3 ====
| |
| This way is interesting for those who want:
| |
| * execute the init() function NOT in GM address space
| |
| * inject multiple css hacks
| |
| * inject multiple .js files (even from different domains)
| |
| | |
| <code><pre>
| |
| /* Filename: hello-world.user.js */
| |
| | |
| inject_css();
| |
|
| |
| /*
| |
| Define single/multiple script(s) to inject
| |
| NOTES:
| |
| - Schemes of file:// type, absolute or implied, are not supported with this method due to
| |
| browser security restrictions.
| |
| - Schemes of http:// or https:// must be present
| |
| | |
| - This method currently works only on Windows but NOT Linux NOR OS X
| |
| See pitfall 1 below
| |
| */
| |
| | |
| var scripts = [
| |
| "http://localhost:8080/hello-injecting.js",
| |
| "http://www.example.com/inject-this-script1.js",
| |
| "http://www.example.com/inject-this-script2.js"
| |
| ];
| |
| | |
| var script;
| |
| for (i in scripts) {
| |
| script = document.createElement("script");
| |
| script.src = scripts[i];
| |
| script.type = "text/javascript";
| |
| | |
| document.getElementsByTagName("head")[0].appendChild(script);
| |
| }
| |
|
| |
| window.addEventListener(
| |
| "load",
| |
| function(event) {
| |
| location.href = "javascript:void(init());";
| |
| },
| |
| false
| |
| );
| |
|
| |
|
| |
| function inject_css() {
| |
| document.title += ' dynamically modified version';
| |
| GM_addStyle("body { color:white; background-color:black } img { border:0 }");
| |
| }
| |
| </pre></code>
| |
| | |
| <code><pre>
| |
| /*
| |
| Filename: http://localhost:8080/hello-injecting.js
| |
| or
| |
| http://www.example.com/hello-injecting.js
| |
| */
| |
| | |
| function init() {
| |
| alert('Hello, world!');
| |
| }
| |
| </pre></code>
| |
| | |
| [[#top|top]] | [[#Alternatives_to_unsafeWindow|back]]
| |
| | |
| ===== Attach Method 3 Pitfall 1 =====
| |
| :The method of hosting hello-injecting.js on a local and remote web server was tested on:
| |
| ::Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.0.6) Gecko/2009011912 Firefox/3.0.6
| |
| ::Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.0.7) Gecko/2009021906 Firefox/3.0.7
| |
| | |
| ::and ''returned Component failure code'' with the following error:
| |
| | |
| :::Error: Component returned failure code: 0x805e000a [nsIDOMLocation.href] = <unknown>
| |
| :::Source file: file://~/.mozilla/firefox/{randomseed}.default/extensions/{class-id}/components/greasemonkey.js
| |
| :::Line: 377
| |
| | |
| ::Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.0.8) Gecko/2009032608 Firefox/3.0.8
| |
| ::Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.8) Gecko/2009032608 Firefox/3.0.8
| |
| ::and ''failed to execute init()'' with the following error:
| |
| | |
| :::Error: init is not defined
| |
| :::Source file: javascript:void(init());
| |
| :::Line: 1
| |
| | |
| == Notes ==
| |
| [[#top|top]]
| |
|
| |
|
| [[Category:API_Reference|U]] | | [[Category:API_Reference|U]] |
| [[Category:Scripting context]] | | [[Category:Scripting context]] |
| [[Category:Security]] | | [[Category:Security]] |