2 * Copyright 2015 Ketmar Dark <ketmar@ketmar.no-ip.org>
3 * Portions copyright 2004-2007 Aaron Boodman
4 * Contributors: See contributors list in install.rdf and CREDITS
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * Note that this license applies only to the Greasemonkey extension source
14 * files, not to the user scripts which it runs. User scripts are licensed
15 * separately by their authors.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * The above copyright notice and this permission notice shall be included in all
26 * copies or substantial portions of the Software.
28 ////////////////////////////////////////////////////////////////////////////////
29 uses("resource://gre/modules/XPCOMUtils.jsm");
31 let {closeStorageObjects
, createSandbox
, runInSandbox
} = require("sbapi/sandbox");
33 const stripCredsRE
= new RegExp("(://)([^:/]+)(:[^@/]+)?@");
36 ////////////////////////////////////////////////////////////////////////////////
37 let consoleActivated
= !addonOptions
.openConsole
;
39 function openConsole (win
) {
40 if (consoleActivated
) return;
41 consoleActivated
= true;
42 let inType
= "global:console";
43 let uri
= "chrome://global/content/console.xul";
44 let topWindow
= Services
.wm
.getMostRecentWindow(inType
);
48 win
.open(uri
, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
54 ////////////////////////////////////////////////////////////////////////////////
55 function runScripts (theWin
, docStart
) {
56 if (!addonOptions
.active
) return; // we are inactive
59 let theDoc
= theWin
.document
;
60 if (!theDoc
) return; //document not provided, it is undefined likely
61 if (!theDoc
instanceof Ci
.nsIDOMHTMLDocument
) return; //not html document, so its likely an xul document
64 // When content does (e.g.) history.replacestate() in an inline script,
65 // the location.href changes between document-start and document-end time.
66 // But the content can call replacestate() much later, too. The only way to
67 // be consistent is to ignore it. Luckily, the document.documentURI does
68 // _not_ change, so always use it when deciding whether to run scripts.
69 var url
= theWin
.document
.documentURI
;
70 if (!scacheAPI
.isGoodScheme(url
)) return;
72 // ignore user/pass in the URL
73 url
= url
.replace(stripCredsRE
, "$1");
75 let sclist
= scacheAPI
.scriptsForUrl(/*theDoc.location.href*/url
, (theWin
.frameElement
? true : false), (docStart
? "document-start" : "document-end"));
76 if (addonOptions
.debugMode
&& sclist
!== false) conlog("document-"+(docStart
? "start" : "end")+" for "+url
+" ("+(sclist
? sclist
.length
: 0)+" scripts)");
77 if (!sclist
|| sclist
.length
== 0) return;
78 if (addonOptions
.debugMode
) {
79 let s
= "=== "+sclist
.length
+" scripts found for ["+url
+"] ===";
80 for (let f
= 0; f
< sclist
.length
; ++f
) s
+= "\n #"+f
+": '"+sclist
[f
].name
+"'";
84 // each script is independent (expect unwrapped), so create separate sandboxes
86 for (let nfo
of sclist
) {
89 if (addonOptions
.debugMode
) {
90 conlog("["+url
+"]: unwrapped script '"+nfo
.name
+"'");
91 //scacheAPI.dumpScriptNfo(nfo);
93 if (!uwpsbox
) uwpsbox
= createSandbox(theWin
, nfo
, url
);
94 runInSandbox(uwpsbox
, nfo
);
97 if (addonOptions
.debugMode
) {
98 conlog("["+url
+"]: wrapped script '"+nfo
.name
+"'");
99 //scacheAPI.dumpScriptNfo(nfo);
101 let sbox
= createSandbox(theWin
, nfo
, url
);
102 runInSandbox(sbox
, nfo
);
108 ////////////////////////////////////////////////////////////////////////////////
109 function ContentObserver () {}
112 ContentObserver
.prototype.QueryInterface
= XPCOMUtils
.generateQI([Ci
.nsIObserver
]);
115 ContentObserver
.prototype.contentLoad = function (evt
) {
116 var contentWin
= evt
.target
.defaultView
;
117 // now that we've seen any first load event, stop listening for any more
118 contentWin
.removeEventListener("DOMContentLoaded", gContentLoad
, true);
119 contentWin
.removeEventListener("load", gContentLoad
, true);
120 //if (addonOptions.debugMode) conlog("document-end for "+contentWin.document.documentURI);
121 runScripts(contentWin
, false);
125 ContentObserver
.prototype.observe = function (aSubject
, aTopic
, aData
) {
126 if (!addonOptions
.active
) return; // we are inactive
127 if (aTopic
== "document-element-inserted") {
129 let win
= doc
&& doc
.defaultView
;
130 if (!doc
|| !win
) return;
131 if (!(doc
instanceof Ci
.nsIDOMHTMLDocument
)) return; //not html document, so its likely an xul document
132 let url
= doc
.documentURI
;
133 if (!scacheAPI
.isGoodScheme(url
)) return;
134 // listen for whichever kind of load event arrives first
135 win
.addEventListener("DOMContentLoaded", gContentLoad
, true);
136 win
.addEventListener("load", gContentLoad
, true);
137 runScripts(win
, true);
139 logError("observe: "+aTopic
);
144 ////////////////////////////////////////////////////////////////////////////////
145 var contentObserver
= new ContentObserver(); //WARNING: don't change to `let`!
146 var gContentLoad
= contentObserver
.contentLoad
.bind(contentObserver
); //WARNING: don't change to `let`!
149 ////////////////////////////////////////////////////////////////////////////////
150 registerStartupHook("injector", function () {
151 Services
.obs
.addObserver(contentObserver
, "document-element-inserted", false);
152 if (!isBootstrapped
) openConsole(window
);
156 registerShutdownHook("injector", function () {
157 Services
.obs
.removeObserver(contentObserver
, "document-element-inserted");
158 closeStorageObjects();