2 * Portions copyright 2004-2007 Aaron Boodman
3 * Copyright 2015 Ketmar Dark <ketmar@ketmar.no-ip.org>
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 let {GuerillaXmlHttpReqester
} = require("sbapi/xmlhttprequest");
30 let {ScriptStorage
} = require("sbapi/scriptstorage");
31 let {openTab
} = require("sbapi/opentab");
34 ////////////////////////////////////////////////////////////////////////////////
35 let ioSvc
= Cc
["@mozilla.org/network/io-service;1"].getService(Ci
.nsIIOService
);
37 function uriFromUrl (url
, base
) {
39 if (typeof(base
) === "string") {
40 baseUri
= uriFromUrl(base
);
45 return ioSvc
.newURI(url
, null, baseUri
);
52 ////////////////////////////////////////////////////////////////////////////////
55 function safeHTMLParser (domWin
, htmlstr
, baseUrl
) {
56 //conlog("domWin: "+domWin);
57 //conlog("htmlstr: "+htmlstr);
58 //conlog("baseUrl: "+baseUrl);
59 let doc
= domWin
.document
.implementation
.createDocument("", "", domWin
.document
.implementation
.createDocumentType("html", "", ""));
60 doc
.appendChild(doc
.createElement("html"));
61 doc
.documentElement
.appendChild(doc
.createElement("body"));
63 let baseUri
= null, frag
;
64 if (typeof(baseUrl
) !== "undefined") baseUri
= uriFromUrl(baseUrl
);
67 pu
= Cc
["@mozilla.org/parserutils;1"].createInstance(Ci
.nsIParserUtils
);
68 if (!pu
) { logError("FUCKED!"); return null; }
70 frag
= pu
.parseFragment(htmlstr
, 0, false, baseUri
, doc
.body
);
72 doc
.body
.appendChild(frag
);
77 ////////////////////////////////////////////////////////////////////////////////
82 uuidgen
= Cc
["@mozilla.org/uuid-generator;1"].createInstance(Ci
.nsIUUIDGenerator
);
83 if (!uuidgen
) throw new Error("no UUID generator available!");
85 return uuidgen
.generateUUID().toString();
89 ////////////////////////////////////////////////////////////////////////////////
90 let storageObjects
= {};
92 function getStorageObject (nfo
) {
93 if (nfo
.name
in storageObjects
) {
94 return storageObjects
[nfo
.name
];
96 let res
= new ScriptStorage(nfo
);
97 storageObjects
[nfo
.name
] = res
;
103 exports
.closeStorageObjects = function () {
104 for (let k
in storageObjects
) {
105 if (typeof(k
) != "string") continue;
106 let dbo
= storageObjects
[k
];
107 //if (typeof(dbo) != "object") continue;
109 if (guerillaOptions
.debugMode
) conlog("freeing storage object for '"+k
+"'");
117 ////////////////////////////////////////////////////////////////////////////////
118 exports
.createSandbox = function (domWin
, nfo
, url
) {
120 let scres
= nfo
.resources
;
123 // create "unwrapped" sandbox
124 sandbox
= Cu
.Sandbox(domWin
, {
125 sandboxName
: "unwrapped",
126 sandboxPrototype
: domWin
/*.wrappedJSObject*/,
129 // alias unsafeWindow for compatibility
130 Cu
.evalInSandbox("const unsafeWindow = window;", sandbox
);
132 // create "real" sandbox
133 sandbox
= Cu
.Sandbox(domWin
, {
134 sandboxName
: nfo
.name
,
135 sandboxPrototype
: domWin
/*.wrappedJSObject*/,
139 // Note that because waivers aren't propagated between origins, we need the
140 // unsafeWindow getter to live in the sandbox. See http://bugzil.la/1043958
141 let unsafeWindowGetter
= new sandbox
.Function("return (window.wrappedJSObject||window);");
142 Object
.defineProperty(sandbox
, "unsafeWindow", {get: unsafeWindowGetter
});
144 sandbox
.GM_generateUUID
= tieto(null, genUUID
);
145 sandbox
.GM_cryptoHash
= tieto(null, cryptoHash
);
147 //Object.defineProperty(sandbox, "GM_safeHTMLParser", {get: function () tieto(null, safeHTMLParser, domWin)});
148 sandbox
.GM_safeHTMLParser
= tieto(null, safeHTMLParser
, domWin
);
150 let scriptStorage
= getStorageObject(nfo
);
151 sandbox
.GM_getValue
= tieto(scriptStorage
, "getValue");
152 sandbox
.GM_setValue
= tieto(scriptStorage
, "setValue");
153 sandbox
.GM_deleteValue
= tieto(scriptStorage
, "deleteValue");
154 sandbox
.GM_listValues
= tieto(scriptStorage
, "listValues");
156 sandbox
.GM_xmlhttpRequest
= tieto(new GuerillaXmlHttpReqester(domWin
, url
, sandbox
), "contentStartRequest");
158 sandbox
.GM_addStyle
= tieto(null, function (doc
, cssstr
) {
159 var head
= doc
.getElementsByTagName("head")[0];
161 var style
= doc
.createElement("style");
162 style
.textContent
= cssstr
;
163 style
.type
= "text/css";
164 head
.appendChild(style
);
170 sandbox
.GM_openInTab
= tieto(null, openTab
, domWin
);
172 sandbox
.GM_getResourceText
= tieto(null, function (name
) {
173 if (typeof(name
) === "undefined") throw new Error("GM_getResourceText(): no name given!");
175 let rsrc
= scres
[name
];
176 if (!rsrc
) throw new Error("GM_getResourceText(): no resource found: '"+name
+"'");
177 return fileReadText(rsrc
.file
);
180 sandbox
.GM_getResourceURL
= tieto(null, function (name
) {
181 //logError("GM_getResourceURL(): stub!");
182 //throw new Error("GM_getResourceURL() not implemented");
183 if (typeof(name
) === "undefined") throw new Error("GM_getResourceText(): no name given!");
185 let rsrc
= scres
[name
];
186 if (!rsrc
) throw new Error("GM_getResourceText(): no resource found: '"+name
+"'");
187 let rawdata
= fileReadBinary(rsrc
.file
);
188 return "data:"+rsrc
.contenttype
+";base64,"+encodeURIComponent(btoa(rawdata
));
192 sandbox
.GM_registerMenuCommand
= tieto(null, function () { logError("GM_registerMenuCommand(): stub!"); });
193 sandbox
.GM_setClipboard
= tieto(null, function () { logError("GM_setClipboard(): stub!"); });
196 // provide log functions for both wrapped and unwrapped scripts
197 if (!nfo
.unwrapped
|| nfo
.wantlog
) {
198 sandbox
.conlog
= tieto(null, conlog
);
199 sandbox
.logError
= tieto(null, logError
);
200 if (!nfo
.unwrapped
) sandbox
.GM_log
= tieto(null, conlog
);
203 Object
.defineProperty(sandbox
, "GM_info", {
204 get: tieto(null, function () { logError("GM_info(): stub!"); return {}; }),
211 exports
.runInSandbox = function (sandbox
, nfo
) {
212 // eval the code, with anonymous wrappers when/if appropriate
213 function evalLazyWrap (code
, fileName
) {
215 Cu
.evalInSandbox(code
, sandbox
, "ECMAv5", fileName
, 1);
217 if ("return not in function" == e
.message
) {
218 // we never anon wrap unless forced to by a "return not in a function" error
219 logError("please, do not use `return` in top-level code in "+fileName
+":"+e
.lineNumber
);
220 Cu
.evalInSandbox("(function(){ "+code
+"\n})()", sandbox
, "ECMAv5", fileName
, 1);
228 // eval the code, with a try/catch to report errors cleanly
229 function evalNoThrow (code
, fileName
) {
231 evalLazyWrap(code
, fileName
);
233 logException("UJS", e
);
241 for (let fl
of nfo
.libs
) {
242 if (!fl
.exists() || fl
.isDirectory() || !fl
.isReadable()) return;
243 let text
= fileReadText(fl
);
244 //conlog("*** lib: ", fl.path);
245 if (!evalNoThrow(text
, "libs/"+fl
.name
+".js")) return;
248 for (let fl
of nfo
.incs
) {
249 if (!fl
.exists() || fl
.isDirectory() || !fl
.isReadable()) return;
250 let text
= fileReadText(fl
);
251 //conlog("*** inc: ", fl.path);
252 if (!evalNoThrow(text
, nfo
.name
+"/"+fl
.name
+".js")) return;
256 if (!nfo
.file
.exists() || nfo
.file
.isDirectory() || !nfo
.file
.isReadable()) return;
257 let text
= fileReadText(nfo
.file
);
258 //conlog("*** main: ", nfo.file.path);
259 evalNoThrow(text
, nfo
.name
+".js");
262 logException("XUJS", e
);