diff options
Diffstat (limited to 'data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish')
6 files changed, 436 insertions, 0 deletions
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/GM_xmlhttpRequester.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/GM_xmlhttpRequester.js new file mode 100644 index 0000000..8ca3f5b --- /dev/null +++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/GM_xmlhttpRequester.js @@ -0,0 +1,238 @@ +'use strict'; + +function Scriptish_stringBundle(a) a; + +const {Cc, Ci, Cu, Cr} = require("chrome"); +var {Instances} = require("../chrome/instances"); +var {XPCOMUtils} = require("../chrome/xpcom-utils"); +var {NetUtil} = require("../chrome/net-utils"); + +const MIME_JSON = /^(application|text)\/(?:x-)?json/i; + +/** + * Abstract base class for (chained) request notification callback overrides + * + * Use such overrides sparely, as the individual request performance might + * degrade quite a bit. + * + * @param req XMLHttpRequest (chrome) + * @author Nils Maier + */ +function NotificationCallbacks(req) { + throw new Error("trying to initiate an abstract NotificationCallbacks"); +} +NotificationCallbacks.prototype = { + init: function(req) { + // rewrite notification callbacks + this._channel = req.channel; + this._notificationCallbacks = this._channel.notificationCallbacks; + this._channel.notificationCallbacks = this; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]), + getInterface: function(iid) { + try { + return this.query(iid); + } + catch (ex) { + return this.queryOriginal(iid); + } + }, + queryOriginal: function(iid) { + if (this._notificationCallbacks) { + return this._notificationCallbacks.getInterface(iid); + } + throw Cr.NS_ERROR_NO_INTERFACE; + } +} + +/** + * Ignore (specific) redirects + * @param req XMLHttpRequest (chrome) + * @author Nils Maier + */ +function IgnoreRedirect(req, ignoreFlags) { + this.init(req); + this.ignoreFlags = ignoreFlags; +} +IgnoreRedirect.prototype = { + __proto__: NotificationCallbacks.prototype, + query: XPCOMUtils.generateQI([Ci.nsIChannelEventSink]), + asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) { + if (this.ignoreFlags & flags) { + // must throw here, not call callback.onRedirectVerifyCallback, + // or else it will completely cancel the request + throw Cr.NS_ERROR_UNEXPECTED; + } + + try { + let ces = this.queryOriginal(Ci.nsIChannelEventSink); + if (ces) { + ces.asyncOnChannelRedirect(oldChannel, newChannel, flags, callback); + return; + } + } + catch (ex) {} + + callback.onRedirectVerifyCallback(Cr.NS_OK); + } +}; + + +function GM_xmlhttpRequester(unsafeContentWin, originUrl, aScript) { + this.unsafeContentWin = unsafeContentWin; + this.originUrl = originUrl; + this.script = aScript; +} +exports.GM_xmlhttpRequester = GM_xmlhttpRequester; + +// this function gets called by user scripts in content security scope to +// start a cross-domain xmlhttp request. +// +// details should look like: +// {method,url,onload,onerror,onreadystatechange,headers,data} +// headers should be in the form {name:value,name:value,etc} +// can't support mimetype because i think it's only used for forcing +// text/xml and we can't support that +GM_xmlhttpRequester.prototype.contentStartRequest = function(details) { + try { + // Validate and parse the (possibly relative) given URL. + var uri = NetUtil.newURI(details.url, null, NetUtil.newURI(this.originUrl)); + var url = uri.spec; + } catch (e) { + // A malformed URL won't be parsed properly. + //throw new Error(Scriptish_stringBundle("error.api.reqURL") + ": " + details.url); + console.error(e); + } + + // check if the script is allowed to access the url + if (!this.script.matchesDomain(url)) + throw new Error( + "User script is attempting access to restricted domain '" + uri.host + "'", + this.script.fileURL); + + // This is important - without it, GM_xmlhttpRequest can be used to get + // access to things like files and chrome. Careful. + switch (uri.scheme) { + case "http": + case "https": + case "ftp": + var req = Instances.xhr; + this.chromeStartRequest(url, details, req); + break; + default: + throw new Error(Scriptish_stringBundle("error.api.reqURL.scheme") + ": " + details.url); + } + + return { + abort: function() { + req.abort(); + } + }; +}; + +// this function is intended to be called in chrome's security context, so +// that it can access other domains without security warning +GM_xmlhttpRequester.prototype.chromeStartRequest = + function(safeUrl, details, req) { + this.setupRequestEvent(this.unsafeContentWin, req, "onload", details); + this.setupRequestEvent(this.unsafeContentWin, req, "onerror", details); + this.setupRequestEvent( + this.unsafeContentWin, req, "onreadystatechange", details); + + if (details.mozBackgroundRequest) req.mozBackgroundRequest = true; + + req.open( + details.method || "GET", + safeUrl, + true, + details.user || "", + details.password || "" + ); + + if (details.overrideMimeType) req.overrideMimeType(details.overrideMimeType); + + if (details.ignoreCache) + req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; // bypass cache + + if (details.ignoreRedirect) + new IgnoreRedirect(req, + Ci.nsIChannelEventSink.REDIRECT_TEMPORARY | Ci.nsIChannelEventSink.REDIRECT_PERMANENT); + if (details.ignoreTempRedirect) + new IgnoreRedirect(req, Ci.nsIChannelEventSink.REDIRECT_TEMPORARY); + if (details.ignorePermanentRedirect) + new IgnoreRedirect(req, Ci.nsIChannelEventSink.REDIRECT_PERMANENT); + + let redirectionLimit = null; + if (details.failOnRedirect) { + redirectionLimit = 0; + } + if ("redirectionLimit" in details) { + if (details.redirectionLimit < 0 || details.redirectionLimit > 10) { + throw new Error("redirectionLimit must be within (0, 10), but it is " + details.redirectionLimit); + } + redirectionLimit = details.redirectionLimit; + } + if (redirectionLimit !== null && req.channel instanceof Ci.nsIHttpChannel) { + req.channel.redirectionLimit = redirectionLimit; + } + + if (details.headers) { + var headers = details.headers; + + for (var prop in headers) { + if (Object.prototype.hasOwnProperty.call(headers, prop)) + req.setRequestHeader(prop, headers[prop]); + } + } + + var body = details.data ? details.data : null; + if (details.binary) req.sendAsBinary(body); + else req.send(body); +} + +// arranges for the specified 'event' on xmlhttprequest 'req' to call the +// method by the same name which is a property of 'details' in the content +// window's security context. +GM_xmlhttpRequester.prototype.setupRequestEvent = + function(unsafeContentWin, req, event, details) { + var origMimeType = details.overrideMimeType; + var script = this.script; + + if (details[event]) { + req[event] = function() { + var responseState = { + // can't support responseXML because security won't + // let the browser call properties on it + responseText: req.responseText, + readyState: req.readyState, + responseHeaders: null, + status: null, + statusText: null, + finalUrl: null + }; + if (4 == req.readyState && 'onerror' != event) { + responseState.responseHeaders = req.getAllResponseHeaders(); + responseState.status = req.status; + responseState.statusText = req.statusText; + if (MIME_JSON.test(origMimeType) + || MIME_JSON.test(details.overrideMimeType) + || MIME_JSON.test(req.channel.contentType)) { + try { + responseState.responseJSON = JSON.parse(req.responseText); + } catch (e) { + responseState.responseJSON = {}; + } + } + responseState.finalUrl = req.channel.URI.spec; + } + + GM_apiSafeCallback( + unsafeContentWin, script, details, details[event], [responseState]); + } + } +} + +// TODO: replace!! +function GM_apiSafeCallback(aWindow, aScript, aThis, aCb, aArgs) { + aCb.apply(aThis, aArgs); +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/convert-2-regexp.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/convert-2-regexp.js new file mode 100644 index 0000000..9b79f30 --- /dev/null +++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/convert-2-regexp.js @@ -0,0 +1,23 @@ +'use strict'; + +const RE_REGEXP = /^\/(.*)\/(i)?$/; +const RE_ESCAPE = /[{}()\[\]\\^$.?]/g; +const RE_WILD = /\*+/g; +const RE_TLD = /^\^[^\/]*(?:\/\/)?[^\/]*\\\.tld(?:\/.*)?\$$/; + +exports.convert2RegExp = function Scriptish_convert2RegExp(aPattern, aNoTLD, forceString) { + var s = aPattern.toString().trim(), m; + + // Already a regexp? + if (!forceString && (m = s.match(RE_REGEXP))) { + return new RegExp(m[1], m[2]); + } + + var res = "^" + s + .replace(RE_ESCAPE, "\\$&") + .replace(RE_WILD, ".*") + + "$"; + var regExp = new RegExp(res, "i"); + regExp.isTLD = !aNoTLD && RE_TLD.test(res); + return regExp; +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/greasemonkey-api.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/greasemonkey-api.js new file mode 100644 index 0000000..e465883 --- /dev/null +++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/greasemonkey-api.js @@ -0,0 +1,76 @@ +'use strict'; + +var { Services } = require("services"); +var prefService = require("preferences-service"); +var tabs = require("tabs"); +var clipboard = require("clipboard"); +var {GM_xmlhttpRequester} = require("GM_xmlhttpRequester"); + +const NS_XHTML = "http://www.w3.org/1999/xhtml"; + +function GM_API(aScript, aURL, aWinID, aSafeWin, aUnsafeContentWin, aChromeWin) { + var document = aSafeWin.document; + var windowID = aWinID; + var xhr = new GM_xmlhttpRequester(aUnsafeContentWin, aURL, aScript); + + this.GM_addStyle = function GM_addStyle(css) { + var head = document.getElementsByTagName("head")[0]; + var style = document.createElement("style"); + if (head) { + style.textContent = css; + style.type = "text/css"; + head.appendChild(style); + } + return style; + }; + + // TODO: use simple storage + this.GM_getValue = function GM_getValue(name, defVal) { + return prefService.get(aScript.prefPrefix + name, defVal); + }; + this.GM_setValue = function GM_setValue(name, val) { + return prefService.set(aScript.prefPrefix + name, val); + }; + + this.GM_safeHTMLParser = function GM_safeHTMLParser(aHTMLStr) { + //if (!GM_apiLeakCheck("GM_safeHTMLParser")) return; + let doc = document.implementation.createDocument(NS_XHTML, "html", null); + let body = document.createElementNS(NS_XHTML, "body"); + doc.documentElement.appendChild(body); + body.appendChild(Services.suhtml.parseFragment(aHTMLStr, false, null, body)); + return doc; + } + + this.GM_xmlhttpRequest = function GM_xmlhttpRequest() { + //if (!GM_apiLeakCheck("GM_xmlhttpRequest")) return; + return xhr.contentStartRequest.apply(xhr, arguments); + }; +}; +exports.GM_API = GM_API; + +GM_API.prototype.GM_openInTab = + function GM_openInTab(aURL, aLoadInBackground, aReuse) { + if (aReuse) { + for each (var tab in tabs) { + if (tab.url == aURL) { + if (!aLoadInBackground) + tab.activate(); + return; + } + } + } + + tabs.open({ + url: aURL, + inBackground: aLoadInBackground + }); +}; + +GM_API.prototype.GM_setClipboard = function GM_setClipboard(aData, aType) { + return clipboard.set(aData, aType); +}; + +GM_API.prototype.GM_generateUUID = function GM_generateUUID() ( + Services.uuid.generateUUID().toString()); + +GM_API.prototype.GM_registerMenuCommand = function() {}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-header-parser.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-header-parser.js new file mode 100644 index 0000000..41f7ffd --- /dev/null +++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-header-parser.js @@ -0,0 +1,31 @@ +'use strict'; + +exports.parse = function(aSource) { + var headers = {}; + var foundMeta = false; + var line; + + // do not 'optimize' by reusing this reg exp! it should not be reused! + var metaRegExp = /\/\/[ \t]*(?:==(\/?UserScript)==|\@(\S+)(?:[ \t]+([^\r\f\n]+))?)/g; + + // read one line at a time looking for start meta delimiter or EOF + while (line = metaRegExp.exec(aSource)) { + if (line[1]) { + if ("userscript" == line[1].toLowerCase()) { + foundMeta = true; // start + continue; + } else { + break; // done + } + } + if (!foundMeta) continue; + + var header = line[2].toLowerCase(); + var value = line[3]; + + if (!headers[header]) headers[header] = [value]; + else headers[header].push(value); + } + + return headers; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-manager.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-manager.js new file mode 100644 index 0000000..f1eec70 --- /dev/null +++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-manager.js @@ -0,0 +1,44 @@ +'use strict'; + +var { Services } = require("../chrome/services"); +var obs = require("sdk/deprecated/observer-service"); + +var sandboxFactory = require("./userscript-sandbox"); + +var userscripts = []; + +// TODO: register obs only when there is a userscript +obs.add("content-document-global-created", docReady); +obs.add("chrome-document-global-created", docReady); + +function docReady(safeWin, data) { + let href = (safeWin.location.href + || (safeWin.frameElement && safeWin.frameElement.src)) || ""; + + safeWin.addEventListener("load", function() { + userscripts.forEach(function(script) { + // check that the userscript should be run on this page + if (!script.matchesURL(href)) + return; + + sandboxFactory.evalInSandbox( + script._source, + sandboxFactory.createSandbox(safeWin, script, href), + script.jsversion); + }); + }, true); +} + +exports.register = function(aScript) { + unregister(aScript); + userscripts.push(aScript); +}; + +var unregister = exports.unregister = function unregister(aScript) { + for (var i = userscripts.length - 1; ~i; i--) { + if (userscripts[i] == aScript) { + userscripts.splice(i, 1); + break; + } + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-sandbox.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-sandbox.js new file mode 100644 index 0000000..1c92066 --- /dev/null +++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scriptish/userscript-sandbox.js @@ -0,0 +1,24 @@ +'use strict'; + +var { Cc, Ci, Cu } = require('chrome'); +var {GM_API} = require("./greasemonkey-api"); + +exports.createSandbox = function createSandbox(safeWin, userScript, aURL) { + var script = userScript.source; + var sandbox = new Cu.Sandbox(safeWin); + sandbox.window = safeWin; + sandbox.document = sandbox.window.document; + sandbox.__proto__ = safeWin; + var api = new GM_API(userScript, aURL, null, safeWin, safeWin.wrappedJSObject); + + for (var key in api) { + sandbox[key] = api[key]; + } + + return sandbox; +}; + +exports.evalInSandbox = function(code, sandbox, jsVersion) { + jsVersion = jsVersion || "1.8"; + Cu.evalInSandbox("(function(){"+code+"})();", sandbox, jsVersion); +};
\ No newline at end of file |