more pm28 fixes
[guerillascript.git] / main / modules / injector.js
blob3aa589e730f873d9f69e23173dfe4bf9c9c92af4
1 /*
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
5  *
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:
12  *
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.
16  *
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
23  * SOFTWARE.
24  *
25  * The above copyright notice and this permission notice shall be included in all
26  * copies or substantial portions of the Software.
27  */
28 ////////////////////////////////////////////////////////////////////////////////
29 uses("resource://gre/modules/XPCOMUtils.jsm");
31 let {closeStorageObjects, createSandbox, runInSandbox} = require("sbapi/sandbox");
33 let stripCredsRE = new RegExp("(://)([^:/]+)(:[^@/]+)?@");
35 //const conService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
36 //function logStr (str) conService.logStringMessage(str);
38 ////////////////////////////////////////////////////////////////////////////////
39 function runScripts (theWin, docStart) {
40   //logStr("000");
41   if (!addonOptions.active) {
42     //logStr("001");
43     return; // we are inactive
44   }
45   //logStr("002");
46   if (!theWin) return;
48   //logStr("003");
49   let theDoc = theWin.document;
50   if (!theDoc) return; //document not provided, it is undefined likely
51   if (!theDoc instanceof Ci.nsIDOMHTMLDocument) return; //not html document, so its likely an xul document
54   //logStr("004");
55   // When content does (e.g.) history.replacestate() in an inline script,
56   // the location.href changes between document-start and document-end time.
57   // But the content can call replacestate() much later, too.  The only way to
58   // be consistent is to ignore it.  Luckily, the  document.documentURI does
59   // _not_ change, so always use it when deciding whether to run scripts.
60   var url = theDoc.documentURI||"";
61   if (!scacheAPI.isGoodScheme(url)) return;
63   // ignore user/pass in the URL
64   url = url.replace(stripCredsRE, "$1");
66   let sclist = scacheAPI.scriptsForUrl(/*theDoc.location.href*/url, (theWin.frameElement ? true : false), (docStart ? "document-start" : "document-end"));
67   if (addonOptions.debugMode && sclist !== false) debuglog("document-"+(docStart ? "start" : "end")+" for "+url+" ("+(sclist ? sclist.length : 0)+" scripts)");
68   if (!sclist || sclist.length == 0) return;
69   if (addonOptions.debugMode) {
70     let s = "=== "+sclist.length+" scripts found for ["+url+"] ===";
71     for (let f = 0; f < sclist.length; ++f) s += "\n  #"+f+": '"+sclist[f].name+"'";
72     debuglog(s);
73   }
75   // each script is independent (expect unwrapped), so create separate sandboxes
76   let uwpsbox = false;
77   for (let nfo of sclist) {
78     if (nfo.unwrapped) {
79       // unwrapped script
80       if (addonOptions.debugMode) {
81         debuglog("["+url+"]: unwrapped script '"+nfo.name+"'");
82         //scacheAPI.dumpScriptNfo(nfo);
83       }
84       if (!uwpsbox) uwpsbox = createSandbox(theWin, nfo, url);
85       runInSandbox(uwpsbox, nfo);
86     } else {
87       // wrapped script
88       if (addonOptions.debugMode) {
89         debuglog("["+url+"]: wrapped script '"+nfo.name+"'");
90         //scacheAPI.dumpScriptNfo(nfo);
91       }
92       let sbox = createSandbox(theWin, nfo, url);
93       runInSandbox(sbox, nfo);
94     }
95   }
99 ////////////////////////////////////////////////////////////////////////////////
100 function ContentObserver () {}
103 ContentObserver.prototype.QueryInterface = XPCOMUtils.generateQI([Ci.nsIObserver]);
106 ContentObserver.prototype.contentLoad = function (evt) {
107   var contentWin = evt.target.defaultView;
108   // now that we've seen any first load event, stop listening for any more
109   contentWin.removeEventListener("DOMContentLoaded", gContentLoad, true);
110   contentWin.removeEventListener("load", gContentLoad, true);
111   //debuglog("document-end for "+contentWin.document.documentURI);
112   runScripts(contentWin, false);
116 ContentObserver.prototype.observe = function (aSubject, aTopic, aData) {
117   if (!addonOptions.active) return; // we are inactive
118   if (aTopic == "document-element-inserted") {
119     let doc = aSubject;
120     let win = doc && doc.defaultView;
121     if (!doc || !win) return;
122     if (!(doc instanceof Ci.nsIDOMHTMLDocument)) return; //not html document, so its likely an xul document
123     // do not try to inject scripts in chrome windows
124     if (win instanceof Ci.nsIDOMChromeWindow) return;
125     let url = doc.documentURI;
126     if (!scacheAPI.isGoodScheme(url)) return;
127     // listen for whichever kind of load event arrives first
128     win.addEventListener("DOMContentLoaded", gContentLoad, true);
129     win.addEventListener("load", gContentLoad, true);
130     runScripts(win, true);
131   } else {
132     logError("observe: "+aTopic);
133   }
137 ////////////////////////////////////////////////////////////////////////////////
138 var contentObserver = new ContentObserver(); //WARNING: don't change to `let`!
139 var gContentLoad = contentObserver.contentLoad.bind(contentObserver); //WARNING: don't change to `let`!
142 ////////////////////////////////////////////////////////////////////////////////
143 registerStartupHook("injector", function () {
144   Services.obs.addObserver(contentObserver, "document-element-inserted", false);
148 registerShutdownHook("injector", function () {
149   Services.obs.removeObserver(contentObserver, "document-element-inserted");
150   closeStorageObjects();
153 //logStr("********* INJECTOR *********");