moved some sources and icon to separate dirs
[guerillascript.git] / modules / sbapi / sandbox.js
blob101dbca667347c7a4156def087cf7ec778de13f1
1 /*
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
23 * SOFTWARE.
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) {
38 let baseUri = null;
39 if (typeof(base) === "string") {
40 baseUri = uriFromUrl(base);
41 } else if (base) {
42 baseUri = base;
44 try {
45 return ioSvc.newURI(url, null, baseUri);
46 } catch (e) {
47 return null;
52 ////////////////////////////////////////////////////////////////////////////////
53 let pu = false;
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);
66 if (!pu) {
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);
71 doc.adoptNode(frag);
72 doc.body.appendChild(frag);
73 return doc;
77 ////////////////////////////////////////////////////////////////////////////////
78 let uuidgen = false;
80 function genUUID () {
81 if (!uuidgen) {
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];
95 } else {
96 let res = new ScriptStorage(nfo);
97 storageObjects[nfo.name] = res;
98 return 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;
108 if (dbo.opened) {
109 if (guerillaOptions.debugMode) conlog("freeing storage object for '"+k+"'");
110 dbo.close();
113 storageObjects = {};
117 ////////////////////////////////////////////////////////////////////////////////
118 exports.createSandbox = function (domWin, nfo, url) {
119 let sandbox;
120 let scres = nfo.resources;
122 if (nfo.unwrapped) {
123 // create "unwrapped" sandbox
124 sandbox = Cu.Sandbox(domWin, {
125 sandboxName: "unwrapped",
126 sandboxPrototype: domWin/*.wrappedJSObject*/,
127 wantXrays: false,
129 // alias unsafeWindow for compatibility
130 Cu.evalInSandbox("const unsafeWindow = window;", sandbox);
131 } else {
132 // create "real" sandbox
133 sandbox = Cu.Sandbox(domWin, {
134 sandboxName: nfo.name,
135 sandboxPrototype: domWin/*.wrappedJSObject*/,
136 wantXrays: true,
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];
160 if (head) {
161 var style = doc.createElement("style");
162 style.textContent = cssstr;
163 style.type = "text/css";
164 head.appendChild(style);
165 return style;
167 return null;
168 }, domWin.document);
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!");
174 name = ""+name;
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!");
184 name = ""+name;
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));
191 // stubs
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 {}; }),
207 return sandbox;
211 exports.runInSandbox = function (sandbox, nfo) {
212 // eval the code, with anonymous wrappers when/if appropriate
213 function evalLazyWrap (code, fileName) {
214 try {
215 Cu.evalInSandbox(code, sandbox, "ECMAv5", fileName, 1);
216 } catch (e) {
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);
221 } else {
222 // otherwise raise
223 throw e;
228 // eval the code, with a try/catch to report errors cleanly
229 function evalNoThrow (code, fileName) {
230 try {
231 evalLazyWrap(code, fileName);
232 } catch (e) {
233 logException("UJS", e);
234 return false;
236 return true;
239 try {
240 // eval libraries
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;
247 // eval includes
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;
254 // eval main script
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");
261 } catch (e) {
262 logException("XUJS", e);