commit e4a3586a14996bbece3b26c9e3b7704ea6af8615 parent 4dbc2fae927bb02ef243c87938e638af9afee8fa Author: Ruben Rodriguez <ruben@gnu.org> Date: Sat, 28 Nov 2015 15:24:36 -0600 LibreJS upgraded to 6.0.10 Diffstat:
328 files changed, 16671 insertions(+), 10752 deletions(-)
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/gpl-3.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/COPYING diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/bootstrap.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/bootstrap.js @@ -1,350 +1,11 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp - -'use strict'; - -// IMPORTANT: Avoid adding any initialization tasks here, if you need to do -// something before add-on is loaded consider addon/runner module instead! - -const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu, - results: Cr, manager: Cm } = Components; -const ioService = Cc['@mozilla.org/network/io-service;1']. - getService(Ci.nsIIOService); -const resourceHandler = ioService.getProtocolHandler('resource'). - QueryInterface(Ci.nsIResProtocolHandler); -const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')(); -const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1']. - getService(Ci.mozIJSSubScriptLoader); -const prefService = Cc['@mozilla.org/preferences-service;1']. - getService(Ci.nsIPrefService). - QueryInterface(Ci.nsIPrefBranch); -const appInfo = Cc["@mozilla.org/xre/app-info;1"]. - getService(Ci.nsIXULAppInfo); -const vc = Cc["@mozilla.org/xpcom/version-comparator;1"]. - getService(Ci.nsIVersionComparator); - - -const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable', - 'install', 'uninstall', 'upgrade', 'downgrade' ]; - -const bind = Function.call.bind(Function.bind); - -let loader = null; -let unload = null; -let cuddlefishSandbox = null; -let nukeTimer = null; - -let resourceDomains = []; -function setResourceSubstitution(domain, uri) { - resourceDomains.push(domain); - resourceHandler.setSubstitution(domain, uri); -} - -// Utility function that synchronously reads local resource from the given -// `uri` and returns content string. -function readURI(uri) { - let ioservice = Cc['@mozilla.org/network/io-service;1']. - getService(Ci.nsIIOService); - let channel = ioservice.newChannel(uri, 'UTF-8', null); - let stream = channel.open(); - - let cstream = Cc['@mozilla.org/intl/converter-input-stream;1']. - createInstance(Ci.nsIConverterInputStream); - cstream.init(stream, 'UTF-8', 0, 0); - - let str = {}; - let data = ''; - let read = 0; - do { - read = cstream.readString(0xffffffff, str); - data += str.value; - } while (read != 0); - - cstream.close(); - - return data; -} - -// We don't do anything on install & uninstall yet, but in a future -// we should allow add-ons to cleanup after uninstall. -function install(data, reason) {} -function uninstall(data, reason) {} - -function startup(data, reasonCode) { - try { - let reason = REASON[reasonCode]; - // URI for the root of the XPI file. - // 'jar:' URI if the addon is packed, 'file:' URI otherwise. - // (Used by l10n module in order to fetch `locale` folder) - let rootURI = data.resourceURI.spec; - - // TODO: Maybe we should perform read harness-options.json asynchronously, - // since we can't do anything until 'sessionstore-windows-restored' anyway. - let options = JSON.parse(readURI(rootURI + './harness-options.json')); - - let id = options.jetpackID; - let name = options.name; - - // Clean the metadata - options.metadata[name]['permissions'] = options.metadata[name]['permissions'] || {}; - - // freeze the permissionss - Object.freeze(options.metadata[name]['permissions']); - // freeze the metadata - Object.freeze(options.metadata[name]); - - // Register a new resource 'domain' for this addon which is mapping to - // XPI's `resources` folder. - // Generate the domain name by using jetpack ID, which is the extension ID - // by stripping common characters that doesn't work as a domain name: - let uuidRe = - /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/; - - let domain = id. - toLowerCase(). - replace(/@/g, '-at-'). - replace(/\./g, '-dot-'). - replace(uuidRe, '$1'); - - let prefixURI = 'resource://' + domain + '/'; - let resourcesURI = ioService.newURI(rootURI + '/resources/', null, null); - setResourceSubstitution(domain, resourcesURI); - - // Create path to URLs mapping supported by loader. - let paths = { - // Relative modules resolve to add-on package lib - './': prefixURI + name + '/lib/', - './tests/': prefixURI + name + '/tests/', - '': 'resource://gre/modules/commonjs/' - }; - - // Maps addon lib and tests ressource folders for each package - paths = Object.keys(options.metadata).reduce(function(result, name) { - result[name + '/'] = prefixURI + name + '/lib/' - result[name + '/tests/'] = prefixURI + name + '/tests/' - return result; - }, paths); - - // We need to map tests folder when we run sdk tests whose package name - // is stripped - if (name == 'addon-sdk') - paths['tests/'] = prefixURI + name + '/tests/'; - - let useBundledSDK = options['force-use-bundled-sdk']; - if (!useBundledSDK) { - try { - useBundledSDK = prefService.getBoolPref("extensions.addon-sdk.useBundledSDK"); - } - catch (e) { - // Pref doesn't exist, allow using Firefox shipped SDK - } - } - - // Starting with Firefox 21.0a1, we start using modules shipped into firefox - // Still allow using modules from the xpi if the manifest tell us to do so. - // And only try to look for sdk modules in xpi if the xpi actually ship them - if (options['is-sdk-bundled'] && - (vc.compare(appInfo.version, '21.0a1') < 0 || useBundledSDK)) { - // Maps sdk module folders to their resource folder - paths[''] = prefixURI + 'addon-sdk/lib/'; - // test.js is usually found in root commonjs or SDK_ROOT/lib/ folder, - // so that it isn't shipped in the xpi. Keep a copy of it in sdk/ folder - // until we no longer support SDK modules in XPI: - paths['test'] = prefixURI + 'addon-sdk/lib/sdk/test.js'; - } - - // Retrieve list of module folder overloads based on preferences in order to - // eventually used a local modules instead of files shipped into Firefox. - let branch = prefService.getBranch('extensions.modules.' + id + '.path'); - paths = branch.getChildList('', {}).reduce(function (result, name) { - // Allows overloading of any sub folder by replacing . by / in pref name - let path = name.substr(1).split('.').join('/'); - // Only accept overloading folder by ensuring always ending with `/` - if (path) path += '/'; - let fileURI = branch.getCharPref(name); - - // On mobile, file URI has to end with a `/` otherwise, setSubstitution - // takes the parent folder instead. - if (fileURI[fileURI.length-1] !== '/') - fileURI += '/'; - - // Maps the given file:// URI to a resource:// in order to avoid various - // failure that happens with file:// URI and be close to production env - let resourcesURI = ioService.newURI(fileURI, null, null); - let resName = 'extensions.modules.' + domain + '.commonjs.path' + name; - setResourceSubstitution(resName, resourcesURI); - - result[path] = 'resource://' + resName + '/'; - return result; - }, paths); - - // Make version 2 of the manifest - let manifest = options.manifest; - - // Import `cuddlefish.js` module using a Sandbox and bootstrap loader. - let cuddlefishPath = 'loader/cuddlefish.js'; - let cuddlefishURI = 'resource://gre/modules/commonjs/sdk/' + cuddlefishPath; - if (paths['sdk/']) { // sdk folder has been overloaded - // (from pref, or cuddlefish is still in the xpi) - cuddlefishURI = paths['sdk/'] + cuddlefishPath; - } - else if (paths['']) { // root modules folder has been overloaded - cuddlefishURI = paths[''] + 'sdk/' + cuddlefishPath; - } - - cuddlefishSandbox = loadSandbox(cuddlefishURI); - let cuddlefish = cuddlefishSandbox.exports; - - // Normalize `options.mainPath` so that it looks like one that will come - // in a new version of linker. - let main = options.mainPath; - - unload = cuddlefish.unload; - loader = cuddlefish.Loader({ - paths: paths, - // modules manifest. - manifest: manifest, - - // Add-on ID used by different APIs as a unique identifier. - id: id, - // Add-on name. - name: name, - // Add-on version. - version: options.metadata[name].version, - // Add-on package descriptor. - metadata: options.metadata[name], - // Add-on load reason. - loadReason: reason, - - prefixURI: prefixURI, - // Add-on URI. - rootURI: rootURI, - // options used by system module. - // File to write 'OK' or 'FAIL' (exit code emulation). - resultFile: options.resultFile, - // Arguments passed as --static-args - staticArgs: options.staticArgs, - // Add-on preferences branch name - preferencesBranch: options.preferencesBranch, - - // Arguments related to test runner. - modules: { - '@test/options': { - allTestModules: options.allTestModules, - iterations: options.iterations, - filter: options.filter, - profileMemory: options.profileMemory, - stopOnError: options.stopOnError, - verbose: options.verbose, - parseable: options.parseable, - checkMemory: options.check_memory, - } - } - }); - - let module = cuddlefish.Module('sdk/loader/cuddlefish', cuddlefishURI); - let require = cuddlefish.Require(loader, module); - - require('sdk/addon/runner').startup(reason, { - loader: loader, - main: main, - prefsURI: rootURI + 'defaults/preferences/prefs.js' - }); - } catch (error) { - dump('Bootstrap error: ' + - (error.message ? error.message : String(error)) + '\n' + - (error.stack || error.fileName + ': ' + error.lineNumber) + '\n'); - throw error; - } -}; - -function loadSandbox(uri) { - let proto = { - sandboxPrototype: { - loadSandbox: loadSandbox, - ChromeWorker: ChromeWorker - } - }; - let sandbox = Cu.Sandbox(systemPrincipal, proto); - // Create a fake commonjs environnement just to enable loading loader.js - // correctly - sandbox.exports = {}; - sandbox.module = { uri: uri, exports: sandbox.exports }; - sandbox.require = function (id) { - if (id !== "chrome") - throw new Error("Bootstrap sandbox `require` method isn't implemented."); - - return Object.freeze({ Cc: Cc, Ci: Ci, Cu: Cu, Cr: Cr, Cm: Cm, - CC: bind(CC, Components), components: Components, - ChromeWorker: ChromeWorker }); - }; - scriptLoader.loadSubScript(uri, sandbox, 'UTF-8'); - return sandbox; -} - -function unloadSandbox(sandbox) { - if ("nukeSandbox" in Cu) - Cu.nukeSandbox(sandbox); -} - -function setTimeout(callback, delay) { - let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - timer.initWithCallback({ notify: callback }, delay, - Ci.nsITimer.TYPE_ONE_SHOT); - return timer; -} - -function shutdown(data, reasonCode) { - let reason = REASON[reasonCode]; - if (loader) { - unload(loader, reason); - unload = null; - - // Don't waste time cleaning up if the application is shutting down - if (reason != "shutdown") { - // Avoid leaking all modules when something goes wrong with one particular - // module. Do not clean it up immediatly in order to allow executing some - // actions on addon disabling. - // We need to keep a reference to the timer, otherwise it is collected - // and won't ever fire. - nukeTimer = setTimeout(nukeModules, 1000); - - // Bug 944951 - bootstrap.js must remove the added resource: URIs on unload - resourceDomains.forEach(domain => { - resourceHandler.setSubstitution(domain, null); - }) - } - } -}; - -function nukeModules() { - nukeTimer = null; - // module objects store `exports` which comes from sandboxes - // We should avoid keeping link to these object to avoid leaking sandboxes - for (let key in loader.modules) { - delete loader.modules[key]; - } - // Direct links to sandboxes should be removed too - for (let key in loader.sandboxes) { - let sandbox = loader.sandboxes[key]; - delete loader.sandboxes[key]; - // Bug 775067: From FF17 we can kill all CCW from a given sandbox - unloadSandbox(sandbox); - } - loader = null; - - // both `toolkit/loader` and `system/xul-app` are loaded as JSM's via - // `cuddlefish.js`, and needs to be unloaded to avoid memory leaks, when - // the addon is unload. - - unloadSandbox(cuddlefishSandbox.loaderSandbox); - unloadSandbox(cuddlefishSandbox.xulappSandbox); - - // Bug 764840: We need to unload cuddlefish otherwise it will stay alive - // and keep a reference to this compartment. - unloadSandbox(cuddlefishSandbox); - cuddlefishSandbox = null; -} +"use strict"; + +const { utils: Cu } = Components; +const rootURI = __SCRIPT_URI_SPEC__.replace("bootstrap.js", ""); +const COMMONJS_URI = "resource://gre/modules/commonjs"; +const { require } = Cu.import(COMMONJS_URI + "/toolkit/require.js", {}); +const { Bootstrap } = require(COMMONJS_URI + "/sdk/addon/bootstrap.js"); +var { startup, shutdown, install, uninstall } = new Bootstrap(rootURI); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/README b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/README diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/assets/css/style.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/assets/css/style.css diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/assets/images/README b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/assets/images/README diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/assets/images/complain-button3.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/assets/images/complain-button3.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/assets/images/complain.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/assets/images/complain.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/assets/images/info-title.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/assets/images/info-title.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/assets/images/separator.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/assets/images/separator.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/assets/images/torchy2.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/assets/images/torchy2.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/chrome_worker/parser/jsdefs.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/chrome_worker/parser/jsdefs.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/chrome_worker/parser/jslex.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/chrome_worker/parser/jslex.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/chrome_worker/parser/jsparse.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/chrome_worker/parser/jsparse.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/chrome_worker/parser/parse.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/chrome_worker/parser/parse.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/complain/contact_finder.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/complain/contact_finder.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/complain/contact_regex.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/complain/contact_regex.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/complain/link_types.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/complain/link_types.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/complain/pagemod_finder.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/complain/pagemod_finder.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/complain/worker_finder.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/complain/worker_finder.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/content/README b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/content/README diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/content/background-panel.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/content/background-panel.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/content/display-panel.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/content/display-panel.html @@ -0,0 +1,72 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>Display JS Monitoring Panel</title> +<link rel="stylesheet" type="text/css" href="./panel-styles.css"/> + +<!-- /** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2014 Loic J. Duros + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +--> +</head> + +<body> + <div class="title-area"> + <div> + <a class="libre" + id="ljs-settings" + href="javascript:void" + title="LibreJS Whitelist Settings"> + <h1 class="libre">LibreJS</h1> + </a> + </div> + <div> + <a target="_blank" href="https://www.gnu.org/software/librejs/" + id="librejs-web-link" + >gnu.org/software/librejs</a> + </div> + <div> + <strong>LibreJS 6.0.10</strong> + </div> + </div> + + <div id="info"> + <div id="dryrun"> + <h2 class="dryrun-js"></h2> + <ul class="dryrun-js"></ul> + </div> + + <div id="accepted"> + <h2 class="accepted-js"></h2> + <ul class="accepted-js"></ul> + </div> + + <div id="blocked"> + <h2 class="blocked-js"></h2> + <ul class="blocked-js"> + </div> + + <div id="librejs-web-labels-pages"> + <h2></h2> + <ul></ul> + </div> + </div> +</body> +</html> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/content/librejs-title-old.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/content/librejs-title-old.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/content/librejs-title.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/content/librejs-title.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/content/panel-styles.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/content/panel-styles.css diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/main_panel.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/display_panel/main_panel.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/images/gnu-icon-white.ico b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/images/gnu-icon-white.ico Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/images/gnu-icon.ico b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/images/gnu-icon.ico Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/images/gnu-icon.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/images/gnu-icon.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/librejs-settings.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/librejs-settings.html diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/Boost-1.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/Boost-1.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/ISC.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/ISC.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/IntelACPI.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/IntelACPI.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/agpl-3.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/agpl-3.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/apache-2.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/apache-2.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/artistic-2.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/artistic-2.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/bsd-3-clause.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/bsd-3-clause.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/cc0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/cc0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/clear-bsd.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/clear-bsd.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/cpal-1.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/cpal-1.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/create-magnets.sh b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/create-magnets.sh diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/epl-1.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/epl-1.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/expat.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/expat.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/freebsd.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/freebsd.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/gpl-2.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/gpl-2.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/gpl-3.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/gpl-3.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/illinois-NCSA.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/illinois-NCSA.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/imlib2.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/imlib2.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/lgpl-2.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/lgpl-2.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/lgpl-2.1.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/lgpl-2.1.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/lgpl-3.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/lgpl-3.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/magnet-links.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/magnet-links.txt @@ -0,0 +1,29 @@ + +magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt +magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt +magnet:?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt +magnet:?xt=urn:btih:89a97c535628232f2f3888c2b7b8ffd4c078cec0&dn=Boost-1.0.txt +magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt +magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt +magnet:?xt=urn:btih:e8823381a12cbaec8042d8f5928ed9ca427ae6ed&dn=clear-bsd.txt +magnet:?xt=urn:btih:84143bc45939fc8fa42921d619a95462c2031c5c&dn=cpal-1.0.txt +magnet:?xt=urn:btih:4c6a2ad0018cd461e9b0fc44e1b340d2c1828b22&dn=epl-1.0.txt +magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt +magnet:?xt=urn:btih:0c9737ee7c3f64a549ae792605960b900d0bab7f&dn=freebsd.txt +magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt +magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt +magnet:?xt=urn:btih:035da57b2e51467406d7f737ce130844ceb555e1&dn=illinois-NCSA.txt +magnet:?xt=urn:btih:34b1392ce6108db166bd9ee4a37e655c67891e5b&dn=imlib2.txt +magnet:?xt=urn:btih:3254dcf4f9d9dadad8dfb4951177854d5d0e2491&dn=IntelACPI.txt +magnet:?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt +magnet:?xt=urn:btih:fcd495f3ca5fb96b147041401bcf213eec0a6439&dn=lgpl-2.0.txt +magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt +magnet:?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt +magnet:?xt=urn:btih:2f25cfbac271643d1e41a754034e8daedeb8a281&dn=magnet-links.txt +magnet:?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt +magnet:?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt +magnet:?xt=urn:btih:5866afca5f37889c0c1fdd108f4922d4fcdb5e3d&dn=unlicense.txt +magnet:?xt=urn:btih:478974f4d41c3fa84c4befba25f283527fad107d&dn=upl-1.0.txt +magnet:?xt=urn:btih:48429d8ae6b908f46e0e6aeabf2130688ef2f93a&dn=wtfpl.txt +magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt +magnet:?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/mpl-2.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/mpl-2.0.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/public-domain.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/public-domain.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/Boost-1.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/Boost-1.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/ISC.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/ISC.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/IntelACPI.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/IntelACPI.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/agpl-3.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/agpl-3.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/apache-2.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/apache-2.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/artistic-2.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/artistic-2.0.txt.torrent Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/bsd-3-clause.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/bsd-3-clause.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/cc0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/cc0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/clear-bsd.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/clear-bsd.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/cpal-1.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/cpal-1.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/epl-1.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/epl-1.0.txt.torrent Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/expat.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/expat.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/freebsd.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/freebsd.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/gpl-2.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/gpl-2.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/gpl-3.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/gpl-3.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/illinois-NCSA.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/illinois-NCSA.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/imlib2.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/imlib2.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/lgpl-2.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/lgpl-2.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/lgpl-2.1.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/lgpl-2.1.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/lgpl-3.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/lgpl-3.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/magnet-links.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/magnet-links.txt.torrent Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/mpl-2.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/mpl-2.0.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/public-domain.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/public-domain.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/unlicense.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/unlicense.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/upl-1.0.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/upl-1.0.txt.torrent @@ -0,0 +1 @@ +d10:created by25:Transmission/2.82 (14160)13:creation datei1445748107e8:encoding5:UTF-84:infod6:lengthi1890e4:name11:upl-1.0.txt12:piece lengthi32768e6:pieces20:^€â;:ÍÆþŒp6}ë0zm7:privatei0eee +\ No newline at end of file diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/wtfpl.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/wtfpl.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/x11.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/x11.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/torrents/xfree86.txt.torrent b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/torrents/xfree86.txt.torrent diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/unlicense.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/unlicense.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/upl-1.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/upl-1.0.txt @@ -0,0 +1,19 @@ +The Universal Permissive License (UPL), Version 1.0 + +Copyright (c) [year] [copyright holders] + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any person obtaining a copy of this software, associated documentation and/or data (collectively the "Software"), free of charge and under any and all copyright rights in the Software, and any and all patent rights owned or freely licensable by each licensor hereunder covering either (i) the unmodified Software as contributed to or provided by such licensor, or (ii) the Larger Works (as defined below), to deal in both + +(a) the Software, and + +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if one is included with the Software (each a “Larger Work†to which the Software is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create derivative works of, display, perform, and distribute the Software and make, use, sell, offer for sale, import, export, have made, and have sold the Software and the Larger Work(s), and to sublicense the foregoing rights on either these or other terms. + +This license is subject to the following condition: + +The above copyright notice and either this complete permission notice or at a minimum a reference to the UPL must be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/wtfpl.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/wtfpl.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/x11.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/x11.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/xfree86.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/licenses/xfree86.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/loading/loader.gif b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/loading/loader.gif Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/loading/loading-panel.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/loading/loading-panel.html diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/preferences_panel/contentscript.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/preferences_panel/contentscript.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/preferences_panel/preferences_panel.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/preferences_panel/preferences_panel.html diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/script_detector/script_detector.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/script_detector/script_detector.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/script_libraries/gethash.sh b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/script_libraries/gethash.sh diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/script_libraries/script-libraries.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/script_libraries/script-libraries.json @@ -0,0 +1,1591 @@ +{ + "9d6f8bdcadd59eba977e9e31066bf393c9fdf8a4": { + "filename": "http://code.jquery.com/jquery-1.0.4.js", + "result": "[freelib]" + }, + "31555f340a206de7622fb760718ef4a1b296ed44": { + "filename": "http://code.jquery.com/jquery-1.1.js", + "result": "[freelib]" + }, + "88c03b5c437ac3551661ecfbe6e1de155c3099c4": { + "filename": "http://code.jquery.com/jquery-1.0.pack.js", + "result": "[freelib]" + }, + "08341cd159e29f561ca0ec16c99bf4b85e43d30f": { + "filename": "http://code.jquery.com/jquery-1.0.1.pack.js", + "result": "[freelib]" + }, + "84b1514a01def3bc0b52f6fa03d0d9fa349bef72": { + "filename": "http://code.jquery.com/jquery-1.0.2.pack.js", + "result": "[freelib]" + }, + "d3b30b0fead39e4c40fb0c91408e74439020a279": { + "filename": "http://code.jquery.com/jquery-1.0.2.js", + "result": "[freelib]" + }, + "fa05290dadfb7d2659a55c50b77595e23f999a74": { + "filename": "http://code.jquery.com/jquery-1.0.1.js", + "result": "[freelib]" + }, + "4a2c9fd552e1ca9ad66feaaad365990b1e664a8f": { + "filename": "http://code.jquery.com/jquery-1.0.4.pack.js", + "result": "[freelib]" + }, + "ddb4126bf4713cb4e0f2310401e58cb9e3f98997": { + "filename": "http://code.jquery.com/jquery-1.0.3.pack.js", + "result": "[freelib]" + }, + "4c12e01d990bd2b1075812d9f28e3ffa50ca59df": { + "filename": "http://code.jquery.com/jquery-1.0.3.js", + "result": "[freelib]" + }, + "16306f8187df578589821e6eb6b807ac4d467d1f": { + "filename": "http://code.jquery.com/jquery-1.1.pack.js", + "result": "[freelib]" + }, + "24dd74d65d2e02aae973af97ebbb31b9820a5bbb": { + "filename": "http://code.jquery.com/jquery-1.1.1.pack.js", + "result": "[freelib]" + }, + "24fdaa88685c8b2dadcc94559ceef318fdcd115b": { + "filename": "http://code.jquery.com/jquery-1.1.1.js", + "result": "[freelib]" + }, + "07c089df7b7a5da16f434870087d6b0e1c45d3b5": { + "filename": "http://code.jquery.com/jquery-1.1.2.pack.js", + "result": "[freelib]" + }, + "788bb58005b75a004cd7abbd26f942eea0391f47": { + "filename": "http://code.jquery.com/jquery-1.1.2.js", + "result": "[freelib]" + }, + "a7e07121debf460f86aa77073676c1e936478c22": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.3.js", + "result": "[freelib]" + }, + "d0d4200eedc83fe692dd65aeab5a548bfe840d06": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.3.1.pack.js", + "result": "[freelib]" + }, + "e1c9252b3e60673e4fa1bb1648cb18cd33139535": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.3.1.js", + "result": "[freelib]" + }, + "0c80055d513ce3103bb70ca956be005f63e32922": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.4.pack.js", + "result": "[freelib]" + }, + "5af7abb29b3b091080db17e53ef6ddcfa555dbe6": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.4.js", + "result": "[freelib]" + }, + "e0c497fc264d7706da23235266ed52acf2c7b89a": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.min.js", + "result": "[freelib]" + }, + "3aca6488dfb65cf0e600a7a70376ca1354b7377c": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.js", + "result": "[freelib]" + }, + "0cafb88edcaebad82c207cdf124de1889364c9f3": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.1.min.js", + "result": "[freelib]" + }, + "384cbfe95d92a30d7c86ac07ea5de56f79c15f6a": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.1.js", + "result": "[freelib]" + }, + "2710cce192fcc4dc676d9572cd852f104ea59387": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.2.pack.js", + "result": "[freelib]" + }, + "6869cb783670d6a4923aaccfe4331015961ed8d6": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.4.pack.js", + "result": "[freelib]" + }, + "55c7f265deba4afc1335071fafbbf7fda8f02bbe": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.6.js", + "result": "[freelib]" + }, + "f3abd53f3725675e3e049c414749e16df11951ba": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.js", + "result": "[freelib]" + }, + "7b9e8594368d30387059e5fdef9d662095dbbf7a": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.min.js", + "result": "[freelib]" + }, + "6be187a67b639b65dc8427eb8e790e42bbe4d7dd": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.1.js", + "result": "[freelib]" + }, + "fed603a4db640b82de54b246de4be7a1cffa8780": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js", + "result": "[freelib]" + }, + "f0b95e99225f314fbe37ccf6b74ce2f916c517de": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.2.js", + "result": "[freelib]" + }, + "3dc9f7c2642efff4482e68c9d9df874bf98f5bcb": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js", + "result": "[freelib]" + }, + "ea6cc893792569fdbb344181034eb668261f2b24": { + "filename": "http://code.jquery.com/jquery-1.5.1.js", + "result": "[freelib]" + }, + "fe7b4d1b72fc22fc397f3df3f1fd891c78f8fc96": { + "filename": "http://code.jquery.com/jquery-1.5.2.min.js", + "result": "[freelib]" + }, + "b509dd44ba3f9c72cf8bba6fcb5f06fae15cabf6": { + "filename": "http://code.jquery.com/jquery-1.5.2.js", + "result": "[freelib]" + }, + "22c1eefcce5be20a3e0966f5bcdf88ed81e9f5e7": { + "filename": "http://code.jquery.com/jquery-1.6.1.js", + "result": "[freelib]" + }, + "7fa300666dadade0d006e4c496bf1c85f4b0ab0c": { + "filename": "http://code.jquery.com/jquery-1.6.2.min.js", + "result": "[freelib]" + }, + "eeee9d4604e71f2e01b818fc1439f7b5baf1be7a": { + "filename": "http://code.jquery.com/jquery-1.6.2.js", + "result": "[freelib]" + }, + "aee58a81bea80c20176c61ff03caaf0aa273f9a1": { + "filename": "http://code.jquery.com/jquery-1.6.3.min.js", + "result": "[freelib]" + }, + "61a11f601d70a331de6444c11e72eab2ffd86427": { + "filename": "http://code.jquery.com/jquery-1.6.4.min.js", + "result": "[freelib]" + }, + "3e5c6d7c6e09965d36df8c1e3d9dca6462c41ec1": { + "filename": "http://code.jquery.com/jquery-1.6.3.js", + "result": "[freelib]" + }, + "921e7702ac9e4c4a4bca052b7bc83b0304440ee3": { + "filename": "http://code.jquery.com/jquery-1.6.4.js", + "result": "[freelib]" + }, + "13184e03cd6a0fc0020cf5ad4eee3d8cb3fadac1": { + "filename": "http://code.jquery.com/jquery-1.7.min.js", + "result": "[freelib]" + }, + "7f389928e5f9d3cb2ae273ae1a6913741d18f0a6": { + "filename": "http://code.jquery.com/jquery-1.7.js", + "result": "[freelib]" + }, + "b47730ffaec4272a8a01756af2ef13ecea1c4e92": { + "filename": "http://code.jquery.com/jquery-1.7.1.js", + "result": "[freelib]" + }, + "0b6da89c21e1dd2093fb26366dd90ffeea635c6a": { + "filename": "http://code.jquery.com/jquery-1.7.1.min.js", + "result": "[freelib]" + }, + "7c64f79dbeeebaa7accd13bf68302c7adb195d7d": { + "filename": "http://code.jquery.com/jquery-1.7.2.min.js", + "result": "[freelib]" + }, + "0d7896e2bb23f88e26e52b22a075350b354df447": { + "filename": "http://code.jquery.com/jquery-1.7.2.js", + "result": "[freelib]" + }, + "0eaabd478dd9538ac53334276b8ff784180140a6": { + "filename": "http://code.jquery.com/jquery-1.8.0.js", + "result": "[freelib]" + }, + "b567b6dd8cb0cb5c1183e55d2f2d1466f32edb39": { + "filename": "http://code.jquery.com/jquery-1.8.2.min.js", + "result": "[freelib]" + }, + "229d5537173d1f006b744b014a28f64912988c61": { + "filename": "http://code.jquery.com/jquery-1.8.2.js", + "result": "[freelib]" + }, + "8b6babff47b8a9793f37036fd1b1a3ad41d38423": { + "filename": "http://code.jquery.com/jquery-1.8.3.min.js", + "result": "[freelib]" + }, + "49a6d1346f3d5a167331a8a5de4f34b5fcc1f6d0": { + "filename": "http://code.jquery.com/jquery-1.8.3.js", + "result": "[freelib]" + }, + "002da8cbe90fcf32fbdebb72386125079e3805ee": { + "filename": "http://code.jquery.com/jquery-1.9.0.min.js", + "result": "[freelib]" + }, + "bfc05b695dfa4f23e11d04b84993585da7a764bf": { + "filename": "http://code.jquery.com/jquery-1.9.0.js", + "result": "[freelib]" + }, + "6c6f10e003ad0c7f462802c0e6422971577c3532": { + "filename": "http://code.jquery.com/jquery-1.8.1.min.js", + "result": "[freelib]" + }, + "45efe8797f5a875878fec7fdaaa90d99532dbf16": { + "filename": "http://code.jquery.com/jquery-1.8.1.js", + "result": "[freelib]" + }, + "ebc4e804054a68c177e9c67cc58e7960d3a8706f": { + "filename": "http://code.jquery.com/jquery-1.8.0.min.js", + "result": "[freelib]" + }, + "ae49e56999d82802727455f0ba83b63acd90a22b": { + "filename": "http://code.jquery.com/jquery-1.9.1.min.js", + "result": "[freelib]" + }, + "9257afd2d46c3a189ec0d40a45722701d47e9ca5": { + "filename": "http://code.jquery.com/jquery-1.9.1.js", + "result": "[freelib]" + }, + "348ab13488f5ab45e048dfb39bb4bc8ed9d840c2": { + "filename": "http://code.jquery.com/jquery-1.10.0.js", + "result": "[freelib]" + }, + "19715ffee604b54e95a0e9db76f6de2b5125c29e": { + "filename": "http://code.jquery.com/jquery-1.10.0.min.js", + "result": "[freelib]" + }, + "b39b6f7d8c5f62a40960ded5c40cc288c10b438d": { + "filename": "http://code.jquery.com/jquery-1.10.1.js", + "result": "[freelib]" + }, + "161b78ec52f28657a835e4a5423f03782fd35806": { + "filename": "http://code.jquery.com/jquery-1.10.1.min.js", + "result": "[freelib]" + }, + "1d85f0f3464e5e49b0522744bf7314e176ac76d9": { + "filename": "http://code.jquery.com/jquery-1.10.2.js", + "result": "[freelib]" + }, + "0511abe9863c2ea7084efa7e24d1d86c5b3974f1": { + "filename": "http://code.jquery.com/jquery-1.10.2.min.js", + "result": "[freelib]" + }, + "6945741107601d402c70a13ce46eb72fd1168bc8": { + "filename": "http://code.jquery.com/jquery-1.11.0.js", + "result": "[freelib]" + }, + "b66ed708717bf0b4a005a4d0113af8843ef3b8ff": { + "filename": "http://code.jquery.com/jquery-1.11.0.min.js", + "result": "[freelib]" + }, + "73e5d044bd153dd912930e8be433059454ce19cd": { + "filename": "http://code.jquery.com/jquery-1.11.1.js", + "result": "[freelib]" + }, + "d6c1f41972de07b09bfa63d2e50f9ab41ec372bd": { + "filename": "http://code.jquery.com/jquery-1.11.1.min.js", + "result": "[freelib]" + }, + "8130544c215fe5d1ec081d83461bf4a711e74882": { + "filename": "http://code.jquery.com/jquery-1.11.2.min.js", + "result": "[freelib]" + }, + "5b57851b09022c5e5f3a5fd08152b2dc12671974": { + "filename": "http://code.jquery.com/jquery-1.11.2.js", + "result": "[freelib]" + }, + "276c87ff3e1e3155679c318938e74e5c1b76d809": { + "filename": "http://code.jquery.com/jquery-1.11.3.min.js", + "result": "[freelib]" + }, + "96c73f3774471cc8378c77a64ecf09b7f625d8b7": { + "filename": "http://code.jquery.com/jquery-1.11.3.js", + "result": "[freelib]" + }, + "41b4bfbaa96be6d1440db6e78004ade1c134e276": { + "filename": "http://code.jquery.com/jquery-2.1.3.min.js", + "result": "[freelib]" + }, + "1852661bd11a09ca9b9cb63d1aa6ff390fffaf4e": { + "filename": "http://code.jquery.com/jquery-2.1.3.js", + "result": "[freelib]" + }, + "43dc554608df885a59ddeece1598c6ace434d747": { + "filename": "http://code.jquery.com/jquery-2.1.4.min.js", + "result": "[freelib]" + }, + "0fed45ad7a48ace869bc725ca474ad86a1ef1562": { + "filename": "http://code.jquery.com/jquery-2.1.4.js", + "result": "[freelib]" + }, + "0be05c714a7e6cf28fe692629ece5b3769901dca": { + "filename": "http://code.jquery.com/jquery-2.0.0.min.js", + "result": "[freelib]" + }, + "79db35e3a94da9ce724c4d3c8ccc5d1864b23a95": { + "filename": "http://code.jquery.com/jquery-2.0.0.js", + "result": "[freelib]" + }, + "d193cc22196566fce6b7a54d483f8ca55b38a2f5": { + "filename": "http://code.jquery.com/jquery-2.0.1.js", + "result": "[freelib]" + }, + "2a35d61baf7dde4a800b08fd7b495a62a8a1e620": { + "filename": "http://code.jquery.com/jquery-2.0.1.min.js", + "result": "[freelib]" + }, + "37fc3e651159cf6b9353a3f6f3bfe6e5e63e0092": { + "filename": "http://code.jquery.com/jquery-2.0.2.js", + "result": "[freelib]" + }, + "1e0331b6dd11e6b511d2e3d75805f5ccdb3b83df": { + "filename": "http://code.jquery.com/jquery-2.0.2.min.js", + "result": "[freelib]" + }, + "ad73590c92b4c3f08d02a0751ba4e4aef658daa0": { + "filename": "http://code.jquery.com/jquery-2.0.3.js", + "result": "[freelib]" + }, + "fbf9c77d0c4e3c34a485980c1e5316b6212160c8": { + "filename": "http://code.jquery.com/jquery-2.0.3.min.js", + "result": "[freelib]" + }, + "0fe3e567e0776226ee98326ba8cae7680683c112": { + "filename": "http://code.jquery.com/jquery-2.1.0.js", + "result": "[freelib]" + }, + "98884258cbdb0d939fa2c5e74fc7ac9e56d8170f": { + "filename": "http://code.jquery.com/jquery-2.1.0.min.js", + "result": "[freelib]" + }, + "8d55aabf2b76486cc311fdc553a3613cad46aa3f": { + "filename": "http://code.jquery.com/jquery-2.1.1.js", + "result": "[freelib]" + }, + "afb90752e0a90c24b7f724faca86c5f3d15d1178": { + "filename": "http://code.jquery.com/jquery-2.1.1.min.js", + "result": "[freelib]" + }, + + "3efaf11e60ea8c541b6dc26f0ef09f195732587a": { + "filename": "https://code.jquery.com/ui/1.11.4/jquery-ui.js", + "result": "[freelib]" + }, + "7f650ee30c6a4d3eea04032039b20ff72997559b": { + "filename": "https://code.jquery.com/ui/1.11.4/jquery-ui.min.js", + "result": "[freelib]" + }, + "0bf0ff43044448711b33453388c3a24d99e6cc9c": { + "filename": "https://code.jquery.com/ui/1.11.3/jquery-ui.js", + "result": "[freelib]" + }, + "0c72ced078c45968712838ac683f09d0980dd0e8": { + "filename": "https://code.jquery.com/ui/1.11.3/jquery-ui.min.js", + "result": "[freelib]" + }, + "4e6a74f1dd52f0b7aa4d9777426adecf8d9377fd": { + "filename": "https://code.jquery.com/ui/1.11.2/jquery-ui.js", + "result": "[freelib]" + }, + "a83caf65714ff3a56aded6088acb525e9d305881": { + "filename": "https://code.jquery.com/ui/1.11.2/jquery-ui.min.js", + "result": "[freelib]" + }, + "0b327b43256da9f57b78e3134aaecc2a4a5a3bad": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.js", + "result": "[freelib]" + }, + "01100f829bce3f074adcb6ae5309d9e769ef29fe": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js", + "result": "[freelib]" + }, + "5f99079e4564f94a1d5e45d22d6dc18acbb148da": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.js", + "result": "[freelib]" + }, + "a2035b74876c5212cfe3e4e35dfd070e74e8c3fd": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/jquery-ui.js", + "result": "[freelib]" + }, + "2a3fa481079f9e02043810cbeee6b5481abf51c0": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.20/jquery-ui.js", + "result": "[freelib]" + }, + "0881516b541abe68d79724c08c1a665872f8f2c2": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.js", + "result": "[freelib]" + }, + "85b15aef55b1eede971c7febd0c00ba04dc16edf": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.js", + "result": "[freelib]" + }, + "d9b48fef067caa58d4e1dec54801c22fe0ea7449": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js", + "result": "[freelib]" + }, + "990dbb08231ef9c9c59653051f5ac7c1e2185d46": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.js", + "result": "[freelib]" + }, + "2e140b943f459e383f569227b3e5569f0dbc6f34": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.js", + "result": "[freelib]" + }, + "53dd39212504739ac18790a4461b9a67c50f2728": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.js", + "result": "[freelib]" + }, + "5cd73db8238d48c08c88f12fe9e5b99b6fa644f7": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.js", + "result": "[freelib]" + }, + "0c3d725fac553c73368496769ff77c3045103704": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.js", + "result": "[freelib]" + }, + "e5de581f09ac990adae2b4aede35264f1dc5cd72": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.js", + "result": "[freelib]" + }, + "e1e87320b2d14e36a9bba1b637b5247645df7185": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.19/jquery-ui.js", + "result": "[freelib]" + }, + "8b71e136c6275d0eeed2b55b9e718a54ce343015": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.js", + "result": "[freelib]" + }, + "c71ddb1b3843c24e909a31595b7e873d7e6da45d": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.js", + "result": "[freelib]" + }, + "d5203dbbb97db1a68ca5a3adf265f17cdaea738d": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.js", + "result": "[freelib]" + }, + "1b96be82b697e835b903c6c22799c8e4e55e285c": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.js", + "result": "[freelib]" + }, + "2804fac51308f459c3eb9c3d20e7ee009a8ba31c": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.js", + "result": "[freelib]" + }, + "5d61b19cbee2f8047f518a58ceff7fdaeeb24921": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js", + "result": "[freelib]" + }, + "7f7859e006f0644a43a7294b50b39e7e9159b3a2": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.js", + "result": "[freelib]" + }, + "842cb8f83614f6de98f70fa7de2f866eecae7ab4": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.js", + "result": "[freelib]" + }, + "90fab357529f510e5134ad0dcdad3f654894d4fc": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.3/jquery-ui.js", + "result": "[freelib]" + }, + "960e36796c42dadf66fafb63bba6087c7d6e1d85": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.js", + "result": "[freelib]" + }, + "1f102103bea71c5e173a916137c563dc62a97cdb": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.js", + "result": "[freelib]" + }, + "61c88c8898ae6bd653737a9dae52209a98998def": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.js", + "result": "[freelib]" + }, + "b87f7150da2b0811ed143443af4038e3e2d41eda": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.js", + "result": "[freelib]" + }, + "9927afbb31df93a76977a676a933b7e3696d61ba": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js", + "result": "[freelib]" + }, + "7b6f5c747c19ad6fbe28957e4318559b45d89111": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/jquery-ui.min.js", + "result": "[freelib]" + }, + "429282063ca7f3bae9797d70a6f09f2e3e05458a": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js", + "result": "[freelib]" + }, + "e398b87b98ae72cbee9f7d3044189ea638f3f80c": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/jquery-ui.min.js", + "result": "[freelib]" + }, + "e9b5baec45507c35477aac5d19afbca8cad92426": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js", + "result": "[freelib]" + }, + "431b7ebb5e36d5af5e7890b782789ac983e28d00": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.19/jquery-ui.min.js", + "result": "[freelib]" + }, + "680f1bd5b4021dbac8b82d68a818d3a94f097ffd": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js", + "result": "[freelib]" + }, + "fc4c1a4691f3819ecd16eaefa68f96f764538f1e": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.min.js", + "result": "[freelib]" + }, + "1d97dd4111b504abc8f6dee45daf6f358aa40140": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.js", + "result": "[freelib]" + }, + "aff393e11d2122a6026df1e2f75d46de4ead89ff": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.js", + "result": "[freelib]" + }, + "d81b246f0f221f4d9a6eb74a8994c4041d2b7215": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.6.0/jquery-ui.js", + "result": "[freelib]" + }, + "8e8b0dccbacc70dc6406023be9e35dfa4f3a944e": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js", + "result": "[freelib]" + }, + "67070ff953d6b0f886083edba723f6d66fa6cbca": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.min.js", + "result": "[freelib]" + }, + "6952564ff6404bd93cb523f1634b451ac1cc8fec": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js", + "result": "[freelib]" + }, + "b48e01c35c1e6ad622386b9a3161bd1bf02723c8": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js", + "result": "[freelib]" + }, + "34d32c47711aa10bdeb196c55d489962296a64c4": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js", + "result": "[freelib]" + }, + "33f5808531e82f2f6e8859da3a765c4d8a0073d2": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js", + "result": "[freelib]" + }, + "973e1554af7d9240e059e38165f2e7b5fc7aa0a5": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js", + "result": "[freelib]" + }, + "ae74362cdb2fadb2eee6c962f47f1e33af51c79d": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.20/jquery-ui.min.js", + "result": "[freelib]" + }, + "31d0cb90f7b82088df6c4e00b5765f9dccc48329": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.js", + "result": "[freelib]" + }, + "a192b2ef3371febba192179ff86e3da3f633160d": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js", + "result": "[freelib]" + }, + "db895a7ed5c8b42e27de2b3ef3199d038a259fdb": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.min.js", + "result": "[freelib]" + }, + "06adc576409427237ce3c269bb9a568d3cd53c9b": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js", + "result": "[freelib]" + }, + "8fdfbe7ccaf0bdcde4c0b34738c0cd73b4587a45": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js", + "result": "[freelib]" + }, + "02d2e4a524b0da52c3cb236619ad065fec44d69a": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.min.js", + "result": "[freelib]" + }, + "42936431058c6c4663e64e2c07931b9159083c31": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js", + "result": "[freelib]" + }, + "bbf7ce8f5ce8d8f9d207f8973328527ac0093b17": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js", + "result": "[freelib]" + }, + "09fdd3d9aebc9086b27b45b3fb051ebded272b39": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js", + "result": "[freelib]" + }, + "e002b335c75b5edefcd251962f61f53a2ab8e0f2": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.min.js", + "result": "[freelib]" + }, + "b5f2733aac4e257929a5f1ff93410ee0bda311b6": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.3/jquery-ui.min.js", + "result": "[freelib]" + }, + "f978dcb9ea6ecfbc7f8a2f9948bacd679c0cd1b4": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js", + "result": "[freelib]" + }, + "f78ae3cdaf4a6a21dfb2565491f5d295462d8be3": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js", + "result": "[freelib]" + }, + "5ed6bdacae842fc530dbc83aabb9a466c7f2b5a1": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.6.0/jquery-ui.min.js", + "result": "[freelib]" + }, + "fe810f47883364fbc4dc2c61e03a3aca0f74fed7": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js", + "result": "[freelib]" + }, + "da851ac384c279992d1855d59257f8d98c603063": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.min.js", + "result": "[freelib]" + }, + "5b59bc1a7087c3a83abd5b9ff559a88428ceab0a": { + "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.min.js", + "result": "[freelib]" + }, + + "0a2054143eddc76447bacf3da455ffc1c726e304": { + "filename": "http://yui.yahooapis.com/3.6.0/build/yui-base/yui-base.js", + "result": "[freelib]" + }, + "5f47da5d3c8902e763ef6ae02e9307a63a95ae5a": { + "filename": "http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader-min.js", + "result": "[freelib]" + }, + "52ebc252c54e6cdaa9e349e1fea37a2950f6af96": { + "filename": "http://yui.yahooapis.com/2.7.0/build/yuiloader/yuiloader-min.js", + "result": "[freelib]" + }, + "e77f9c1022bb48425d63cbaf309d7718ff5d3fbd": { + "filename": "http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader-min.js", + "result": "[freelib]" + }, + "8f1cfeefecc782f53f411de1bf64c77b48b8ba56": { + "filename": "http://yui.yahooapis.com/2.8.1/build/yuiloader/yuiloader-min.js", + "result": "[freelib]" + }, + "aa113da84ddbad46a8002ea22393a238eccf9ee4": { + "filename": "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader-min.js", + "result": "[freelib]" + }, + "a4fadcd6f68d7823a9fd9d1f6089025041a3212a": { + "filename": "http://yui.yahooapis.com/2.8.2/build/yuiloader/yuiloader-min.js", + "result": "[freelib]" + }, + "c398b7eab95bfe84816f60311eaf91194f3bfec8": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/aes.js", + "result": "[freelib]" + }, + "a7eba31001379f751d1a54b988ccdb500d873ec1": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/enc-base64.js", + "result": "[freelib]" + }, + "9bdf0dfad487422fd36693d4119b59175f0112ee": { + "filename": "http://yui.yahooapis.com/2.8.1/build/yuiloader/yuiloader.js", + "result": "[freelib]" + }, + "d9f710afddaba467707c0d6e7b187a8beae1e1f2": { + "filename": "http://yui.yahooapis.com/2.8.2/build/yuiloader/yuiloader.js", + "result": "[freelib]" + }, + "5f8d372d7b385588f61dd53c588608f47a3c3b60": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/enc-utf16.js", + "result": "[freelib]" + }, + "4dc6c77a03258ee7fbe5e877a1ed97311bc45652": { + "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject_src.js", + "result": "[freelib]" + }, + "5847ed101f55d51c53538a7078971e7de8fb6762": { + "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", + "result": "[freelib]" + }, + "fe91b37266d1cdb4b4f51297f69326e271704f35": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "493afa22594fdff6e6fc4f21f99c626533c35b06": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "9fa29ea8f3ec6714b3b6236eb2ce6e1ce905c560": { + "filename": "http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader.js", + "result": "[freelib]" + }, + "1523029ce227a35976407408c5d08039c8fe4f0e": { + "filename": "http://yui.yahooapis.com/2.7.0/build/yuiloader/yuiloader.js", + "result": "[freelib]" + }, + "9514b1927292acf4c670fae6492e9ce2e263472f": { + "filename": "http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader.js", + "result": "[freelib]" + }, + "6b911b0dc178423b946b0299851d9661004c21ef": { + "filename": "http://code.jquery.com/jquery-1.4.1.js", + "result": "[freelib]" + }, + "65cbff4e9d95d47a6f31d96ab4ea361c1f538a7b": { + "filename": "http://code.jquery.com/jquery-1.4.2.min.js", + "result": "[freelib]" + }, + "f02e1f7f1bb966d5fcf16b03daa79ee077a993f8": { + "filename": "http://code.jquery.com/jquery-1.4.js", + "result": "[freelib]" + }, + "b9c72aa78de3c124248f30234c64bf6f3b1a7cb5": { + "filename": "http://code.jquery.com/jquery-1.1.3.pack.js", + "result": "[freelib]" + }, + "bff995d3a845903f281b0b51fea421059459a808": { + "filename": "http://code.jquery.com/jquery-1.4.1.min.js", + "result": "[freelib]" + }, + "b5efe44645f5358e3d785091af3440f80afa85e3": { + "filename": "http://code.jquery.com/jquery-1.4.min.js", + "result": "[freelib]" + }, + "0e9545b59077541c44f521769243a8b717d83aae": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.5/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "e80905e4a45e31075b89189f5ba4913fc0451fdf": { + "filename": "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader.js", + "result": "[freelib]" + }, + "80494ad8eb98e317ffec3671b00944cdc30cee02": { + "filename": "http://yui.yahooapis.com/3.4.0/build/yui-base/yui-base-min.js", + "result": "[freelib]" + }, + "83d1b489e30275a03f568f7e3fa6537d695e0197": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.pack.js", + "result": "[freelib]" + }, + "e956e4de8f223992e2d1362d78c5b5bb33e27497": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "3c737636f4789a45b73f5365cd4cfc8c0922f458": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/hmac.js", + "result": "[freelib]" + }, + "42a8029d12e24767778fc1c6d978b4696b445524": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-cfb.js", + "result": "[freelib]" + }, + "14682f01c5c15f8656cb01425487ad675676df8e": { + "filename": "http://yui.yahooapis.com/3.5.1/build/yui-base/yui-base-min.js", + "result": "[freelib]" + }, + "e1ae2c72f8c5e1b6c423c015349a476f8a908b22": { + "filename": "http://yui.yahooapis.com/3.4.1/build/yui-base/yui-base-min.js", + "result": "[freelib]" + }, + "ca0aea084a63d0a56e1bbf17fde5061f631b391f": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.1.pack.js", + "result": "[freelib]" + }, + "265a86a9d9df5dfdbad77e06c85605bec4beb32a": { + "filename": "http://code.jquery.com/jquery-1.4.2.js", + "result": "[freelib]" + }, + "a2358d630d1a5dad24b679d52e9777b7349910b2": { + "filename": "http://yui.yahooapis.com/3.5.0/build/yui-base/yui-base-min.js", + "result": "[freelib]" + }, + "65fe3b80fae349ecb3acd6541ef651d1ff4961f6": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "66851ab2133e27b97c4f3048416b947aa7ed82c5": { + "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js", + "result": "[freelib]" + }, + "08f37f8169e620c6ecd87635c18fc2b22e3e850e": { + "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js", + "result": "[freelib]" + }, + "28780fdb8fc54bf7d80b1f223abca4f77cd89e85": { + "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject_src.js", + "result": "[freelib]" + }, + "00a5e26ff9ed4b84fc93c764225684c33588a41e": { + "filename": "http://yui.yahooapis.com/3.6.0/build/yui-base/yui-base-min.js", + "result": "[freelib]" + }, + "fe56013bb04c602e676feb34bb49add4da2e0225": { + "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js", + "result": "[freelib]" + }, + "6c445baf655cccb16ee2788714827ab186ed94bf": { + "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.2/scriptaculous.js", + "result": "[freelib]" + }, + "74974f9dc0810ea359367589cb273dd5174d80df": { + "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.1/scriptaculous.js", + "result": "[freelib]" + }, + "c7e9c7f2fb17e0d2ca2391e33007bf3547fec465": { + "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js", + "result": "[freelib]" + }, + "d97ecac3f1b3ccf1f0f68434e8406f87f5acc907": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.2.min.js", + "result": "[freelib]" + }, + "97be02d1785b7bb4f41ae116a6a9bef74cb018d6": { + "filename": "http://code.jquery.com/jquery-1.4.3.min.js", + "result": "[freelib]" + }, + "6a7a7d88fa4e7369003de24164f5961852731e0e": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-ctr.js", + "result": "[freelib]" + }, + "d65a39fc4b09df061a30172f080019ef9d800ca4": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-ecb.js", + "result": "[freelib]" + }, + "427300f82762288c5af967dbf642fbec58c201ea": { + "filename": "http://code.jquery.com/jquery-1.4.4.js", + "result": "[freelib]" + }, + "94ec4a3bcd6b30353584026c0e109e79fb21b6ad": { + "filename": "http://code.jquery.com/jquery-1.5.min.js", + "result": "[freelib]" + }, + "71adcc2cae87e412e521e4a7276efeaee2347927": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.2.js", + "result": "[freelib]" + }, + "677c1ad6d84705c818d63a43298ee3a12959c1b3": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.3.pack.js", + "result": "[freelib]" + }, + "3d542e33a9f3eb3cb45e06fe93d08dd4b7490496": { + "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js", + "result": "[freelib]" + }, + "e70997dd3dbadadebf375908515617059d0c597e": { + "filename": "http://yui.yahooapis.com/3.4.1/build/yui-base/yui-base.js", + "result": "[freelib]" + }, + "b3db6906c1c0641b7a3098e547e0a8039accd80a": { + "filename": "http://yui.yahooapis.com/3.5.0/build/yui-base/yui-base.js", + "result": "[freelib]" + }, + "cc66556593e147584f19b41b697405f828f7562e": { + "filename": "http://code.jquery.com/jquery-1.5.js", + "result": "[freelib]" + }, + "c147a1a86a2c33e60f160b8861501f43f4638c8d": { + "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js", + "result": "[freelib]" + }, + "d45787e64e233eb17f3f1492b12a682f294f866a": { + "filename": "http://code.jquery.com/jquery-1.5.1.min.js", + "result": "[freelib]" + }, + "278d68b8e9edad4895836e272fbc8f78ec4f2f3e": { + "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js", + "result": "[freelib]" + }, + "b98bb654c88a9b7da659fe8dad95a5c7376bb166": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/md5.js", + "result": "[freelib]" + }, + "6463e558dd79d51a2e8464806824c7bbc18c77fd": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.3.min.js", + "result": "[freelib]" + }, + "5cc87d3fcd5cb3c5913c08bad17ff80f4d0d7f46": { + "filename": "http://yui.yahooapis.com/3.4.0/build/yui-base/yui-base.js", + "result": "[freelib]" + }, + "333b6d92a99eac873b1de2045c670fbdb61970ab": { + "filename": "http://yui.yahooapis.com/3.5.1/build/yui-base/yui-base.js", + "result": "[freelib]" + }, + "522f0852b91775306ca47138c1d6ceeb87677880": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-ofb.js", + "result": "[freelib]" + }, + "4407f7b9602539e80f1569ae734696fd92deeff0": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-ansix923.js", + "result": "[freelib]" + }, + "c82ea9768b18696832408b6cc729e2e121def691": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.3.js", + "result": "[freelib]" + }, + "0d2bc9db63acd9cc238a4925e79f9a3079490970": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.4.min.js", + "result": "[freelib]" + }, + "5900300a75ed7917eaa6f75077afe9ef49e66986": { + "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js", + "result": "[freelib]" + }, + "2cc787ebd4d29f2e24646f76f9c525336949783e": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools.js", + "result": "[freelib]" + }, + "a965003ea3313be11a02743f4807411c9eb71f04": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-iso10126.js", + "result": "[freelib]" + }, + "3bb92e84642c03cf0fe49174d0e1c420d46d2e18": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.4.js", + "result": "[freelib]" + }, + "325edd57857f7a3160cfe2512dff5526d7e647db": { + "filename": "http://code.jquery.com/jquery-1.6.min.js", + "result": "[freelib]" + }, + "034970f98cb529c779c8f961b2b7c09ecb499240": { + "filename": "http://code.jquery.com/jquery-1.6.js", + "result": "[freelib]" + }, + "341a7a52109c3abfb23d5a5b4f363fd8d6a52f6c": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-iso97971.js", + "result": "[freelib]" + }, + "c654cdaa3ca1184d9b18d0c31f8369a04c63f7f5": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-nopadding.js", + "result": "[freelib]" + }, + "20860bad9c83c3890be57052f009b9d97848c9ec": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.5.min.js", + "result": "[freelib]" + }, + "6111fcf6c2277eba8821ca365dbbea472a3206e7": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.4/mootools.js", + "result": "[freelib]" + }, + "9025fe9334566eb919ddca85a8f949b01c7d837d": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.5.pack.js", + "result": "[freelib]" + }, + "0e9a07ee104153a459cdbcb9fa28293b4bbb429f": { + "filename": "http://code.jquery.com/jquery-1.6.1.min.js", + "result": "[freelib]" + }, + "e55462193a857ffe36e42bfcbecfebf1ca33d0b8": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools.js", + "result": "[freelib]" + }, + "7df0e9aae795337db012b3efd0b9ee9cc7719b56": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools.js", + "result": "[freelib]" + }, + "8963108fa84c2033a1052d47079d7f75a7e5b60e": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.5.js", + "result": "[freelib]" + }, + "aa7020d6c8d5475ae588640954caa9e4cdd7eca0": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-zeropadding.js", + "result": "[freelib]" + }, + "1be9c3684054001f53fa7ff6d85ec3cb573a9cd2": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js", + "result": "[freelib]" + }, + "e0f3225498158bc63af7bfba636b091ea4ee5fcd": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pbkdf2.js", + "result": "[freelib]" + }, + "c415b533f7edda8b9de417cc0517904f86e9fe1f": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/rabbit.js", + "result": "[freelib]" + }, + "c10dbe0c2b23444d0794f3376398702d84f41583": { + "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.6.pack.js", + "result": "[freelib]" + }, + "f4d4125bcd5151aad69dd849a11fc1ca589cc64b": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools.js", + "result": "[freelib]" + }, + "4ee6675ca57dda3255aa669d8ec4d35760eb47c3": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.0/mootools.js", + "result": "[freelib]" + }, + "0c89448016629bb2ea758f4e98529c2e166a122d": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.1/mootools.js", + "result": "[freelib]" + }, + "b4096385cad3144e81c255aa6e4b7dabb30bc19f": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/rc4.js", + "result": "[freelib]" + }, + "037f4fadbc2020ccb4935384b8ae5af62bdd0145": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha1.js", + "result": "[freelib]" + }, + "bc018ec49a5c7757577bb63e5d5f8a99be0e3954": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.2/mootools.js", + "result": "[freelib]" + }, + "aa5c283b9e094eeacdd080b44951406abbc9e58c": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha224.js", + "result": "[freelib]" + }, + "6dc7644a54d5cc254a1f6d7cb7154128b2b6570a": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.3/mootools.js", + "result": "[freelib]" + }, + "c0c37b7d3119f29d3759fdaf7eb8bc4670ea9e7f": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.1/mootools.js", + "result": "[freelib]" + }, + "b38f741b43f6ddcce3f1b47274d1683cca9f07a8": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha256.js", + "result": "[freelib]" + }, + "e29701dd85d792bddbf52d1e1fc3d1ada41b6192": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha384.js", + "result": "[freelib]" + }, + "cc019ac09f68258ee3442fe7cc440adf78a3cef2": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "e88bb2c302b41a4cc5b97604354a48d068e3e1eb": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha512.js", + "result": "[freelib]" + }, + "fc39ed8ca4a58668124471e509506443de4467f2": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.4/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "b1a271458ae47d0b47c9e0996956091a93dec16f": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.1/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "86f0df8662b511142dfc4e0ce9c81d805c8d7a7e": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.0/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "e0bfed3ffc741a9f4e59e6004a1dec9c71241a59": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/x64-core.js", + "result": "[freelib]" + }, + "fc21f8084ad4040ddbf620ba79acd3998fb3dc7b": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "1e8f9e1614db771782bc9e871fb712b06610b9f4": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.2/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "c7e2076a3af9997731499bc1f7dc3941b522c1eb": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.3/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "dd7783b4c8d4ecaad4091d1d32df2f97d7b10ddc": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.2/mootools.js", + "result": "[freelib]" + }, + "55bba460dcbb70562536ddd5c8734b311f38c42d": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools.js", + "result": "[freelib]" + }, + "3c1ddf62af20a1f5c5de7a3af180b32528dc47db": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.2/mootools.js", + "result": "[freelib]" + }, + "c43a38fce1aa745d59b1a6f7ab7def81f28701a4": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.3/mootools.js", + "result": "[freelib]" + }, + "e5335c2a82f26e49b1324edc21e452de040d5cdc": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools.js", + "result": "[freelib]" + }, + "ccf015fcd45618c6b116977c96539d93ee10b542": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/tripledes.js", + "result": "[freelib]" + }, + "3d9fc65389ce7de16f87909039aa2e728c693b3d": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.5/mootools.js", + "result": "[freelib]" + }, + "5f970c3c8ca26a94c14a1ae1e7321621cf4eae0c": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.2/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "03a65e56fc95caea1b85a591c984e9b6c080726d": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.1/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "669d164e3bff6156b21084cf035979d62433df75": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.2/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "f3e20ad41082a93dbd09202590717da71aebd316": { + "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.3/mootools-yui-compressed.js", + "result": "[freelib]" + }, + "8dda5f159c9bedee9f4a6b7a7a6028a554977994": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "15c3f73c75bb3ab87040fe55240f9dd5ea69b6bf": { + "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core-debug.js", + "result": "[freelib]" + }, + "5c83aac1a3409dc1ec3a228e4c765292eb4434d4": { + "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.0.0/ext-core-debug.js", + "result": "[freelib]" + }, + "7dc1b4f3e358c58030c4676c990eff60a0fc838f": { + "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core.js", + "result": "[freelib]" + }, + "d19d40a20252730e9fd9af1c7867c0f5417ebe32": { + "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.0.0/ext-core.js", + "result": "[freelib]" + }, + "e1db767afb82018ab6a695fe52334f2f5d81a0e3": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "a90b5f6afb6c78b30c3539392d49e45fd9dfe3d9": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5.1/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "0a0a820f2bc4f2dac8dcfde2282411275e2dc697": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "b6d2c0b655b327407966b52303449dedce084ded": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "4cc838a3be933fda21bbbfc8f52b01e14a1e70a5": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "2ef4341a4ca0b9a0fc1aea422d85b5d9771fde87": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.0/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "df435b881e8364ddfbd44d5f786b10c75f964175": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "19214655c4152b79f204e222a481d1e18da84972": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "f444ee6b041735ee6109dd2fe3c3a7755fa949f7": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.0/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "c7f5b42b2306a79f67988ee073ac98c2a1d5782f": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.3/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "d8afec39893c1a99139212feb40888847f8a5253": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "a6edefef305d9164212fa140426629c7d8a58c93": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.1.1/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "a3e5c42f93722ad28cda811f8635bddf213819ed": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "741b8eeb65774256a8a76ea1af91f976357fcd81": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5.1/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "911a35988b8540414cfbc990fbc112eb124fd968": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "c753cf372377ef0b5a18204cd86df8d4792fa8f5": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "8b95d59f6b28b072ceb4228a6db107b934500a02": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.0/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "8c135fc57355fe5d5a18f3dbe5736bc772bb20a7": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "70b1fe9dd4ebec0b5d417647e549bca8f9200020": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "8980e43d4750c63eb57cfff5f0723f118d243c67": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.0/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "d2fc56e1b9f2014fb7710d186a355a57e3acd283": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.3/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "2bab42610adee25cdc0d3a4ba96b94f1e9ccd115": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "6bb906d86dd239add79d0779a9fcdf9740aa7e3b": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.1.1/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "3d96f61e48510cbe595081ef8b2d5c8479f95d3e": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "1e4cb0dcb97df9a15433477f9f8a666914eedc3c": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.0/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "47732fb5e03d251aff1a7c0b550a3af74c7ceea5": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.3/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "85399dd9527026afc66a6fb43ad5c0d4ea97f83e": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "147eab514dfe1d88506a5e158b782cb5c504c056": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.xd.js.uncompressed.js", + "result": "[freelib]" + }, + "229e4025f71b0b94d98505f56c5cfd7cd41d06aa": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.3/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "135ade1e60da3e3b79fd73c3a6a005a250e2a7f7": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "135188b624daae8f4b015b0b8b75875a6132aa3d": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "fac80a6188865418344d4b6c5d4955ee7e7362c2": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.0/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "311d8f38b12a09f16f5a19e1dfb6575b5ce0f83c": { + "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.xd.js", + "result": "[freelib]" + }, + "ca2868985811d45cfbad118a297869707572e0bb": { + "filename": "https://raw.github.com/voldsoftware/toolbarbutton-jplib/stable/lib/toolbarbutton.js", + "result": "[freelib]" + }, + "32d542564913a016f1cea340ba8ac164c160004d": { + "filename": "http://yui.yahooapis.com/3.3.0/build/yui-base/yui-base.js", + "result": "[freelib]" + }, + "012cc186912c473552a341b2eaffb71240688ccd": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/cipher-core.js", + "result": "[freelib]" + }, + "d1c9d4d91c1c3c76f601778cb5e0489e0f80a10d": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/evpkdf.js", + "result": "[freelib]" + }, + "794503310ed31a11f233e1acdddc10f2ce91748e": { + "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/core.js", + "result": "[freelib]" + }, + "5717e22c3b2c7caf870fc0772a64344962b59ee6": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.6/underscore.js", + "result": "[freelib]" + }, + "7e0294019938a772f4ddd7799501496074e0f0fb": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.7/underscore.js", + "result": "[freelib]" + }, + "28e41c3ce9232633468013342c49fd62a4f5f6bd": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.2/underscore.js", + "result": "[freelib]" + }, + "8d84b347dfe4f5b75f7b5f670326ca5c8041b7a9": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.3/underscore.js", + "result": "[freelib]" + }, + "9564fa7a6a001e4e56b0244ccda03eef3940813e": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.3/underscore.js", + "result": "[freelib]" + }, + "058cbd179f032f667823545519aa2d10b0b69508": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.2/underscore.js", + "result": "[freelib]" + }, + "868141351efa758d031779c776e608e3a049d823": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.4/underscore.js", + "result": "[freelib]" + }, + "2fee700150a7de876acc21403f77e57dae2f5618": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.5/underscore.js", + "result": "[freelib]" + }, + "40946800c5c8bee189ca3e7f8017661f9456e490": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.0/underscore.js", + "result": "[freelib]" + }, + "b842a8ca5e996e001e648fc8c73316cd55e496ed": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.4/underscore.js", + "result": "[freelib]" + }, + "f2fa9179d764f6a688dc0c99b1b5283f1b680249": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.1/underscore.js", + "result": "[freelib]" + }, + "c1dff1c5dbb68af6e22bd401afd28aab970a8aff": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.3/underscore.js", + "result": "[freelib]" + }, + "5846c870e0f1daca152db22277915adb6520ffa3": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.0/underscore.js", + "result": "[freelib]" + }, + "cdacc2b0045fa1b920b64664b88b155d0c0df169": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.2/underscore.js", + "result": "[freelib]" + }, + "baa693e82387a328abccf9694c6d2db571ac8aca": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.3/underscore-min.js", + "result": "[freelib]" + }, + "e67cf6a985999c7ef5595772e4ffefeacd0c6ac3": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.1/underscore.js", + "result": "[freelib]" + }, + "0a15952061f6fb7a5493281f6ff8eb916a417e2f": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.1/underscore-min.js", + "result": "[freelib]" + }, + "bd9624f882f7d3d29292ddc7f484987b3e991cb5": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.0/underscore.js", + "result": "[freelib]" + }, + "ede1d022640f26eaa6109da9e924670f6ed14cce": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.2/underscore-min.js", + "result": "[freelib]" + }, + "63f6a94752e5fde78627529763e67ecd4ef78f12": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.4/underscore-min.js", + "result": "[freelib]" + }, + "1185da1043863517c6aa0a4e0a3bc433dfb98313": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.2/underscore-min.js", + "result": "[freelib]" + }, + "86752ba2e4f3855a8a5e45d5f07567ea70a9cc98": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.0/underscore-min.js", + "result": "[freelib]" + }, + "cfbc3fa20d685d100308e123c3310dc9600ef0fd": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.3/underscore-min.js", + "result": "[freelib]" + }, + "083bbcd739b7b1336f13c72603e1704b164c02bd": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.1/underscore-min.js", + "result": "[freelib]" + }, + "f665459959c5167c0905974a62ffe923f2c19813": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.5/underscore-min.js", + "result": "[freelib]" + }, + "2de2ecea5ba12e7235ffb44d6892cc77fe6f4abe": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.4/underscore-min.js", + "result": "[freelib]" + }, + "81afb4cd3755671fea5e74d7118d7d460c475308": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.7/underscore-min.js", + "result": "[freelib]" + }, + "9e389ede8ed7f782c5ecf2f87c3afa3b1e309bff": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.3/underscore-min.js", + "result": "[freelib]" + }, + "703d6a61f31ddb45252c55813556a92e8cc2ee22": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.6/underscore-min.js", + "result": "[freelib]" + }, + "7d6e352b0d26655ba851863561b5d912cc24caa7": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.0/underscore-min.js", + "result": "[freelib]" + }, + "5de53da57fc8b7ab6c77d597c22875d747352fef": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.1/underscore-min.js", + "result": "[freelib]" + }, + "bcdd63e18a8a7cf728253f738556ad3b88d74649": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.2/underscore-min.js", + "result": "[freelib]" + }, + "ee68308411c690cd51cc8a43fe6ae60d3d1678af": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.4/underscore-min.js", + "result": "[freelib]" + }, + "49a747d3284b1d04f3eb823a4188f7725004f823": { + "filename": "https://raw.github.com/documentcloud/underscore/1.1.0/underscore-min.js", + "result": "[freelib]" + }, + "97f93241957893ebd7febc5b5bac9a7bd1d94a0f": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.3/underscore-min.js", + "result": "[freelib]" + }, + "710c3a99f0bd456c2fd6dcbcbd1e500e0646ec19": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.1/underscore-min.js", + "result": "[freelib]" + }, + "7361e8afa72bd0098e2520584786474c9c4a5064": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.2/underscore-min.js", + "result": "[freelib]" + }, + "ad0775c89a87111019840dc7bbf902d832e4ccdf": { + "filename": "https://raw.github.com/documentcloud/underscore/1.0.0/underscore-min.js", + "result": "[freelib]" + }, + "34454bfed864addf8ec4aacdd9adf872f8360ed3": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.1/underscore.js", + "result": "[freelib]" + }, + "07916c0b7274275f916fe288d01b254545b17d9a": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.4/underscore.js", + "result": "[freelib]" + }, + "133de2283d03193cb06f62f92c494afe098460a5": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.0/underscore.js", + "result": "[freelib]" + }, + "4c977634c87efbd2b7113993d36dad603b8dcf2f": { + "filename": "https://raw.github.com/documentcloud/underscore/1.2.1/underscore.js", + "result": "[freelib]" + }, + "3fa74bb289537fcdee796b26968e47d53d38f903": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.2/underscore.js", + "result": "[freelib]" + }, + "772b2587aa2fa345fb760eff9ebe5acd97937243": { + "filename": "https://raw.github.com/documentcloud/underscore/1.3.3/underscore.js", + "result": "[freelib]" + }, + "562c6c44b39809ec07c047f4ed6c591f3ae7c034": { + "filename": "https://raw.github.com/documentcloud/underscore/1.4.0/underscore.js", + "result": "[freelib]" + }, + "063a7d75792dff2b46eee81cc12de63def672911": { + "filename": "https://raw.github.com/documentcloud/underscore/1.4.1/underscore.js", + "result": "[freelib]" + }, + "47479149fe12fc56685a9de90c5a9903390cb451": { + "filename": "https://raw.github.com/documentcloud/underscore/1.4.2/underscore.js", + "result": "[freelib]" + }, + "d53fbd7308ae3d7eeb4a536c2cbfe739648850b4": { + "filename": "https://raw.github.com/documentcloud/underscore/1.4.3/underscore.js", + "result": "[freelib]" + }, + "6d9ee62759cb911ec03b21078c9f92f0f2afa25c": { + "filename": "https://raw.github.com/documentcloud/underscore/1.4.4/underscore.js", + "result": "[freelib]" + }, + "5d42ed92480d3a88efa270449f38c6d88d653af5": { + "filename": "https://raw.github.com/documentcloud/underscore/1.5.0/underscore.js", + "result": "[freelib]" + }, + "9ee15c1f1a84a258ba5f48de72da3538c8b7c375": { + "filename": "https://raw.github.com/documentcloud/underscore/1.5.1/underscore.js", + "result": "[freelib]" + }, + "c9ae7b502c521d2f53b9065ef4fc7d7cc97dce4c": { + "filename": "https://raw.github.com/documentcloud/underscore/1.5.2/underscore.js", + "result": "[freelib]" + }, + "fe1b87838b7328273812380d26837f58348103b0": { + "filename": "https://raw.github.com/documentcloud/underscore/1.6.0/underscore.js", + "result": "[freelib]" + }, + "92d29762b3d85d123d593f14b113d4fb6385598f": { + "filename": "https://raw.github.com/documentcloud/underscore/1.7.0/underscore.js", + "result": "[freelib]" + }, + "fb26909af4ad2a6c240b9aa4b35bb983cf4b20e4": { + "filename": "https://raw.github.com/documentcloud/underscore/1.7.0/underscore-min.js", + "result": "[freelib]" + }, + + "63a001665725b35d2bc4a6212385a746584c1a3b": { + "filename": "http://cdn.jsdelivr.net/jquery.fancytree/2.6.0/jquery.fancytree-all.min.js", + "result": "[freelib]" + }, + "d6469e3aa15a6107ad5783a96e3c8fa3f5ce21ca": { + "filename": "http://cdn.jsdelivr.net/jquery.fancytree/2.5.0/jquery.fancytree-all.min.js", + "result": "[freelib]" + }, + "2de56a2ec01b0aa170754bd6ed7485576f16f165": { + "filename": "http://cdn.jsdelivr.net/jquery.fancytree/2.4.1/jquery.fancytree-all.min.js", + "result": "[freelib]" + }, + + "5ada7c103fc1deabc925cc1fdbbb6e451c21fc70": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js", + "result": "[freelib]" + }, + "afa7af2bc7cbe37eeccb9b65577744c08219c5a9": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.js", + "result": "[freelib]" + }, + "b3f2ef9f985e7906c9360756b73cd64bf7733647": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js", + "result": "[freelib]" + }, + "f8752e9ae24daec0a0baffd7819122f8c6fd9103": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.js", + "result": "[freelib]" + }, + "253711c6d825de55a8360552573be950da180614": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js", + "result": "[freelib]" + }, + "542cfd539f0cad650342c8cab8baf1cdbcd5fea6": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.js", + "result": "[freelib]" + }, + "6c264e0e0026ab5ece49350c6a8812398e696cbb": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js", + "result": "[freelib]" + }, + "bbf55e20f1ebb6368522799f29db39830a08ef93": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js", + "result": "[freelib]" + }, + "5814e91bb6276f4de8b7951c965f2f190a03978d": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js", + "result": "[freelib]" + }, + "fd607f85d598503b24d7799722db29fec4de1ef6": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.js", + "result": "[freelib]" + }, + "c6a8a0f02ee0ecd975226ae4b38e9660750d1f93": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js", + "result": "[freelib]" + }, + "539e456bb40d9e98244060186f5f131b1a7f4b33": { + "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.js", + "result": "[freelib]" + }, + + "128273a9c66a32d7d59a6f290deb6cc4a2b2ee5a": { + "filename": "http://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.7.1/js/lightbox.min.js", + "result": "[freelib]" + }, + "250d7c160f17c13e89cee0e1dcd1debb2e940ed2": { + "filename": "http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js", + "result": "[freelib]" + } +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/images/button-download.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/images/button-download.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/images/libre.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/images/libre.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/images/logo-medium.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/images/logo-medium.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/index.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/index.html diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/js/form-row.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/js/form-row.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/js/form-types.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/js/form-types.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/js/pagescript-emitter.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/js/pagescript-emitter.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/js/pagescript-listener.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/js/pagescript-listener.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/js/permafrost-info-box.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/js/permafrost-info-box.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/styles/form.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/styles/form.css diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/styles/styles.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/styles/styles.css diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/settings/third-party/jquery/jquery.min.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/settings/third-party/jquery/jquery.min.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/widget/images/README b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/widget/images/README diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/icon.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/widget/images/librejs-32.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/icon64.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/widget/images/librejs-64.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/widget/images/librejs-off.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/widget/images/librejs-off.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/widget/images/librejs.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/data/widget/images/librejs.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/defaults/preferences/prefs.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/defaults/preferences/prefs.js @@ -1,5 +0,0 @@ -pref("extensions.jid1-KtlZuoiikVfFew@jetpack.whitelist", ""); -pref("extensions.jid1-KtlZuoiikVfFew@jetpack.complaint_tab", true); -pref("extensions.jid1-KtlZuoiikVfFew@jetpack.display_notifications", false); -pref("extensions.jid1-KtlZuoiikVfFew@jetpack.complaint_email_subject", "Please make your JavaScript free"); -pref("extensions.jid1-KtlZuoiikVfFew@jetpack.complaint_email_body", "I could not use your site because it requires running JavaScript code which is not free software. Since a nonfree program disrespects the user's freedom, I decided not to run it. \n\nSee http://gnu.org/philosophy/javascript-trap.html for more information, and please make your JavaScript code free."); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/harness-options.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/harness-options.json @@ -1,751 +0,0 @@ -{ - "abort_on_missing": false, - "check_memory": false, - "enable_e10s": false, - "is-sdk-bundled": false, - "jetpackID": "jid1-KtlZuoiikVfFew@jetpack", - "loader": "addon-sdk/lib/sdk/loader/cuddlefish.js", - "main": "lib/main", - "mainPath": "librejs/main", - "manifest": { - "librejs/addon_management/install_uninstall": { - "docsSHA256": null, - "jsSHA256": "b78ebeb97a54faec0bb84b6e1bab5196ebc3b743fffc48ac61c74d2ea4455779", - "moduleName": "addon_management/install_uninstall", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "http_observer/caching": "librejs/http_observer/caching", - "http_observer/http_request_observer": "librejs/http_observer/http_request_observer", - "parser/narcissus_worker": "librejs/parser/narcissus_worker", - "sdk/tabs": "sdk/tabs", - "settings/storage": "librejs/settings/storage" - }, - "sectionName": "lib" - }, - "librejs/addon_management/prefchange": { - "docsSHA256": null, - "jsSHA256": "af09f0cd11d98c63cb7bc31ea0a2012ae5749417838fb6c6d755d54f984bb66f", - "moduleName": "addon_management/prefchange", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/simple-prefs": "sdk/simple-prefs" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/bug_fix": { - "docsSHA256": null, - "jsSHA256": "00774ce848cbb8e4411e2f34beb3d5f7873d16a8da2075d910332a74aabd987a", - "moduleName": "html_script_finder/bug_fix", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/html_script_finder/dom_handler": { - "docsSHA256": null, - "jsSHA256": "c28997dfa6916ae696e9153bdf25af139c4e7ecc5ebc9d0deb0f0c444dbc4d32", - "moduleName": "html_script_finder/dom_handler", - "packageName": "librejs", - "requirements": { - "addon_management/prefchange": "librejs/addon_management/prefchange", - "chrome": "chrome", - "html_script_finder/dom_handler/attributes": "librejs/html_script_finder/dom_handler/attributes", - "html_script_finder/dom_handler/dom_checker": "librejs/html_script_finder/dom_handler/dom_checker", - "html_script_finder/dom_handler/dom_gatherer": "librejs/html_script_finder/dom_handler/dom_gatherer", - "html_script_finder/dom_handler/script_object": "librejs/html_script_finder/dom_handler/script_object", - "html_script_finder/dom_handler/script_properties": "librejs/html_script_finder/dom_handler/script_properties", - "html_script_finder/web_labels/js_web_labels": "librejs/html_script_finder/web_labels/js_web_labels", - "http_observer/allowed_referrers": "librejs/http_observer/allowed_referrers", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/js_checker": "librejs/js_checker/js_checker", - "js_checker/privacy_checker": "librejs/js_checker/privacy_checker", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/dom_handler/attributes": { - "docsSHA256": null, - "jsSHA256": "86c5b89ce30dcb634e1d5352d38c4c2141faee08a511bceed3a4c53f429472e0", - "moduleName": "html_script_finder/dom_handler/attributes", - "packageName": "librejs", - "requirements": { - "html_script_finder/dom_handler/script_object": "librejs/html_script_finder/dom_handler/script_object", - "html_script_finder/dom_handler/script_properties": "librejs/html_script_finder/dom_handler/script_properties" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/dom_handler/dom_checker": { - "docsSHA256": null, - "jsSHA256": "0c3fb8f55d636d6cd165b67e85a053132530d564409be98910182bb04ec83da5", - "moduleName": "html_script_finder/dom_handler/dom_checker", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "html_script_finder/dom_handler/request": "librejs/html_script_finder/dom_handler/request", - "html_script_finder/dom_handler/script_properties": "librejs/html_script_finder/dom_handler/script_properties", - "html_script_finder/url_seen_tester": "librejs/html_script_finder/url_seen_tester", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/js_checker": "librejs/js_checker/js_checker", - "js_checker/privacy_checker": "librejs/js_checker/privacy_checker", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/timers": "sdk/timers", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/dom_handler/dom_gatherer": { - "docsSHA256": null, - "jsSHA256": "5c3c6fe8b44d506dc5d042c3255d35e1ccae60fc414b35bd05faecfd600f4d3a", - "moduleName": "html_script_finder/dom_handler/dom_gatherer", - "packageName": "librejs", - "requirements": { - "html_script_finder/bug_fix": "librejs/html_script_finder/bug_fix", - "html_script_finder/dom_handler/attributes": "librejs/html_script_finder/dom_handler/attributes", - "html_script_finder/dom_handler/script_object": "librejs/html_script_finder/dom_handler/script_object", - "html_script_finder/dom_handler/script_properties": "librejs/html_script_finder/dom_handler/script_properties", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/privacy_checker": "librejs/js_checker/privacy_checker", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/dom_handler/request": { - "docsSHA256": null, - "jsSHA256": "1918e579fe8bbd4b4bc9563671187cfc267212806efc4c4b1096918388cedfd7", - "moduleName": "html_script_finder/dom_handler/request", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "html_script_finder/url_seen_tester": "librejs/html_script_finder/url_seen_tester", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/timers": "sdk/timers", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/dom_handler/script_object": { - "docsSHA256": null, - "jsSHA256": "db9933f854feb1f6887e643ef110b8c7ec69bd48ae73e4b3364eaf90328b4ab2", - "moduleName": "html_script_finder/dom_handler/script_object", - "packageName": "librejs", - "requirements": { - "script_entries/accepted_scripts": "librejs/script_entries/accepted_scripts", - "script_entries/dryrun_scripts": "librejs/script_entries/dryrun_scripts", - "script_entries/removed_scripts": "librejs/script_entries/removed_scripts" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/dom_handler/script_properties": { - "docsSHA256": null, - "jsSHA256": "13442bf443dde1cdcab84a86c0562df7a0d9a8aef6a130cc688f7e669a5d6e70", - "moduleName": "html_script_finder/dom_handler/script_properties", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/html_script_finder/html_parser": { - "docsSHA256": null, - "jsSHA256": "2fc55cf1e90ade703e65f5aaed4ac350b82abe4b418a648f025cdc648964f447", - "moduleName": "html_script_finder/html_parser", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "html_script_finder/dom_handler": "librejs/html_script_finder/dom_handler" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/url_seen_tester": { - "docsSHA256": null, - "jsSHA256": "f0d64fd7ebe2bcff3312a3439e9e54cf570bb6b3697a34b63cdf1847182f668e", - "moduleName": "html_script_finder/url_seen_tester", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/html_script_finder/web_labels/find_js_labels": { - "docsSHA256": null, - "jsSHA256": "5638228ac2995090744e23f96f5536d5d2545fb83a82277e4796d765408d8b17", - "moduleName": "html_script_finder/web_labels/find_js_labels", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/html_script_finder/web_labels/js_web_labels": { - "docsSHA256": null, - "jsSHA256": "97c3f8b0ed2695db5298a40c38cc14ae670dd3e0a571f1560477905472173d11", - "moduleName": "html_script_finder/web_labels/js_web_labels", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "html_script_finder/web_labels/find_js_labels": "librejs/html_script_finder/web_labels/find_js_labels", - "html_script_finder/web_labels/script_hash_worker": "librejs/html_script_finder/web_labels/script_hash_worker", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/license_definitions": "librejs/js_checker/license_definitions", - "sdk/self": "sdk/self", - "sdk/timers": "sdk/timers", - "sdk/url": "sdk/url", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/html_script_finder/web_labels/script_hash_worker": { - "docsSHA256": null, - "jsSHA256": "cf9a9c2c803daa74e223429431f9140c5524cbe570dd09bf611c3b8f32572d4a", - "moduleName": "html_script_finder/web_labels/script_hash_worker", - "packageName": "librejs", - "requirements": { - "html_script_finder/dom_handler/dom_checker": "librejs/html_script_finder/dom_handler/dom_checker", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/timers": "sdk/timers" - }, - "sectionName": "lib" - }, - "librejs/http_observer/allowed_referrers": { - "docsSHA256": null, - "jsSHA256": "bd6f1b505826869176a90eee89ba53dfef4824a5cedfdeb9b4c3c4cb96bd8906", - "moduleName": "http_observer/allowed_referrers", - "packageName": "librejs", - "requirements": { - "addon_management/prefchange": "librejs/addon_management/prefchange" - }, - "sectionName": "lib" - }, - "librejs/http_observer/caching": { - "docsSHA256": null, - "jsSHA256": "82fb91a8e048e79fdf347a870b09941277fca9e2350b824f11ed7cfd53923173", - "moduleName": "http_observer/caching", - "packageName": "librejs", - "requirements": { - "chrome": "chrome" - }, - "sectionName": "lib" - }, - "librejs/http_observer/http_request_observer": { - "docsSHA256": null, - "jsSHA256": "478999611e52df1458bc861c658bdcb179782cf83c2e3f00d95fbe640470c9f4", - "moduleName": "http_observer/http_request_observer", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "html_script_finder/url_seen_tester": "librejs/html_script_finder/url_seen_tester", - "http_observer/stream_loader": "librejs/http_observer/stream_loader" - }, - "sectionName": "lib" - }, - "librejs/http_observer/process_response": { - "docsSHA256": null, - "jsSHA256": "c9efc372a64c71375964ef567de75db8a09f9244e134e4d0feff6d7acc49a939", - "moduleName": "http_observer/process_response", - "packageName": "librejs", - "requirements": { - "addon_management/prefchange": "librejs/addon_management/prefchange", - "chrome": "chrome", - "html_script_finder/html_parser": "librejs/html_script_finder/html_parser", - "html_script_finder/web_labels/js_web_labels": "librejs/html_script_finder/web_labels/js_web_labels", - "http_observer/allowed_referrers": "librejs/http_observer/allowed_referrers", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/js_checker": "librejs/js_checker/js_checker", - "script_entries/accepted_scripts": "librejs/script_entries/accepted_scripts", - "script_entries/dryrun_scripts": "librejs/script_entries/dryrun_scripts", - "script_entries/removed_scripts": "librejs/script_entries/removed_scripts", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/http_observer/stream_loader": { - "docsSHA256": null, - "jsSHA256": "0d3694002a24e5735391556eb5013364cd02d9b43d323c2be56f57467ed9a784", - "moduleName": "http_observer/stream_loader", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "http_observer/process_response": "librejs/http_observer/process_response" - }, - "sectionName": "lib" - }, - "librejs/js_checker/constant_types": { - "docsSHA256": null, - "jsSHA256": "9327eb745318a8c4aa668bf8ad147ee15b541914dc4d408cc4a7752c5fe70a3f", - "moduleName": "js_checker/constant_types", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/js_checker/free_checker": { - "docsSHA256": null, - "jsSHA256": "445c610c4035848553e1a05d132b24f8aed5eaee088fc0022f74734b189afe6f", - "moduleName": "js_checker/free_checker", - "packageName": "librejs", - "requirements": { - "html_script_finder/bug_fix": "librejs/html_script_finder/bug_fix", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/license_definitions": "librejs/js_checker/license_definitions", - "js_checker/pattern_utils": "librejs/js_checker/pattern_utils", - "sdk/simple-storage": "sdk/simple-storage" - }, - "sectionName": "lib" - }, - "librejs/js_checker/js_checker": { - "docsSHA256": null, - "jsSHA256": "5aefeae7e553157314165bd28998b852dc7c8387153d582f05b453a4b567228c", - "moduleName": "js_checker/js_checker", - "packageName": "librejs", - "requirements": { - "addon_management/prefchange": "librejs/addon_management/prefchange", - "chrome": "chrome", - "html_script_finder/bug_fix": "librejs/html_script_finder/bug_fix", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/free_checker": "librejs/js_checker/free_checker", - "js_checker/nontrivial_checker": "librejs/js_checker/nontrivial_checker", - "js_checker/relation_checker": "librejs/js_checker/relation_checker", - "parser/narcissus_worker": "librejs/parser/narcissus_worker", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/timers": "sdk/timers", - "ui/notification": "librejs/ui/notification" - }, - "sectionName": "lib" - }, - "librejs/js_checker/license_definitions": { - "docsSHA256": null, - "jsSHA256": "e59b0a4595a3143ae40dcde99c64cb1b403994411aa1836f0838064a2ed99974", - "moduleName": "js_checker/license_definitions", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/js_checker/nontrivial_checker": { - "docsSHA256": null, - "jsSHA256": "7df338528a6ec20b2f41f48976d37c26d439a44d43ac991bfb4263d05cc13c7f", - "moduleName": "js_checker/nontrivial_checker", - "packageName": "librejs", - "requirements": { - "js_checker/constant_types": "librejs/js_checker/constant_types" - }, - "sectionName": "lib" - }, - "librejs/js_checker/pattern_utils": { - "docsSHA256": null, - "jsSHA256": "8713284af95d802646022691d72b3b853d6c750eaf37135296662e4eac9c2914", - "moduleName": "js_checker/pattern_utils", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/js_checker/privacy_checker": { - "docsSHA256": null, - "jsSHA256": "8a068ce2daeaffe2b4a76d714ec9a3763ee9f978c57e56f9757cefbc5c648fab", - "moduleName": "js_checker/privacy_checker", - "packageName": "librejs", - "requirements": { - "js_checker/pattern_utils": "librejs/js_checker/pattern_utils", - "js_checker/privacy_threat_definitions.js": "librejs/js_checker/privacy_threat_definitions" - }, - "sectionName": "lib" - }, - "librejs/js_checker/privacy_threat_definitions": { - "docsSHA256": null, - "jsSHA256": "94e6f14ab0212d278f825ddc1f7b828fa2dd0637ec384a255ac84d91370cf482", - "moduleName": "js_checker/privacy_threat_definitions.js", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/js_checker/relation_checker": { - "docsSHA256": null, - "jsSHA256": "54ca8c75c75c62dce31465d8d71581d92d87d45a67efc9ac2d5af2771fe1abdf", - "moduleName": "js_checker/relation_checker", - "packageName": "librejs", - "requirements": { - "js_checker/constant_types": "librejs/js_checker/constant_types" - }, - "sectionName": "lib" - }, - "librejs/main": { - "docsSHA256": null, - "jsSHA256": "7729ed1dc55313d601fde31e512bcf8ef840aef5efdceaa001f498db21adba7c", - "moduleName": "main", - "packageName": "librejs", - "requirements": { - "addon_management/install_uninstall": "librejs/addon_management/install_uninstall", - "addon_management/prefchange": "librejs/addon_management/prefchange", - "chrome": "chrome", - "http_observer/http_request_observer": "librejs/http_observer/http_request_observer", - "pref_observer/pref_observer": "librejs/pref_observer/pref_observer", - "sdk/preferences/service": "sdk/preferences/service", - "settings/storage": "librejs/settings/storage", - "ui": "librejs/ui", - "ui/script_panel.js": "librejs/ui/script_panel", - "ui/ui_info": "librejs/ui/ui_info" - }, - "sectionName": "lib" - }, - "librejs/parser/narcissus_worker": { - "docsSHA256": null, - "jsSHA256": "57ae8c03ad08c7242c43e1a6a4143f31eb176be9687e07f16d8137209d3f83ff", - "moduleName": "parser/narcissus_worker", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "js_checker/js_checker": "librejs/js_checker/js_checker", - "sdk/self": "sdk/self" - }, - "sectionName": "lib" - }, - "librejs/pref_observer/pref_observer": { - "docsSHA256": null, - "jsSHA256": "985652fb6b93b60a46dbe376cc45cff9aba48767da4d3be1f74fc39f22fb450a", - "moduleName": "pref_observer/pref_observer", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "http_observer/http_request_observer": "librejs/http_observer/http_request_observer", - "sdk/preferences/service": "sdk/preferences/service" - }, - "sectionName": "lib" - }, - "librejs/script_entries/accepted_scripts": { - "docsSHA256": null, - "jsSHA256": "aa9e23e7f54bcb935f62d8ad0c8f5bfd3032d32433771154932e355e04852263", - "moduleName": "script_entries/accepted_scripts", - "packageName": "librejs", - "requirements": { - "script_entries/all_scripts": "librejs/script_entries/all_scripts" - }, - "sectionName": "lib" - }, - "librejs/script_entries/all_scripts": { - "docsSHA256": null, - "jsSHA256": "a219023367c56f9698c39731c3a554bb81def6a23f645625adb27bf4804a529c", - "moduleName": "script_entries/all_scripts", - "packageName": "librejs", - "requirements": { - "script_entries/crypto": "librejs/script_entries/crypto" - }, - "sectionName": "lib" - }, - "librejs/script_entries/crypto": { - "docsSHA256": null, - "jsSHA256": "74a2c6893ba9b871f01a340403fee1639dcc78dbe869a9f23bace2478e60abf5", - "moduleName": "script_entries/crypto", - "packageName": "librejs", - "requirements": { - "chrome": "chrome" - }, - "sectionName": "lib" - }, - "librejs/script_entries/dryrun_scripts": { - "docsSHA256": null, - "jsSHA256": "1109c4841a8924f96ab2f27dd64fbecf243a4c00b00a06b7ae8efab51a022e8c", - "moduleName": "script_entries/dryrun_scripts", - "packageName": "librejs", - "requirements": { - "script_entries/all_scripts": "librejs/script_entries/all_scripts", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/script_entries/free_libraries": { - "docsSHA256": null, - "jsSHA256": "07ec51813e419fceda598ca6e279b71fefea60166dc9a9c966bb869b501eaf43", - "moduleName": "script_entries/free_libraries", - "packageName": "librejs", - "requirements": { - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/relation_checker": "librejs/js_checker/relation_checker", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/self": "sdk/self" - }, - "sectionName": "lib" - }, - "librejs/script_entries/removed_scripts": { - "docsSHA256": null, - "jsSHA256": "8ddc24050cbea9f12b31b616bf61b528c1241fff27d14ef0ff3a2fbae531e349", - "moduleName": "script_entries/removed_scripts", - "packageName": "librejs", - "requirements": { - "script_entries/all_scripts": "librejs/script_entries/all_scripts", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/script_entries/scripts_cache": { - "docsSHA256": null, - "jsSHA256": "030b71b0336647a67fe07ddc185a38f240e5d017e1d5f3e16b3bfd19f3ef6e3a", - "moduleName": "script_entries/scripts_cache", - "packageName": "librejs", - "requirements": { - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/relation_checker": "librejs/js_checker/relation_checker", - "script_entries/crypto": "librejs/script_entries/crypto", - "script_entries/free_libraries": "librejs/script_entries/free_libraries", - "ui/notification": "librejs/ui/notification" - }, - "sectionName": "lib" - }, - "librejs/settings/settings_tab": { - "docsSHA256": null, - "jsSHA256": "2b2ea2b657e51109c6caeb4464f75ede476b9fb672a8e550de56cfff33811fa7", - "moduleName": "settings/settings_tab", - "packageName": "librejs", - "requirements": { - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/self": "sdk/self", - "sdk/tabs": "sdk/tabs", - "settings/storage": "librejs/settings/storage" - }, - "sectionName": "lib" - }, - "librejs/settings/storage": { - "docsSHA256": null, - "jsSHA256": "0b1274e63ed9e9cab2bead56dad469a709460a2443eb6aa2bbdb1e5cac4f5306", - "moduleName": "settings/storage", - "packageName": "librejs", - "requirements": { - "chrome": "chrome", - "js_checker/relation_checker": "librejs/js_checker/relation_checker", - "script_entries/free_libraries": "librejs/script_entries/free_libraries", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache" - }, - "sectionName": "lib" - }, - "librejs/ui": { - "docsSHA256": null, - "jsSHA256": "d540923f2af5519a22217c15fb4ee0c32b2f226ac4dbf4343180877a89a6e4bf", - "moduleName": "ui", - "packageName": "librejs", - "requirements": { - "html_script_finder/web_labels/js_web_labels": "librejs/html_script_finder/web_labels/js_web_labels", - "http_observer/allowed_referrers": "librejs/http_observer/allowed_referrers", - "js_checker/constant_types": "librejs/js_checker/constant_types", - "js_checker/js_checker": "librejs/js_checker/js_checker", - "menuitems": "menuitems/menuitems", - "script_entries/accepted_scripts": "librejs/script_entries/accepted_scripts", - "script_entries/dryrun_scripts": "librejs/script_entries/dryrun_scripts", - "script_entries/removed_scripts": "librejs/script_entries/removed_scripts", - "script_entries/scripts_cache": "librejs/script_entries/scripts_cache", - "sdk/panel": "sdk/panel", - "sdk/self": "sdk/self", - "sdk/tabs": "sdk/tabs", - "sdk/ui/button/toggle": "sdk/ui/button/toggle", - "sdk/window/utils": "sdk/window/utils", - "settings/settings_tab": "librejs/settings/settings_tab", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/ui/notification": { - "docsSHA256": null, - "jsSHA256": "43b48acdce02c58b525040972dfc28fbed32fffe1b2eaf0351c198ccedaa9751", - "moduleName": "ui/notification", - "packageName": "librejs", - "requirements": { - "addon_management/prefchange": "librejs/addon_management/prefchange", - "notification-box": "notification-box/notification-box", - "sdk/self": "sdk/self", - "sdk/timers": "sdk/timers" - }, - "sectionName": "lib" - }, - "librejs/ui/script_panel": { - "docsSHA256": null, - "jsSHA256": "98bf80f5942a0a2839b4d2bfa8bd94f8886215f43e80c1fa6d466d6aaa0817fa", - "moduleName": "ui/script_panel.js", - "packageName": "librejs", - "requirements": { - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/ui/ui_info": { - "docsSHA256": null, - "jsSHA256": "44adfa30ccdfa4b671f71c563fa0ea7d0d818f1a7046123c22fd4bec5430e735", - "moduleName": "ui/ui_info", - "packageName": "librejs", - "requirements": { - "addon_management/prefchange": "librejs/addon_management/prefchange", - "sdk/page-mod": "sdk/page-mod", - "sdk/page-worker": "sdk/page-worker", - "sdk/self": "sdk/self", - "sdk/tabs": "sdk/tabs", - "url_handler/url_handler": "librejs/url_handler/url_handler" - }, - "sectionName": "lib" - }, - "librejs/url_handler/node_punycode": { - "docsSHA256": null, - "jsSHA256": "65292808e3b26536463db39fe2d20905969a31112326e5cca7dc31a7117c7287", - "moduleName": "url_handler/node_punycode", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/url_handler/node_querystring": { - "docsSHA256": null, - "jsSHA256": "46e9f5b1f7e935b6ec9e0d3907895b88c21060c687a08661102bcf40af0fdbc4", - "moduleName": "url_handler/node_querystring", - "packageName": "librejs", - "requirements": {}, - "sectionName": "lib" - }, - "librejs/url_handler/node_url": { - "docsSHA256": null, - "jsSHA256": "72082ac4797e25f9051bce5c187ad70a6bb410b76ceb3adf329362eab899a2aa", - "moduleName": "url_handler/node_url", - "packageName": "librejs", - "requirements": { - "url_handler/node_punycode": "librejs/url_handler/node_punycode", - "url_handler/node_querystring": "librejs/url_handler/node_querystring" - }, - "sectionName": "lib" - }, - "librejs/url_handler/url_handler": { - "docsSHA256": null, - "jsSHA256": "19d55c02dea5897a184c4bdf69967f0fbe22f259df4c49ac07ba91fa0efd8674", - "moduleName": "url_handler/url_handler", - "packageName": "librejs", - "requirements": { - "url_handler/node_url": "librejs/url_handler/node_url" - }, - "sectionName": "lib" - }, - "menuitems/menuitems": { - "docsSHA256": "58ad1ff182b33d89a46eb8e0b4847ff84f5403840ddbd03b017a4a855d2008fc", - "jsSHA256": "30d5fc7421841e6ac4ec3756515ac8f2dc3850bed7334f3ff038528d18262524", - "moduleName": "menuitems", - "packageName": "menuitems", - "requirements": { - "sdk/core/heritage": "sdk/core/heritage", - "sdk/core/namespace": "sdk/core/namespace", - "sdk/deprecated/api-utils": "sdk/deprecated/api-utils", - "sdk/deprecated/window-utils": "sdk/deprecated/window-utils", - "sdk/event/core": "sdk/event/core", - "sdk/event/target": "sdk/event/target", - "sdk/window/utils": "sdk/window/utils", - "unload+": "vold-utils/unload+" - }, - "sectionName": "lib" - }, - "notification-box/notification-box": { - "docsSHA256": null, - "jsSHA256": "d7e5a8b906ff408b90622769e175d02e243b1e9b238d7a54ad4be213e03c8454", - "moduleName": "notification-box", - "packageName": "notification-box", - "requirements": { - "chrome": "chrome", - "sdk/window/utils": "sdk/window/utils" - }, - "sectionName": "lib" - }, - "vold-utils/unload+": { - "docsSHA256": "465618992a8bbf3da6425fd79aaec54b92db0353d9670d8dcc1373d14c25b69b", - "jsSHA256": "fbbdfe29fd5cd3ed3593d5720278df4091bd208fc14478fcbff6776fad6c4dd1", - "moduleName": "unload+", - "packageName": "vold-utils", - "requirements": { - "sdk/core/heritage": "sdk/core/heritage", - "sdk/core/namespace": "sdk/core/namespace", - "sdk/system/unload": "sdk/system/unload" - }, - "sectionName": "lib" - } - }, - "metadata": { - "addon-sdk": { - "description": "Add-on development made easy.", - "keywords": [ - "javascript", - "engine", - "addon", - "extension", - "xulrunner", - "firefox", - "browser" - ], - "license": "MPL 2.0", - "name": "addon-sdk" - }, - "librejs": { - "author": "Loic J. Duros", - "description": "GNU LibreJS is an add-on for Mozilla-based browsers (IceCat, Firefox, Abrowser, Iceweasel)\n that prevents the execution of nonfree nontrivial JavaScript as described in \"The Javascript Trap\": http://www.gnu.org/philosophy/javascript-trap.html", - "homepage": "gnu.org/software/librejs/", - "license": "GPL-3.0+", - "main": "lib/main", - "name": "librejs", - "permissions": { - "private-browsing": true, - "unsafe-content-script": true - }, - "version": "6.0.10.20150620" - }, - "menuitems": { - "author": "Erik Vold (http://erikvold.com/) <erikvvold@gmail.com>", - "description": "Menuitems for Jetpacks", - "keywords": [ - "menu", - "menuitems", - "button", - "ui" - ], - "license": "MPL 2.0", - "name": "menuitems", - "version": "1.1.1" - }, - "notification-box": { - "description": "a basic add-on", - "license": "MPL 2.0", - "main": "main", - "name": "notification-box", - "version": "0.1" - }, - "vold-utils": { - "author": "Erik Vold (http://erikvold.com/) <erikvvold@gmail.com>", - "description": "Utilitys for Jetpacks", - "name": "vold-utils", - "version": "1.1" - } - }, - "name": "librejs", - "parseable": false, - "preferences": [ - { - "name": "whitelist", - "title": "Whitelist domain, separated by comma, omit protocol, e.g.: gnu.org, wildcard is *", - "type": "string", - "value": "" - }, - { - "name": "complaint_tab", - "title": "Display complaint tab on sites where nonfree nontrivial JavaScript is detected", - "type": "bool", - "value": true - }, - { - "name": "display_notifications", - "title": "Display notifications of the JavaScript code being analyzed by LibreJS.", - "type": "bool", - "value": false - }, - { - "description": "Initial subject line used in complaint emails", - "name": "complaint_email_subject", - "title": "Complaint email subject", - "type": "string", - "value": "Please make your JavaScript free" - }, - { - "description": "Initial body text used in complaint emails", - "name": "complaint_email_body", - "title": "Complaint email body", - "type": "string", - "value": "I could not use your site because it requires running JavaScript code which is not free software. Since a nonfree program disrespects the user's freedom, I decided not to run it. \\n\\nSee http://gnu.org/philosophy/javascript-trap.html for more information, and please make your JavaScript code free." - } - ], - "preferencesBranch": "jid1-KtlZuoiikVfFew@jetpack", - "sdkVersion": "1.17", - "staticArgs": {}, - "verbose": false -} -\ No newline at end of file diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/install.rdf b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/install.rdf @@ -1,21 +1,27 @@ -<?xml version="1.0" encoding="utf-8"?><!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - <Description about="urn:mozilla:install-manifest"> - <em:id>jid1-KtlZuoiikVfFew@jetpack</em:id> - <em:version>6.0.10.20150620</em:version> - <em:type>2</em:type> - <em:bootstrap>true</em:bootstrap> - <em:unpack>false</em:unpack> +<?xml version="1.0" encoding="utf-8"?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>jid1-KtlZuoiikVfFew@jetpack</em:id> + <em:type>2</em:type> + <em:bootstrap>true</em:bootstrap> + <em:unpack>false</em:unpack> + <em:version>6.0.10</em:version> + <em:name>GNU LibreJS</em:name> + <em:description>GNU LibreJS is an add-on for Mozilla-based browsers (IceCat, Firefox, Abrowser, Iceweasel) + that prevents the execution of nonfree nontrivial JavaScript as described in "The Javascript Trap": http://www.gnu.org/philosophy/javascript-trap.html</em:description> + <em:creator>Loic J. Duros</em:creator> + <em:iconURL>data/widget/images/librejs-64.png</em:iconURL> + <em:homepageURL>https://gnu.org/software/librejs/</em:homepageURL> + <em:optionsURL>data:text/xml,<placeholder/></em:optionsURL> + <em:optionsType>2</em:optionsType> - <!-- Firefox --> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>26.0</em:minVersion> - <em:maxVersion>39.0</em:maxVersion> - </Description> - </em:targetApplication> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>38.0a1</em:minVersion> + <em:maxVersion>43.0</em:maxVersion> +</Description> +</em:targetApplication> <!-- Firefox Mobile for Android --> <em:targetApplication> @@ -26,14 +32,6 @@ </Description> </em:targetApplication> + </Description> - <!-- Front End MetaData --> - <em:name>GNU LibreJS</em:name> - <em:description>GNU LibreJS is an add-on for Mozilla-based browsers (IceCat, Firefox, Abrowser, Iceweasel) - that prevents the execution of nonfree nontrivial JavaScript as described in "The Javascript Trap": http://www.gnu.org/philosophy/javascript-trap.html</em:description> - <em:creator>Loic J. Duros</em:creator> - <em:homepageURL>gnu.org/software/librejs/</em:homepageURL> - <em:optionsType>2</em:optionsType> - - </Description> </RDF> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/addon_management/install_uninstall.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/addon_management/install_uninstall.js @@ -0,0 +1,67 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * The following module is intended to perform tasks when the + * add-on is enabled and disabled. + */ + +const {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +const httpObserver = require("../http_observer/http_request_observer"); +var narcissusWorker = require("../parser/narcissus_worker") + .narcissusWorker; +const caching = require("../http_observer/caching"); + +const prompt = Cc["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Ci.nsIPromptService); + + +const tabs = require('sdk/tabs'); + +/** + * Stop the httpObserver when the add-on is disabled or removed. + */ +exports.onUnload = function(reason) { + if (reason == "disable" || + reason == "shutdown" || + reason == "upgrade" || + reason == "downgrade") { + require("../settings/storage").librejsStorage.writeCacheToDB(); + // remove all http notifications + httpObserver.removeHttpObserver(); + // remove worker. + narcissusWorker.stopWorker(); + } + +}; + +exports.onLoad = function () { + try { + var clearCache = prompt.dialog(null, "LibreJS installation", "If you have tabs and windows opened prior to installing LibreJS, you will have to refresh them for their JavaScript to be analyzed and blocked. Press OK to clear the browser cache."); + if (clearCache) { + caching.clearAllCache(); + } + } catch (e) { + console.debug(e); + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/addon_management/prefchange.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/addon_management/prefchange.js @@ -0,0 +1,126 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var whitelist = []; + +var prefSet = require("sdk/simple-prefs"); +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +var prompt = Cc['@mozilla.org/embedcomp/prompt-service;1']. + getService(Ci.nsIPromptService); +var scriptsCached = require("../script_entries/scripts_cache").scriptsCached; + +var setWhitelist = function () { + whitelist = []; + + var str; + var whitelistString; + if (typeof prefSet.prefs.whitelist === 'undefined') { + whitelistString = ''; + } else { + whitelistString = prefSet.prefs.whitelist.split(','); + } + + for (var i = 0; i < whitelistString.length; i++) { + // remove space, trailing slash, escape any nonalpha except *, + // replace * with .* + str = whitelistString[i] + .replace(" ", "").replace(/\/$/, "") + .replace(/[^a-z0-9\*]/ig, "\\$&").replace("*", ".*"); + + if (str !== '') { + whitelist.push( + new RegExp('^https?:\/\/(www\\.)?' + str + '/', 'i')); + } + } +}; + +exports.getWhitelist = function () { + return whitelist; +}; + +exports.init = function () { + setWhitelist(); +}; + +prefSet.on("whitelist", setWhitelist); + +/*var setDryRun = function () { + var dryRun = prefSet.prefs.dryrun; + if (dryRun === true) { + prompt.alert(null, "LibreJS Dry Run Mode", "Is Dry Run Mode really what you want? LibreJS will still analyze JavaScript on a page, but it will not block any of it. As a result, ALL of the JavaScript on a page will run as is, whether it is free and trivial or not. You will not be warned again. Uncheck that box if you are unsure."); + scriptsCached.resetCache(); + } else { + prompt.alert(null, "LibreJS Dry Run Mode", "LibreJS Dry Run Mode is now disabled"); + } +};*/ + +//prefSet.on("dryrun", setDryRun); + +/*exports.isDryRun = function () { + // Returns true if dryRun mode is enabled. False otherwise. + //return prefSet.prefs.dryrun; + return false; +};*/ + +var setComplaintTab = function () { + var complaintTab = prefSet.prefs.complaint_tab; + if (complaintTab === true) { + prompt.alert(null, "Turning on complaint tab", "A complaint tab will be displayed on pages where nonfree nontrivial JavaScript is found and contact information is found as well."); + } else { + prompt.alert(null, "Turning off complaint tab", "No complaint tab will appear on pages, even when nonfree nontrivial JavaScript is found."); + } +}; +prefSet.on("complaint_tab", setComplaintTab); + +exports.isComplaintTab = function () { + /** + * Returns true if complaint tab mode is enabled. False otherwise. + */ + return prefSet.prefs.complaint_tab; +}; + +var setDisplayNotifications = function () { + var displayNotifications = prefSet.prefs.display_notifications; + if (displayNotifications === true) { + prompt.alert(null, "Turning on notifications", "Notifications with code snippets will now appear while LibreJS is analyzing JavaScript on a page."); + } else { + prompt.alert(null, "Turning off notifications", "Notifications of code being analyzed will not be displayed."); + } +}; + +prefSet.on("display_notifications", setDisplayNotifications); + +exports.isDisplayNotifications = function () { + /** + * Returns true if complaint tab mode is enabled. False otherwise. + */ + return prefSet.prefs.display_notifications; +}; + +exports.complaintEmailSubject = function() { + return prefSet.prefs.complaint_email_subject; +}; + +exports.complaintEmailBody = function() { + return prefSet.prefs.complaint_email_body; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/bug_fix.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/bug_fix.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler.js @@ -0,0 +1,570 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * + * dom_handler.js + * + * After the HTML DOM has been parsed, domHandler finds all the scripts + * on a page (including inline, on-page, and external files), and triggers the + * JavaScript analysis for each of them. + * + */ + +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +var scriptProperties = require("./dom_handler/script_properties"); + +const scriptTypes = scriptProperties.scriptTypes; +const statusTypes = scriptProperties.statusTypes; +const reasons = scriptProperties.reasons; + +var urlHandler = require("../url_handler/url_handler"); + +var WebLabelFinder = require("./web_labels/js_web_labels").WebLabelFinder; + +// object model for script entries. +var scriptObject = require("./dom_handler/script_object"); + +var privacyChecker = require("../js_checker/privacy_checker").privacyCheck; +var jsChecker = require("../js_checker/js_checker"); +const types = require("../js_checker/constant_types"); + +var checkTypes = types.checkTypes; + +var stripCDATAOpen = /<\!\[CDATA\[/gi; +var stripCDATAClose = /]]>/g; + +var isDryRun = require("../addon_management/prefchange").isDryRun; +var allowedRef = require('../http_observer/allowed_referrers') + .allowedReferrers; +var attributeHelpers = require("./dom_handler/attributes"); + +// javascript:* +var jsInAttrRe = attributeHelpers.jsInAttrRe; + +// the list of all available event attributes +var intrinsicEvents = attributeHelpers.intrinsicEvents; + +var domGatherer = require("./dom_handler/dom_gatherer").domGatherer; +var domChecker = require("./dom_handler/dom_checker").domChecker; + +/** + * The DomHandler object takes a whole document, + * finds script elements within that DOM, analyzes them + * using the js_checker module and finally returns a cleaned + * DOM depending on the result. + */ +var DomHandler = function() { + // external object with methods used + // in DomHandler + this.domGatherer = null; + + // external object with methods used + // in DomHandler + this.domChecker = null; + + this.dom = null; + this.pageURL = null; + + // fragment found in url. + this.fragment = null; + + // array containing all scripts on a page. + this.domScripts = []; + + // array containing all scripts on a page, + // data related to them, such as parse tree, ... + this.inlineScripts = []; + + this.externalScripts = []; + + // all scripts. + this.scripts = []; + + // keeps track of the number of scripts. + this.numScripts = 0; + + // store the reference to the callback method + // presumably from htmlParser. + this.callback = function() {}; + + // boolean set to true if external scripts are loaded + // from the html page. + this.loadsHtmlExternalScripts = false; + + this.jsCheckString = null; + + /* object containing boolean property set to false if trivialness + is not allowed anymore (if another script defines ajax requests, + ...) */ + this.allowTrivial = null; + + // boolean set to true if inline JavaScript + // is found to be free. + this.inlineJsFree = null; + + // boolean set to true when at least one script + // has been removed. + this.hasRemovedScripts = null; + + // boolean to check if scripts were removed + // prevents removeAllJs from running multiple times. + this.removedAllScripts = null; + + // will eventually contain an array of data + // for the js web labels licenses. + this.licenseList = []; + + // the response status for the page (200, 404, ...) + this.responseStatus = null; + + // number of scripts fully tested. + this.scriptsTested = 0; + + // number of external scripts to be tested. + this.numExternalScripts = null; + + // number of inline/inattribute scripts + this.numInlineScripts = null; +}; + +/** + * Initialize properties of the object + * + * @param {domObject} obj A reference of the DOM object being + * analyzed. + * + * @param {pageURL} string The formatted URL (with fragment + * removed) of the corresponding page for this DOM + * + * @param {fragment} the #fragment from the url if applicable. + * + * @param {callback} the callback function. + * + */ +DomHandler.prototype.init = function( + domObject, pageURL, fragment, responseStatus, callback +) { + // initialize object properties. + + console.debug('init', pageURL); + var that = this; + + this.reset(); + + // arguments passed. + this.dom = domObject; + this.pageURL = pageURL; + this.fragment = fragment; + this.responseStatus = responseStatus; + + console.debug('in dom handler, responseStatus is', this.responseStatus); + + // make callback function available + // for the entire object. + this.callback = function (dom) { + callback(dom); + that.destroy(); + }; +}; + +DomHandler.prototype.reset = function () { + + this.dom = null; + // arrays. + this.onEventElement = []; + this.scriptStatus = []; + this.inlineScripts = []; + this.externalScripts = []; + this.scripts = []; + + // booleans + this.allowTrivial = true; + this.inlineJsFree = false; + this.hasRemovedScripts = false; + this.removedAllScripts = false; + + // we start with 0, and will increment in + // dom_checker. + this.numExternalScripts = 0; + + this.numInlineScripts = 0; + + this.scriptsTested = 0; + +}; + +DomHandler.prototype.destroy = function () { + this.domGatherer = null; + this.domChecker = null; + /* destroy callback so that it can't be called multiple times. */ + this.callback = function() {}; + //this.reset(); +}; + +DomHandler.prototype.scriptHasBeenTested = function() { + this.scriptsTested++; + console.debug('incremented DomHandler.scriptsTested to', + this.scriptsTested); +}; + +/** + * scriptHasJsWebLabel + * + * Checks if a script was found earlier in a Js License Web Label + * table. See http://www.gnu.org/licenses/javascript-labels.html + * for more information. + * + */ +DomHandler.prototype.scriptHasJsWebLabel = function(script) { + if (this.licenseList) { + + var url = urlHandler.resolve(this.pageURL, script.src), + i = 0, + len = this.licenseList.length; + + console.debug('looking for web label'); + + for (; i < len; i++) { + if (this.licenseList[i].fileUrl === url && + this.licenseList[i].free === true + ) { + console.debug('found something true'); + console.debug( + this.licenseList[i].fileUrl, ' is found'); + return true; + } + } + } + return false; +}; + +/** + * processScripts. + * Starts by looking for a js web labels page + * then calls the complete function, which runs + * the rest of the check. + */ +DomHandler.prototype.processScripts = function () { + var that = this; + + // check for the existence of the + // js web labels first. + this.lookForJsWebLabels(function () { + + // gather and check all script elements on + // page. + console.debug("Calling checkAllScripts"); + that.checkAllScripts(); + + }); + +}; + +/** + * jsWebLabelsComplete + * + */ +DomHandler.prototype.checkAllScripts = function () { + try { + console.debug( + 'found in', this.pageURL, JSON.stringify(this.licenseList)); + console.debug('checkAllScripts triggered async'); + + // use domGatherer to gather scripts. + this.domGatherer.findScripts(); + this.domGatherer.gatherScriptsContent(); + this.domGatherer.gatherIntrinsicEvents(); + + console.debug('fragment is', this.fragment); + + if ( + this.fragment === undefined || + this.fragment === null || + this.fragment.indexOf('librejs=true') < 0 + ) { + try { + + // use domChecker to check scripts. + console.debug("Calling checkAllInlineScripts"); + this.domChecker.checkAllInlineScripts(); + } catch (x) { + console.debug('error in domChecker:', x, x.lineNumber); + this.removeAllJs(); + } + } else { + console.debug('This is a pageworker, removing all js'); + // this is the Page Worker to find contact link + // just remove all the JS since we don't need it. + console.debug('fragment found, remove js'); + this.removeAllJs(); + } + } catch (x) { + console.debug('error', x, x.lineNumber, x.fileName); + } +}; + +/** + * lookForJsWebLabels + * + * Checks if a link to a js web label table exists. + * If it does, return an array of objects with the data + * gathered (script name, path, license name, url, ...) + * + */ +DomHandler.prototype.lookForJsWebLabels = function (completed) { + var that = this; + console.debug("calling lookForJsWebLabels"); + if (this.fragment !== '#librejs=true') { + var webLabelFinder = new WebLabelFinder(); + webLabelFinder.init( + this.dom, + this.pageURL, + function (licenseList) { + // assign array returned to property. + that.licenseList = licenseList; + console.debug("calling completed"); + completed(); + }); + } else { + completed(); + } +}; + +DomHandler.prototype.checkScriptForJsWebLabels = function(script) { + var scriptEntry; + + if (this.hasSrc(script) && this.scriptHasJsWebLabel(script)) { + // This script is in the list of allowed scripts (through web labels) + scriptEntry = scriptObject.Script({ + 'type': scriptTypes.EXTERNAL, + 'status': statusTypes.ACCEPTED, + 'element': script, + 'url': urlHandler.resolve(this.pageURL, script.src) + }); + + scriptEntry.tagAsAccepted(this.pageURL, reasons.FREE); + return true; + } +}; + +/** + * hasSrc + * Check the given script has an src attribute. + * @param script obj The script element. + * @return a string with the value of the src attribute. + */ +DomHandler.prototype.hasSrc = function(script) { + if (script.src) { + return script.src; + } + return false; +}; + +/** + * Uses relationChecker to guess whether the script only uses + * predefined functions/variables or interacts with other scripts + * (this is still very experimental and needs improvement.) + * + */ +DomHandler.prototype.removeScriptIfDependent = function (script) { + var nonWindowProps = script.tree.relationChecker.nonWindowProperties; + + for (var entry in nonWindowProps) { + if (nonWindowProps[entry]) { + console.debug('script has non window properties.'); + this.removeGivenJs(script, reasons.TRIVIAL_NOT_ALLOWED); + return true; + } + } +}; + +/** + * removeGivenJs + * Remove a single script from the DOM. + * @param script Obj The script element to be removed from the + * DOM. + * + */ +DomHandler.prototype.removeGivenJs = function (script, reason, singleton, hash) { + var commentedOut; + var isAllowed = allowedRef.urlInAllowedReferrers(this.pageURL); + console.debug("removing given js hash", hash); + + if (script.status != statusTypes.REJECTED && + script.status != statusTypes.JSWEBLABEL + ) { + console.debug('removing a', script.type); + if (script.type === scriptTypes.ATTRIBUTE && + !isAllowed + ) { + this.removeGivenAttribute(script, reason); + return; + } + if (!isAllowed) { + // set invalid type if dry run off. + script.element.setAttribute('type', 'librejs/blocked'); + // add entry as removed. + console.debug('removeGivenJs hash is', hash); + script.tagAsRemoved(this.pageURL, reason, hash); + } else { + script.element.setAttribute( + 'data-librejs-dryrun', 'librejs/blocked'); + script.tagAsDryRun(this.pageURL, reason, hash); + } + + if (singleton === true) { + // flag singletons. + script.element.setAttribute('data-singleton', 'true'); + } + + // remove src if dry run off. + if (script.element.getAttribute('src') !== undefined) { + script.element.setAttribute( + 'data-librejs-blocked-src', + script.element.getAttribute('src') + ); + if (!isAllowed) { + script.element.removeAttribute('src'); + } + } + if (isAllowed) { + comment_str = 'LibreJS: Script should be blocked, but page is whitelisted.'; + script.status = statusTypes.ACCEPTED; + } else { + comment_str = 'LibreJS: script blocked.'; + script.status = statusTypes.REJECTED; + } + + commentedOut = this.dom.createComment(comment_str); + // add a comment for curious source readers. + script.element.parentNode.appendChild(commentedOut); + script.element.parentNode.insertBefore(commentedOut, script.element); + this.hasRemovedScripts = true; + } +}; + +DomHandler.prototype.removeGivenAttribute = function (script, reason) { + var i = 0, + le = script.jsAttributes.length; + + console.debug('removing given attribute', script, reason); + script.element.setAttribute('data-librejs-blocked-event', + JSON.stringify(script.jsAttributes)); + + script.tagAsRemoved(this.pageURL, reason, script.hash || script.tree.hash); + + // might need to be removed. + script.element.setAttribute('data-librejs-blocked-value', ''); + + if (!allowedRef.urlInAllowedReferrers(this.pageURL)) { + // only run if not in dry run mode. + for (; i < le; i++) { + console.debug('removing attribute', JSON.stringify(script.jsAttributes)); + script.element.removeAttribute(script.jsAttributes[i].attribute); + } + } else { + + } + this.hasRemovedScripts = true; +}; + +/** + * removeAllJs + * Loop through all scripts from top to bottom and add a type + * attribute 'librejs/blocked' to prevent their interpretation + * by the browser. + * + */ +DomHandler.prototype.removeAllJs = function (reason) { + // remove all js is useless from now on. + console.debug('removeAllJs'); + this.hasRemovedScripts = true; + + // removeAllJs needs not be run next time. + this.removedAllScripts = true; + + try { + this.removeAllArray(this.scripts, reason); + this.callback(this.dom); + } catch (x) { + console.debug( + 'in removeAllJs method: ', + x, + 'number of scripts is', + this.numScripts + ); + this.callback(this.dom); + } + +}; + +DomHandler.prototype.removeAllArray = function(scriptArray, reason) { + var script, i = 0, le; + console.debug('removeAllArray'); + try { + le = scriptArray.length; + // loop through all scripts. + + for (; i < le; i++) { + script = scriptArray[i]; + if (script.type === scriptTypes.INLINE || + script.type === scriptTypes.EXTERNAL + ) { + this.removeGivenJs(script, reason); + } + else if (script.type === scriptTypes.ATTRIBUTE) { + this.removeGivenAttribute(script, reason); + } + } + } catch (e) { + this.callback(""); + } + +}; + +exports.DomHandler = DomHandler; + +/** + * exports.domHandler + * Instantiates a DomHandler and checks the DOM + * @param dom obj The given dom for analysis. + * @param pageURL string the URL for the page. + * @param callback function callback when all the work has been performed. + */ +exports.domHandler = function( + dom, pageURL, fragment, responseStatus, callback) { + console.debug("Creating domHandler"); + var domHandler = new DomHandler(); + domHandler.init(dom, pageURL, fragment, responseStatus, callback); + + // use domGatherer methods. + domHandler.domGatherer = domGatherer(domHandler); + + // use domChecker methods. + domHandler.domChecker = domChecker(domHandler); + + // launch the whole process. + console.debug("Calling processScripts"); + domHandler.processScripts(); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/attributes.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/attributes.js @@ -0,0 +1,138 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +// object model for script entries. +var scriptObject = require("./script_object"); +var scriptProperties = require("./script_properties"); + +const scriptTypes = scriptProperties.scriptTypes; + +const statusTypes = scriptProperties.statusTypes; + +var jsInAttrRe = /javascript:/ig; + +// the list of all available event attributes +var intrinsicEvents = [ + "onload", + "onunload", + "onclick", + "ondblclick", + "onmousedown", + "onmouseup", + "onmouseover", + "onmousemove", + "onmouseout", + "onfocus", + "onblur", + "onkeypress", + "onkeydown", + "onkeyup", + "onsubmit", + "onreset", + "onselect", + "onchange"]; + +exports.jsInAttrRe = jsInAttrRe; +exports.intrinsicEvents = intrinsicEvents; + + +/** + * findJSinAttribute + * + * Looks for attributes containing 'javascript:' + * + */ +exports.findJSinAttribute = function (elem, callback) { + var i = 0, attrLen = elem.attributes.length; + + var attribPairs = []; + + for (; i < attrLen; i++) { + + //looping through all attributes in elem to look for "javascript:" + attrib = elem.attributes[i]; + + if (attrib.value.match(jsInAttrRe)) { + str = attrib.value.replace(jsInAttrRe, ''); + attribPairs.push({attribute: attrib.name, value: str}); + } + + } + + if (attribPairs.length > 0) { + // contains in attribute javascript. + scriptEntry = scriptObject.Script({'type': scriptTypes.ATTRIBUTE, + 'status': statusTypes.UNCHECKED, + 'element': elem, + 'jsAttributes': attribPairs + }); + + // push back to DOMHandler + callback(scriptEntry); + + } else { + callback(false); + } + +}; + +/** + * findOnJSAttribute. + * + * Look for attributes in on* + * + */ +exports.findOnJSAttribute = function (elem, callback) { + + var i = 0, eventsLen = intrinsicEvents.length; + + var attribPairs = []; + + for (; i < eventsLen; i++) { + + // looping through all on* attributes + if (elem.hasAttribute(intrinsicEvents[i])) { + + attribPairs.push({ + attribute: intrinsicEvents[i], + value: elem.getAttribute(intrinsicEvents[i]) + }); + + } + + } + if (attribPairs.length > 0) { + + console.debug('found an attribute', scriptTypes.ATTRIBUTE); + scriptEntry = scriptObject.Script({'type': scriptTypes.ATTRIBUTE, + 'status': statusTypes.UNCHECKED, + 'element':elem, + 'jsAttributes': attribPairs + }); + // Push back to DOMHandler. + // push back to DOMHandler + callback(scriptEntry); + + } else { + callback(false); + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/dom_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/dom_checker.js @@ -0,0 +1,480 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * dom_checker.js + * + * checks scripts for nonfree/nontrivial. + * + */ + +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); +var timer = require("sdk/timers"); + +var scriptProperties = require("./script_properties"); +const scriptTypes = scriptProperties.scriptTypes; +const statusTypes = scriptProperties.statusTypes; +const reasons = scriptProperties.reasons; + +// ensure xhr won't create an infinite loop +// with html content. +var urlTester = require("../url_seen_tester").urlSeenTester; +var urlHandler = require("../../url_handler/url_handler"); + +var privacyChecker = require("../../js_checker/privacy_checker").privacyCheck; +var jsChecker = require("../../js_checker/js_checker"); + +const types = require("../../js_checker/constant_types"); +var checkTypes = types.checkTypes; +var stripCDATAOpen = /<\!\[CDATA\[/gi; +var stripCDATAClose = /]]>/g; + +const getHash = require("../../script_entries/scripts_cache") + .scriptsCached.getHash; + +var DomChecker = function() { + // reference to domHandler instance + // using this object. + this.d = null; +}; + +/** + * init + * + * assign a reference domHandler object + * to access/updates its properties. + * + */ +DomChecker.prototype.init = function(domHandler) { + "use strict"; + + this.d = domHandler; +}; + +DomChecker.prototype.destroy = function() { + "use strict"; + + this.d = null; +}; + +/** + * checkAllInlineScripts + * + * Sends all the inline/onpage scripts as a whole for a check and + * removes all scripts if nonfree nontrivial is found. + * + */ +DomChecker.prototype.checkAllInlineScripts = function() { + "use strict"; + + try { + var i = 0, len, script; + + if (typeof this.d.inlineScripts !== 'undefined' && + this.d.inlineScripts.length > 0 + ) { + script = this.d.inlineScripts.shift(); + console.debug("checking script for page", + this.d.pageURL + /*, JSON.stringify(script)*/); + if (this.d.removedAllScripts) { + // all js has already been removed. + // stop check. + console.debug("removed all"); + return; + } + + if (this.d.inlineJsFree === true) { + // add entry as accepted. + try { + hash = getHash(script.text); + script.tagAsAccepted(this.d.pageURL, reasons.FREE, hash); + } catch (e) { + console.debug(e); + } + } + + // even if page is free we need to check for allow trivial. + if (script.type === scriptTypes.INLINE) { + console.debug("analyzing script", script); + this.analyzeJs(script, + script.text, + this.checkSingleInlineScript.bind(this)); + } else if (script.type === scriptTypes.ATTRIBUTE) { + console.debug("analyzing inline script", script); + this.analyzeJs(script, + this.concatAttributes(script), + this.checkSingleElementAttributes.bind(this)); + } + } else { + // no more inline scripts. Switch to external scripts. + this.readyForExternal(); + } + } catch (x) { + console.debug('checkAllInlineScripts error', + x, x.lineNumber, x.fileName); + this.readyForExternal(); + } +}; + +DomChecker.prototype.concatAttributes = function(script) { + "use strict"; + var i = 0, + le = script.jsAttributes.length, + text = ""; + + // we concatenate all js in multiple attributes. + // because it's too much of a hassle to keep track + // otherwise. + for (; i < le; i++) { + text += script.jsAttributes[i].value + '\n'; + } + + return text; +}; + +/** + * + * check a single element with attributes + */ +DomChecker.prototype.checkSingleElementAttributes = function( + script, loadedScript, checker) { + "use strict"; + var check, value, + i = 0, + le = script.jsAttributes.length, + text = ""; + + try { + check = checker.parseTree.freeTrivialCheck; + script.tree = checker; + script.result = check; + script.status = statusTypes.CHECKED; + } catch (e) { + console.debug('problem checking inline scripts', e, e.lineNumber); + this.d.removeGivenJs(script); + } + + this.processInlineCheckResult(script, check, checker); +}; + +DomChecker.prototype.processInlineCheckResult = function( + script, check, checker) { + "use strict"; + console.debug("check.reason is", check.reason, "and type", check.type); + var hash = checker.hash; + + if (this.d.inlineJsFree === true) { + console.debug('tagging', script.text, 'as accepted', "with reason", check.reason); + script.tagAsAccepted(this.d.pageURL, this.d.freeReason + " -- " + check.reason, hash); + } + + // process the result. + if (check.type === checkTypes.FREE) { + // this is free. + console.debug('tagging', script.text, 'as accepted with reason', check.reason); + this.d.inlineJsFree = true; + this.d.freeReason = check.reason; + // add entry as accepted. + script.tagAsAccepted(this.d.pageURL, check.reason, hash); + } else if (check.type === checkTypes.FREE_SINGLE_ITEM) { + // accept this script. + console.debug("free single item, ", check.reason); + script.tagAsAccepted(this.d.pageURL, check.reason, hash); + } else if (check.type === checkTypes.NONTRIVIAL) { + console.debug("nontrivial hash is", hash); + if (this.d.inlineJsFree) { + // inline is free. So accept. + console.debug('tagging', script.text, 'as accepted'); + script.tagAsAccepted( + this.d.pageURL, + this.d.freeReason + ' -- ' + check.reason, + hash); + } else { + console.debug('tagging', script.text, 'as removed'); + this.d.removeGivenJs(script, check.reason, false, hash); + } + } else if (!this.d.inlineJsFree && + this.d.loadsHtmlExternalScripts && + check.type === checkTypes.TRIVIAL_DEFINES_FUNCTION + ) { + // nontrivial, because defines function and loads + // external scripts + console.debug('tagging', script.text, 'as removed'); + this.d.removeGivenJs(script, reasons.FUNCTIONS_INLINE, false, hash); + } else if (!this.d.loadsHtmlExternalScripts && + check === checkTypes.TRIVIAL_DEFINES_FUNCTION + ) { + console.debug("Tag as accepted doesn't load another external script"); + script.tagAsAccepted(this.d.pageURL, check.reason, hash); + } else if (check.type === checkTypes.TRIVIAL || + check.type === checkTypes.TRIVIAL_DEFINES_FUNCTION || + check.type === checkTypes.WHITELISTED + ) { + // add entry as accepted. + console.debug("Trivial accepted"); + script.tagAsAccepted(this.d.pageURL, check.reason, hash); + } + + // next inline script, if applicable. + this.checkAllInlineScripts(); +}; + +DomChecker.prototype.readyForExternal = function() { + "use strict"; + + console.debug('DomChecker.readyForExternal'); + // done with those inline scripts, continue with + // the rest. + this.checkExternalScripts(); +}; + +/** + * check a single inline script. + */ +DomChecker.prototype.checkSingleInlineScript = function( + script, loadedScript, checker) { + "use strict"; + var check, text; + + console.debug('DomChecker.checkSingleInlineScript'); + + try { + + check = checker.parseTree.freeTrivialCheck; + + // update status. + script.tree = checker; + script.result = check; + console.debug("script result is", check.type); + script.status = statusTypes.CHECKED; + + } catch (e) { + console.debug('problem checking inline scripts', e, e.lineNumber); + this.d.removeGivenJs(script, '', false, checker.hash); + } + + this.processInlineCheckResult(script, check, checker); + +}; + +/** + * checkExternalScripts + * Loop through series of external scripts, + * perform xhr to get their data, and check them + * to see whether they are free/nontrivial + * + */ +DomChecker.prototype.checkExternalScripts = function() { + "use strict"; + + console.debug('DomChecker.checkExternalScripts'); + + var i = 0; + var len = this.d.externalScripts.length; + var that = this; + + console.debug("externalScripts length", len); + if (this.d.removedAllScripts || len === 0) { + // all js has already been removed. + // stop check. + this.wrapUpBeforeLeaving(); + return; + } + + for (; i < len; i++) { + this.xhr( + this.d.externalScripts[i], + function(script, scriptText) { + console.debug("In xhr callback for script url:", script.url); + if (scriptText === false) { + that.d.removeGivenJs(script); + that.d.scriptHasBeenTested(); + that.externalCheckIsDone(); + return; + } + + console.debug('about to analyzeJS for script:', script.url); + that.analyzeJs( + script, + scriptText, + that.checkSingleExternalScript.bind(that)); + } + ); + } +}; + +DomChecker.prototype.wrapUpBeforeLeaving = function() { + "use strict"; + + console.debug("wrap up before leaving triggered"); + console.debug('wrapping up'); + this.d.callback(this.d.dom); + +}; + +DomChecker.prototype.analyzeJs = function(script, scriptText, callback) { + "use strict"; + console.debug('DomChecker.analyzeJs for script:', script.url); + try { + var checker = jsChecker.jsChecker(); + var url = ""; + if (typeof script.url !== "undefined") { + url = script.url; + } else { + url = this.pageURL; + } + checker.searchJs(scriptText, function() { + console.debug("Analyze JS"/*, JSON.stringify(checker)*/); + timer.setTimeout(function() { + callback(script, scriptText, checker); + }, 0); + }, url); + } catch (x) { + console.debug('error', x, x.lineNumber, x.fileName); + } +}; + +/** + * Check a single external script. + */ +DomChecker.prototype.checkSingleExternalScript = function( + script, loadedScript, checker +) { + "use strict"; + var check; + + console.debug('DomChecker.checkSingleExternalScript()'); + try { + check = checker.parseTree.freeTrivialCheck; + + script.tree = checker; + script.result = check; + console.debug('in checkSingleExternalScript, checker.hash is', + checker.hash); + if (script.status != statusTypes.JSWEBLABEL) { + script.status = statusTypes.CHECKED; + } + + if (check.type === checkTypes.FREE || + check.type === checkTypes.FREE_SINGLE_ITEM + ) { + // add entry as accepted. + script.tagAsAccepted(this.d.pageURL, check.reason, checker.hash); + } + + else if (check.type === checkTypes.NONTRIVIAL) { + console.debug("Removing given js", check.reason); + this.d.removeGivenJs(script, check.reason, false, checker.hash); + } + + else if (check.type === checkTypes.TRIVIAL || + check.type === checkTypes.WHITELISTED + ) { + // if it's accepted, allow. + script.tagAsAccepted(this.d.pageURL, check.reason, checker.hash); + } else { + // anything else is nontrivial. Including TRIVIAL_DEFINES_FUNCTION. + console.debug("checker hash for remove is ", checker.hash); + this.d.removeGivenJs( + script, reasons.FUNCTIONS_EXTERNAL, false, checker.hash); + } + + } catch (e) { + console.debug('error in checkExternalScript', + e, e.lineNumber, 'for script', script.url); + + this.d.removeAllJs(); + this.destroy(); + return; + } + console.debug('script url is', script.url, 'result is', script.result); + this.d.scriptHasBeenTested(); + this.externalCheckIsDone(); +}; + +DomChecker.prototype.externalCheckIsDone = function() { + "use strict"; + console.debug('DomChecker.externalCheckIsDone'); + + console.debug('scriptsTested is', this.d.scriptsTested); + console.debug('num external', this.d.numExternalScripts); + + if (this.d.scriptsTested >= this.d.numExternalScripts) { + console.debug('wrapping up external'); + this.wrapUpBeforeLeaving(); + } else { + var scriptsToCheck = this.d.numExternalScripts - this.d.scriptsTested; + console.debug('Not wrapping up! Waiting to check ' + scriptsToCheck + + ' more script(s)'); + + if (this.d.externalScripts[0]) { + console.debug('script 0 is', this.d.externalScripts[0]); + } + if (this.d.externalScripts[1]) { + console.debug('script 1 is', this.d.externalScripts[1]); + } + } +}; + +/** + * xhr + * Perform a XMLHttpRequest on the url given. + * @param url string A URL. + * @return The response text. + */ +DomChecker.prototype.xhr = function(script, responseCallback) { + "use strict"; + + var regex = /^text\/html/i; + var url = script.url; + + try { + // add url to whitelist. + urlTester.addUrl(url); + + // request module. Compatible with Https-Everywhere. + require('./request').request(script, responseCallback).request(); + } catch (x) { + console.debug('error', x, x.lineNumber, x.fileName); + responseCallback(script, false); + } +}; + +/** + * exports.domChecker + * Instantiate a brand new clone of the domChecker. + * @param dom obj The given dom for analysis. + * @param pageURL string the URL for the page. + * @param callback function callback when all the work has been performed. + */ +exports.domChecker = function(domHandler) { + "use strict"; + + var domChecker = new DomChecker(); + + domChecker.init(domHandler); + + return domChecker; +}; + +exports.xhr = new DomChecker().xhr; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/dom_gatherer.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/dom_gatherer.js @@ -0,0 +1,286 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var scriptProperties = require("./script_properties"); + +const scriptTypes = scriptProperties.scriptTypes; +const scriptsCached = require("../../script_entries/scripts_cache") + .scriptsCached; + +const statusTypes = scriptProperties.statusTypes; +// object model for script entries. +var scriptObject = require("./script_object"); + +var urlHandler = require("../../url_handler/url_handler"); + +var attributeHelpers = require("./attributes"); + +// javascript:* +var jsInAttrRe = attributeHelpers.jsInAttrRe; + +// the list of all available event attributes +var intrinsicEvents = attributeHelpers.intrinsicEvents; + +var privacyChecker = require("../../js_checker/privacy_checker").privacyCheck; + +const types = require("../../js_checker/constant_types"); + +var checkTypes = types.checkTypes; + +// array reflex valid types as listed in +// http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsScriptLoader.cpp#437 +// anything appended to end of strings is considered valid: +var jsValidTypes = [ + /^text\/javascript/i, + /^text\/ecmascript/i, + /^application\/javascript/i, + /^application\/ecmascript/i, + /^application\/x-javascript/i +]; + +var stripCDATAOpen = /<\!\[CDATA\[/gi; +var stripCDATAClose = /]]>/g; + +var stripHtmlCommentsInScript = function (s) { + s = s.replace(stripCDATAOpen, ''); + s = s.replace(stripCDATAClose, ''); + return s; +}; + + +// gather scripts and javascript in attributes across a dom object. +var DomGatherer = function() { + // domHandler object. + this.d = null; +}; + +/** + * init + * + * assign a reference domHandler object + * to access/updates its properties. + * + */ +DomGatherer.prototype.init = function (domHandler) { + this.d = domHandler; +}; + +/** + * scriptHasInvalidType + * + * Checks that a script does not have a js "template" type. + * Normally any script that has a type attribute other than the + * few allowed ones is not interpreted. But by security, we only + * discard a few of them. + * + * @param script obj The script element. + * @return returns true if it matches a template type. + * + */ +DomGatherer.prototype.scriptHasInvalidType = function (script) { + var i = 0, + le = jsValidTypes.length; + + var type = script.getAttribute('type'); + + if (type === 'librejs/blocked') { + // js has already been blocked. + return true; + } + + if (!type) { + // type isn't set, don't look further. + return false; + } + + for (; i < le; i++) { + if (jsValidTypes[i].test(type)) { + return false; + } + } + + // type is invalid and + // hence cannot be executed. + return true; +}; + +/** + * findScripts + * + * Assigns the array of scripts in the dom to a property + * as well as a number of scripts present for looping purposing. + */ +DomGatherer.prototype.findScripts = function() { + this.d.domScripts = this.d.dom.getElementsByTagName('script'); + this.d.numScripts = this.d.domScripts.length; +}; + +/** + * gatherIntrinsicEvents + * + * Fetches all the event attributes that might contain JavaScript + * as well as all element attributes that start with + * "javascript:". + * + */ +DomGatherer.prototype.gatherIntrinsicEvents = function() { + var i = 0, j, k, + all = this.d.dom.getElementsByTagName('*'), + max = all.length, + that = this, + attrLen, attrib, str, scriptEntry; + + for (; i < max; i++) { + // look for attributes with value javascript:* + attributeHelpers.findJSinAttribute( + all[i], + function (scriptEntry) { + if (scriptEntry !== false) { + + that.d.inlineScripts.push(scriptEntry); + that.d.scripts.push(scriptEntry); + + // add inline script in the count. + that.d.numInlineScripts++; + } + }); + + // look for attributes of on* (onLoad, ...) + attributeHelpers.findOnJSAttribute( + all[i], + function (scriptEntry) { + if (scriptEntry !== false) { + that.d.inlineScripts.push(scriptEntry); + that.d.scripts.push(scriptEntry); + + // add inline script in the count. + that.d.numInlineScripts++; + } + }); + } + +}; + +/** + * gatherScriptsContent + * + * Aggregate all content within on-page JavaScript code. + * Keep a list of all absolute urls to external scripts. + * + */ +DomGatherer.prototype.gatherScriptsContent = function() { + var i = 0, currentScript = '', absolutePath, scriptEntry, + that = this; + try { + for (; i < this.d.numScripts; i++) { + if (this.d.checkScriptForJsWebLabels(this.d.domScripts[i])) { + //break; + absolutePath = urlHandler.resolve( + this.d.pageURL, this.d.domScripts[i].src); + scriptEntry = scriptObject.Script( + {'type': scriptTypes.EXTERNAL, + 'status': statusTypes.JSWEBLABEL, + 'element': this.d.domScripts[i], + 'url': absolutePath}); + scriptEntry.tree = {}; + + this.d.externalScripts.push(scriptEntry); + that.d.scripts.push(scriptEntry); + + this.d.loadsHtmlExternalScripts = true; + + // increment number of scripts found. + this.d.numExternalScripts++; + } + + // check that script has valid type + else if (!this.scriptHasInvalidType(this.d.domScripts[i])) { + + + if (this.d.hasSrc(this.d.domScripts[i]) && + !this.d.scriptHasJsWebLabel(this.d.domScripts[i])) { + + console.debug('an external script', this.d.domScripts[i]); + + absolutePath = urlHandler.resolve( + this.d.pageURL, this.d.domScripts[i].src); + scriptEntry = scriptObject.Script( + {'type': scriptTypes.EXTERNAL, + 'status': statusTypes.UNCHECKED, + 'element': this.d.domScripts[i], + 'url': absolutePath}); + this.d.externalScripts.push(scriptEntry); + that.d.scripts.push(scriptEntry); + + this.d.loadsHtmlExternalScripts = true; + + // increment number of scripts found. + this.d.numExternalScripts++; + + } else if (privacyChecker.checkScriptPrivacyThreat(this.d.domScripts[i].text)) { + this.d.removeGivenJs(scriptObject.Script( + {'type': scriptTypes.SINGLETON, + 'status': statusTypes.UNCHECKED, + 'element': this.d.domScripts[i], + 'text': this.d.domScripts[i].text + }), '', true); + } else if (this.d.domScripts[i].text !== '') { + // using else if since script text is + // ignored if src attribute is set. + // adding this.narcissusBugFixLibreJS to fix comment bug. + var bugfix = require('../../html_script_finder/bug_fix') + .narcissusBugFixLibreJS; + currentScript = stripHtmlCommentsInScript( + this.d.domScripts[i].text + bugfix); + + scriptEntry = scriptObject.Script( + {'type': scriptTypes.INLINE, + 'status': statusTypes.UNCHECKED, + 'element': this.d.domScripts[i], + 'text': currentScript}); + this.d.inlineScripts.push(scriptEntry); + this.d.scripts.push(scriptEntry); + + // add inline script in the count. + this.d.numInlineScripts++; + } + } + } + } catch (e) { + // Any problem arising, we remove the script. + console.debug('problem gathering scripts', e, e.lineNumber); + this.d.removeAllJs(); + } +}; + +/* + * exports.domGatherer + * Instantiate a brand new clone of the domGatherer. + * @param dom obj The given dom for analysis. + * @param pageURL string the URL for the page. + * @param callback function callback when all the work has been performed. + */ +exports.domGatherer = function (domHandler) { + var dg = new DomGatherer(); + dg.init(domHandler); + return dg; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/request.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/request.js @@ -0,0 +1,118 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var timer = require("sdk/timers"); + +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); +var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + + +// ensure xhr won't create an infinite loop +// with html content. +var urlTester = require("../url_seen_tester").urlSeenTester; +var urlHandler = require("../../url_handler/url_handler"); +const scriptsCached = require("../../script_entries/scripts_cache") + .scriptsCached; + +var Request = function() { + this.url = null; + this.channel = null; + this.script = null; + this.responseCallback = null; +}; + +/** + * init + */ +Request.prototype.init = function(script, callback) { + this.script = script; + // set initial url + this.url = this.script.url; + + console.debug('In Request.init() for url:', this.url); + + this.responseCallback = callback; + + var iOService = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService); + + this.channel = iOService.newChannel(this.url, null, null); +}; + +Request.prototype.request = function() { + var that = this; + var responseReceived = function (data) { + that.responseCallback(that.script, data); + }; + try { + this.channel.asyncOpen({ + QueryInterface: XPCOMUtils.generateQI( + [Ci.nsIRequestObserver, Ci.nsIStreamListener]), + data: "", + charset: null, + + onStartRequest: function(request, context) { + this.charset = request.contentCharset || "UTF-8"; + }, + + onDataAvailable: function (request, context, stream, offset, count) { + try { + var binaryInputStream = Cc["@mozilla.org/binaryinputstream;1"] + .createInstance(Ci.nsIBinaryInputStream); + binaryInputStream.setInputStream(stream); + var data = binaryInputStream.readBytes(count); + this.data += data; + } catch (x) { + console.debug('error in request', x, x.lineNumber); + responseReceived(""); + } + }, + + onStopRequest: function (request, context, result) { + try { + if (this.charset.toLowerCase() != "utf-8") { + var uConv = Cc["@mozilla.org/intl/utf8converterservice;1"] + .createInstance(Ci.nsIUTF8ConverterService); + + this.data = uConv.convertStringToUTF8( + this.data, this.charset, true); + } + } catch (e) { + console.debug("Issue with nsIUTF8ConverterService", e); + console.debug("Charset was", this.charset); + responseReceived(""); + } + responseReceived(this.data); + } + }, null); + } catch(e) { + console.debug("asyncOpen exception", e); + responseReceived(""); + } +}; + +// Instantiate a Request +exports.request = function(script, callback) { + var obj = new Request(); + obj.init(script, callback); + return obj; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/script_object.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/script_object.js @@ -0,0 +1,212 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var removedScripts = require("../../script_entries/removed_scripts") + .removedScripts; + +var acceptedScripts = require("../../script_entries/accepted_scripts") + .acceptedScripts; +var dryRunScripts = require("../../script_entries/dryrun_scripts") + .dryRunScripts; + +var Script = function(props) { + // can be an attribute, an inline script, + // or an external script. + this.type = null; + + /* + * Script.status - The script's current status. + * + * Possible values are: + * + * 0 - unchecked + * 1 - checked + * 2 - accepted + * 3 - rejected + * 4 - jsweblabel + * + * See script_properties.js for definitions. + */ + this.status = null; + + // contains the dom element + this.element = null; + + // the attribute name, if applicable. + this.attribute = null; + + // the script text as a string. + this.value = null; + + // the src url if external. + this.url = null; + + // the script text if inline. + this.text = null; + + this.init(props); +}; + +Script.prototype.init = function(props) { + // check the required elements are present. + if (typeof props === 'undefined') { + throw "Error, missing script entry value in script_object.js"; + } + + // required properties + if (typeof props.type !== 'undefined') { + this.type = props.type; + } else { + throw "type is missing"; + } + + if (typeof props.status !== 'undefined') { + this.status = props.status; + } else { + throw "status is missing"; + } + + if (typeof props.element !== 'undefined') { + this.element = props.element; + } else { + throw "element is missing"; + } + + // conditional properties. + this.url = (props.url) ? props.url : null; + this.text = (props.text) ? props.text : null; + this.jsAttributes = (props.jsAttributes) ? props.jsAttributes : null; + + if (typeof this.text !== 'string' && + this.tree !== null && + typeof this.tree === 'object' && + this.tree.hasOwnProperty('jsCode') + ) { + this.text = this.tree.jsCode; + } +}; + +Script.prototype.tagAsDryRun = function(pageURL, reason, hash) { + var content = this.findContentType(); + var inline = (this.url != undefined) ? false : true; + var url = (inline == false ? this.url : null); + console.debug("url is", url); + this.element.setAttribute('data-librejs', 'dryrun'); + this.element.setAttribute('data-librejs-reason', reason); + + dryRunScripts.addAScript( + pageURL, + {'inline': inline, + 'contents': content, + 'reason': reason, + 'url': url, + 'hash': hash + }); +}; + +Script.prototype.tagAsAccepted = function(pageURL, reason, hash) { + var content = this.findContentType(); + var inline = (this.url != undefined) ? false : true; + var url = (inline == false ? this.url : null); + console.debug("url is", url); + this.element.setAttribute('data-librejs', 'accepted'); + this.element.setAttribute('data-librejs-reason', reason); + + acceptedScripts.addAScript( + pageURL, + {'inline': inline, + 'contents': content, + 'reason': reason, + 'url': url, + 'hash': hash + }); + +}; + +Script.prototype.tagAsRemoved = function(pageURL, reason, hash) { + var content = this.findContentType(); + var inline = (this.url != undefined) ? false : true; + var url = (inline == false ? this.url : null); + this.element.setAttribute('data-librejs', 'rejected'); + this.element.setAttribute('data-librejs-reason', reason); + console.debug("tagAsRemoved hash is", hash); + removedScripts.addAScript(pageURL, { + 'inline': inline, + 'contents': content, + 'reason': reason, + 'url': url, + 'hash': hash + }); + +}; + +Script.prototype.tagAsDryRun = function(pageURL, reason, hash) { + var content = this.findContentType(); + var inline = (this.url != undefined) ? false : true; + var url = (inline == false ? this.url : null); + this.element.setAttribute('data-librejs', 'dryrun'); + this.element.setAttribute('data-librejs-reason', reason); + + dryRunScripts.addAScript( + pageURL, + {'inline': inline, + 'contents': content, + 'reason': reason, + 'url': url, + 'hash': hash + }); +}; + +/** + * removeNarcissusBugLine + * + * Removes the line that is appended to all + * inline scripts and prevent the bug that prevent + * script tags with comments only from being checked. + * + */ +Script.prototype.removeNarcissusBugLine = function(str) { + return str.replace('\n\nthis.narcissusBugFixLibreJS', ''); +}; + +/** + * findContentType + * + * Figure out whether it's an external script, + * an inline script, or an attribute from the property + * that has been set, rather than blindly trusting the given + * constant. + */ +Script.prototype.findContentType = function() { + if (this.url != undefined) { + return ""; + } else if (this.text != undefined) { + return this.element.text; + } else if (this.jsAttributes != undefined) { + // return the array. + return JSON.stringify(this.jsAttributes); + } +}; + +exports.Script = function(props) { + return new Script(props); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/script_properties.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/dom_handler/script_properties.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/html_parser.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/html_parser.js @@ -0,0 +1,160 @@ +/* + # ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1/GPL 2.0/LGPL 2.1 + # + # The contents of this file are subject to the Mozilla Public License Version + # 1.1 (the "License"); you may not use this file except in compliance with + # the License. You may obtain a copy of the License at + # http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" basis, + # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + # for the specific language governing rights and limitations under the + # License. + # + # The Original Code is Microsummarizer. + # + # The Initial Developer of the Original Code is Mozilla. + # Portions created by the Initial Developer are Copyright (C) 2006 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Myk Melez <myk@mozilla.org> (Original Author) + # Simon Bünzli <zeniko@gmail.com> + # Asaf Romano <mano@mozilla.com> + # Dan Mills <thunder@mozilla.com> + # Ryan Flint <rflint@dslr.net> + # + # Alternatively, the contents of this file may be used under the terms of + # either the GNU General Public License Version 2 or later (the "GPL"), or + # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + # in which case the provisions of the GPL or the LGPL are applicable instead + # of those above. If you wish to allow use of your version of this file only + # under the terms of either the GPL or the LGPL, and not to allow others to + # use your version of this file under the terms of the MPL, indicate your + # decision by deleting the provisions above and replace them with the notice + # and other provisions required by the GPL or the LGPL. If you do not delete + # the provisions above, a recipient may use your version of this file under + # the terms of any one of the MPL, the GPL or the LGPL. + # + # ***** END LICENSE BLOCK ***** + */ + +/* + * The original file is located here: + * http://mxr.mozilla.org/mozilla/source/browser/components/microsummaries/src/nsMicrosummaryService.js?raw=1 + * + */ + +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * html_parser + * + * Takes in an http response (string), loads it into a secured iframe + * so that it can be manipulated as a DOM object. It then returns a + * modified string to be passed along as a replacement of the original + * response. + * + */ + +var {Cc, Ci, Cu} = require("chrome"); + +var domHandlerModule = require("./dom_handler"); + +const PR_UINT32_MAX = 2147483647; + + +exports.htmlParser = function () { + + return { + charset: null, + htmlText: null, + pageURL: null, + fragment: null, + contentType: null, + responseStatus: null, + + parse: function (htmlText, charset, contentType, url, fragment, + responseStatus, parseResult) { + + // DOMParser still has too many issues. + this.htmlText = htmlText; + this.charset = charset; + + if (this.charset === "" || this.charset === undefined) { + this.charset = "utf-8"; + } + this.contentType = contentType; + this.pageURL = url; + this.fragment = fragment; + this.responseStatus = responseStatus; + var that = this; + + var domParser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); + + var dom = domParser.parseFromString(this.htmlText, this.contentType); + // console.debug(dom.getElementsByTagName('body')[0].innerHTML); + domHandlerModule.domHandler(dom, this.pageURL, this.fragment, this.responseStatus, function (newDom) { + parseResult(that.serializeToStream(newDom, that)); + }); + + }, + + /** + * serializeToStream + * Serializes an HTML DOM into a binary stream. Uses + * nsIDOMSerializer only as a backup to when the + * reconstituteHtmlString method fails (not sure if/when it + * happens). + * @param dom obj Reference to the dom object + * @param that obj Reference to the object returned by htmlParser. + * This allows to give access to the iframe. + * @return a binary stream. + */ + serializeToStream: function (dom, that) { + + var newData, len; + + try { + var storageStream = Cc["@mozilla.org/storagestream;1"].createInstance(Ci.nsIStorageStream); + var binaryOutputStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream); + var serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"].createInstance(Ci.nsIDOMSerializer); + var encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=" + this.contentType] + .createInstance(Ci.nsIDocumentEncoder); + + encoder.setCharset(this.charset); + encoder.init(dom, this.contentType, 0); + storageStream.init(8192, PR_UINT32_MAX, null); + + binaryOutputStream.setOutputStream(storageStream.getOutputStream(0)); + encoder.encodeToStream(binaryOutputStream); + return storageStream; + } catch (e) { + console.debug('issue with serializer', e, e.lineNumber); + } + } + + }; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/url_seen_tester.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/url_seen_tester.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/web_labels/find_js_labels.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/web_labels/find_js_labels.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/web_labels/js_web_labels.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/web_labels/js_web_labels.js @@ -0,0 +1,299 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +// node.js url module. Makes it easier to resolve +// urls in that datauri loaded dom +var urlHandler = require("../../url_handler/url_handler"); +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); +var data = require("sdk/self").data; + +// license definitions, we are using canonical urls and license +// identifiers. +var licenses = require('../../js_checker/license_definitions').licenses; + +var getLicenseList = require('./find_js_labels').getLicenseList; +const types = require("../../js_checker/constant_types"); + +const addToCache = require("./script_hash_worker") + .addToCache; + +// keep web labels in memory so that they can be checked even when they +// are embedded dynamically. +var jsWebLabelEntries = {}; + +// store the url to js web labels already visited during this session +var jsLabelsPagesVisited = {}; + +var WebLabelFinder = function () { + this.dom = null; + this.pageURL = null; + this.jslicenseURL = null; + this.pageContent = null; + this.licenseList = null; + this.callback = null; +}; + +WebLabelFinder.prototype.init = function(dom, pageURL, callback) { + var that = this; + this.pageURL = pageURL; + this.dom = dom; + this.callback = function (a) { + if (typeof a === 'undefined') { + a = null; + } + + // rewrite callback as soon as it is triggered once. + that.callback = function () { + console.debug("Callback already called"); + }; + + callback(a); + }; + this.findJavaScriptLicenses(); + this.pageContent = ''; + this.jslicenseURL = ''; +}; + +WebLabelFinder.prototype.findJavaScriptLicenses = function () { + this.searchForJsLink(); + + if (this.jslicenseURL && !(jsLabelsPagesVisited[this.jslicenseURL])) { + // get content from license page. + console.debug('called fetch license page for', this.jslicenseURL); + this.pageContent = this.fetchLicensePage(); + } else { + console.debug(this.jslicenseURL, "already visited"); + this.callback(); + } +}; + +WebLabelFinder.prototype.searchForJsLink = function() { + console.debug('triggered searchForJsLink'); + if (this.dom) { + var linkTags = this.dom.getElementsByTagName('a'), + i = 0, + len = linkTags.length, + path; + + // loop through all a tags. + for (; i < len; i++) { + if ( + (linkTags[i].hasAttribute('rel') && + linkTags[i].getAttribute('rel') === 'jslicense') || + (linkTags[i].hasAttribute('data-jslicense') && + linkTags[i].getAttribute('data-jslicense') === '1') + ) { + // This page has a web labels link + return this.formatURL(linkTags[i]); + } + } + } + + // no js web labels were found. call back. + this.callback(); + return false; +}; + +WebLabelFinder.prototype.formatURL = function(link) { + this.jslicenseURL = urlHandler.resolve(this.pageURL, link.href); + this.jslicenseURL = urlHandler.addFragment(this.jslicenseURL, 'librejs=true'); + console.debug('license URL found', this.jslicenseURL); + return this.jslicenseURL; +}; + +WebLabelFinder.prototype.fetchLicensePage = function() { + var that = this; + try { + var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(); + + req.onload = function() { + console.debug("Fetching License!"); + console.debug("URL is ", this._url); + + that.licenseList = getLicenseList(this.responseXML); + console.debug("the license list", that.licenseList); + that.matchListWithDefs(this._url); + + // add these entries to the global + // object for dynamically embedded scripts. + jsWebLabelEntries[that.pageURL] = that.licenseList; + jsLabelsPagesVisited[req._url] = 1; + }; + console.debug(this.jslicenseURL); + req.open('GET', this.jslicenseURL, true); + req._url = this.jslicenseURL; + req.responseType = "document"; + req.send(); + } catch (e) { + console.debug(e, e.lineNumber, e.fileName, this.jslicenseURL); + this.callback({}); + } +}; + +/** + * @method isLicenseFree + * Returns true if the given web labels row refers to a script that + * can be executed by LibreJS. + * + * This method has some side effects :-/ + * + * @param {Object} lic - A license node from a JS web labels page. It's + * expected to contain one or more licenses. + * @return {Boolean} + */ +WebLabelFinder.prototype.isLicenseFree = function( + lic, jslicenseURL, callback +) { + // For each license that this license row contains. + var isFree = false; + // licenseStatuses is later used to determine isFree. + var licenseStatuses = []; + + for (var i = 0; i < lic.licenses.length; i++) { + var license; + var found = false; + + // Check if we can look up this license by its identifier. + var identifier = lic.licenses[i].licenseName; + if (typeof identifier !== 'undefined' && + typeof licenses[identifier] !== 'undefined' + ) { + console.debug('recognized by index', identifier); + // This license was recognized, and it was free. Add it + // to the array of license status, which we'll look at + // when we're done with this web label row. + licenseStatuses.push(true); + + console.debug("about TO ADD TO XHR: ", lic.fileUrl); + this.listCheck[lic.fileUrl] = 0; + addToCache(lic, 0, jslicenseURL, callback); + + // Break out of the loop cause we found a matching license. + found = true; + continue; + } + + // For each license from the internal license definitions + for (license in licenses) { + if (found === true) { + break; + } + var licDef = licenses[license]; + var licArray = []; + if (!licDef.canonicalUrl) { + continue; + } + if (typeof licDef.canonicalUrl === 'string') { + licArray = [licDef.canonicalUrl]; + } else { + licArray = licDef.canonicalUrl; + } + + // For each of the canonical URLs recognized by this license + // definition + for (var j = 0; j < licArray.length; j++) { + if (urlHandler.removeFragment(licArray[j]) === + urlHandler.removeFragment(lic.licenses[i].licenseUrl) + ) { + if (!require("sdk/url").isValidURI(lic.fileUrl)) { + console.debug(lic.fileUrl, " is not a valid URL"); + callback(); + } + + // This license was recognized, and it was free. Add it + // to the array of license status, which we'll look at + // when we're done with this web label row. + licenseStatuses.push(true); + + console.debug("about TO ADD TO XHR: ", lic.fileUrl); + this.listCheck[lic.fileUrl] = 0; + addToCache(lic, 0, jslicenseURL, callback); + + // Break out of the nearest two loops cause we found + // a matching license + found = true; + break; + } + } + } + } + + // Tally up the licenses we were able to match. + if (licenseStatuses.length > 0 && + // If the number of licenses we matched is at least one, and + // it's the same number as the number of licenses in this Web + // Label column, only then can we recognize this script as free. + // licenseStatus.length should never be larger than + // lic.licenses.length. + licenseStatuses.length >= lic.licenses.length + ) { + isFree = true; + } + + return isFree; +}; + +WebLabelFinder.prototype.matchListWithDefs = function(jslicenseURL) { + var that = this; + var licDef, + license, script; + var cacheCalls = 0; + this.listCheck = {}; + + // nested loop. + cacheCalls = 0; + var callback = function (url) { + cacheCalls++; + that.listCheck[url] = 1; + if (cacheCalls === Object.keys(that.listCheck).length) { + console.debug("triggering callback duh"); + // return array to requester object + callback = false; + that.callback(that.licenseList); + } + }; + require("sdk/timers").setTimeout(function () { + // callback after 60 seconds if it's still not returned. + // using this as a safeguard. + // return array to requester object + if (callback !== false) { + that.callback(that.licenseList); + console.debug(that.listCheck); + } + }, 15000); + + for (var i = 0; i < this.licenseList.length; i++) { + // this.licenseList[i] is the web labels license column + var lic = this.licenseList[i]; + if (this.isLicenseFree(lic, jslicenseURL, callback)) { + lic.free = true; + } + } +}; + +exports.WebLabelFinder = WebLabelFinder; + +// Store the web labels harvested across webpages (only in this session). +exports.jsWebLabelEntries = jsWebLabelEntries; + +exports.jsLabelsPagesVisited = jsLabelsPagesVisited; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/web_labels/script_hash_worker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/html_script_finder/web_labels/script_hash_worker.js @@ -0,0 +1,78 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +const types = require("../../js_checker/constant_types"); +const scriptsCached = require("../../script_entries/scripts_cache") + .scriptsCached; +const xhr = require('../dom_handler/dom_checker').xhr; +const timers = require("sdk/timers"); + +exports.addToCache = function (lic, delay, jsWebLabelsURL, callback) { + console.debug("jslicenseURL is", jsWebLabelsURL); + if (typeof delay === 'undefined') { + delay = 0; + } + + // get file hash and store as cached. + console.debug('performing xhr for', lic.fileUrl); + timers.setTimeout(function() { + var cb = function (script, contents) { + try { + // add a cache entry. + var hash = scriptsCached.addEntryIfNotCached( + contents, + types.freeWithComment( + 'This script is free according to a JS Web Labels ' + + 'page visited recently (at ' + + jsWebLabelsURL.replace("librejs=true", "") + ' )' + ), + {}, + true, + lic.fileUrl + ); + console.debug('returning xhr from', lic.fileUrl); + if (typeof callback === 'function') { + callback(lic.fileUrl); + } else { + console.debug('callback is not a function:', callback); + } + } catch (e) { + if (typeof callback === 'function') { + callback(lic.fileUrl); + } else { + console.debug('callback is not a function:', callback); + } + } + }; + // just callback after 5 seconds if we don't get the answer yet. + timers.setTimeout(function() { + cb = function() {}; + if (typeof callback === 'function') { + callback(lic.fileUrl); + } else { + console.debug('callback is not a function:', callback); + } + }, 20000); + + xhr({'url': lic.fileUrl}, cb); + }, delay); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/allowed_referrers.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/allowed_referrers.js @@ -0,0 +1,69 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var prefChange = require("../addon_management/prefchange"); + +var allowed = {}; + +/** + * Contains a list of pages that are allowed + * to execute JavaScript regardless of whether it is + * nonfree and nontrivial. + */ +var AllowedReferrers = function() { +}; + +AllowedReferrers.prototype.addPage = function(url) { + allowed[url] = 1; +}; + +AllowedReferrers.prototype.urlInAllowedReferrers = function (url) { + if (allowed[url] === 1) { + return true; + } + // check if whitelisted. + return this.urlInWhitelist(url); +}; + +AllowedReferrers.prototype.urlInWhitelist = function(url) { + var whitelist = prefChange.getWhitelist(); + var i = 0, le = whitelist.length; + for (; i < le; i++) { + if (whitelist[i].test(url)) { + return true; + } + } +}; + +AllowedReferrers.prototype.clearSinglePageEntry = function(url) { + var index = allowed[url]; + + if (allowed[url] === 1) { + delete allowed[url]; + } +}; + +AllowedReferrers.prototype.clearAllEntries = function() { + allowed = {}; +}; + +exports.allowedReferrers = new AllowedReferrers(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/caching.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/caching.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/http_request_observer.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/http_request_observer.js @@ -0,0 +1,149 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +var observerService = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); + +// these are our target mime types for response interception. +var targetMimeTypes = /.*(javascript|ecmascript|html).*/i; +//var targetMimeTypes = /.*(html).*/i; + +// ensure xhr won't create an infinite loop +// with html content. +var urlTester = require("../html_script_finder/url_seen_tester") + .urlSeenTester; +var streamLoader = require("../http_observer/stream_loader").streamLoader; + +var httpRequestObserver = { + observe: function(request, aTopic, aData) { + console.debug('atopic is', aTopic); + var url, newListener, status; + + if (aTopic === "http-on-examine-response" || + aTopic === "http-on-examine-cached-response" || + aTopic === "http-on-examine-merged-response" + ) { + request.QueryInterface(Ci.nsIHttpChannel); + + if (request.URI.scheme !== 'chrome' && + (request.responseStatus < 300 || + request.responseStatus > 399) && + (targetMimeTypes.test(request.contentType) || + request.contentType === undefined) && + (!urlTester.isWhitelisted(request.URI.spec) && + !urlTester.isWhitelisted(request.originalURI.spec)) + ) { + newListener = new TracingListener(); + request.QueryInterface(Ci.nsITraceableChannel); + newListener.originalListener = request.setNewListener(newListener); + } else if (urlTester.isWhitelisted(request.URI.spec) || + urlTester.isWhitelisted(request.originalURI.spec) + ) { + urlTester.clearUrl(request.URI.spec); + urlTester.clearUrl(request.originalURI.spec); + } + + } + }, + + QueryInterface: function (aIID) { + if (aIID.equals(Ci.nsIObserver) || + aIID.equals(Ci.nsISupports) + ) { + return this; + } + throw Cr.NS_NOINTERFACE; + } +}; + +// Copy response listener implementation. +function TracingListener() { + this.originalListener = null; + this.streamLoader = streamLoader(); +} + +TracingListener.prototype = { + onDataAvailable: function(request, context, inputStream, offset, count) { + try { + this.streamLoader.loader.onDataAvailable( + request, context, inputStream, offset, count); + } catch (x) { + console.debug(x, x.lineNumber, x.fileName, "In this case, charset is"); + } + }, + + onStartRequest: function(request, context) { + this.streamLoader.setOriginalListener(this.originalListener); + this.streamLoader.loader.onStartRequest(request, context); + this.originalListener.onStartRequest(request, context); + }, + + onStopRequest: function(request, context, statusCode) { + try { + this.streamLoader.loader.onStopRequest(request, context, statusCode); + } catch (e) { + console.debug('error in onStopRequest', e, e.lineNumber); + } + }, + + QueryInterface: function (aIID) { + if (aIID.equals(Ci.nsIStreamListener) || + aIID.equals(Ci.nsISupports) + ) { + return this; + } + throw Cr.NS_NOINTERFACE; + }, +}; + +exports.startHttpObserver = function() { + try { + observerService.addObserver(httpRequestObserver, + "http-on-examine-response", false); + observerService.addObserver(httpRequestObserver, + "http-on-examine-cached-response", false); + observerService.addObserver(httpRequestObserver, + "http-on-examine-merged-response", false); + console.debug('turned on http observer'); + } catch (e) { + console.debug(e); + } +}; + +exports.startHttpObserver(); + +/* remove observer */ +exports.removeHttpObserver = function() { + try { + observerService.removeObserver(httpRequestObserver, + "http-on-examine-response"); + observerService.removeObserver(httpRequestObserver, + "http-on-examine-cached-response"); + observerService.removeObserver(httpRequestObserver, + "http-on-examine-merged-response"); + console.debug('turned off http observer'); + } catch (e) { + console.debug(e); + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/process_response.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/process_response.js @@ -0,0 +1,424 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * This module checks http responses by mime type and returns a + * modified response. + */ + +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +var jsChecker = require("../js_checker/js_checker"); + +const types = require("../js_checker/constant_types"); +var checkTypes = types.checkTypes; + +// check if scripts embedded dynamically have a jsWebLabel entry indexed by referrer. +var jsWebLabelEntries = require("../html_script_finder/web_labels/js_web_labels") + .jsWebLabelEntries; + +var htmlParser = require("../html_script_finder/html_parser"); + +var removedScripts = require("../script_entries/removed_scripts") + .removedScripts; +var allowedRef = require('../http_observer/allowed_referrers') + .allowedReferrers; + +var acceptedScripts = require("../script_entries/accepted_scripts") + .acceptedScripts; + +// used to display info when a url is whitelisted. +var dryRunScripts = require("../script_entries/dryrun_scripts").dryRunScripts; + +// node.js url module. Makes it easier to resolve +// urls in that datauri loaded dom +var urlHandler = require("../url_handler/url_handler"); +var isDryRun = require("../addon_management/prefchange").isDryRun; + +var jsMimeTypeRe = /.*(javascript|ecmascript).*/i; +var htmlMimeTypeRe = /.*(xhtml\+xml|html|multipart\/x-mixed-replace).*/i; + + +var processResponseObject = { + data: null, + myParser: null, + url: null, + scriptFinder: null, + jsCheckString: null, + referrer: null, + contentType: null, + resInfo: null, + listener: null, + req: null, + + /** + * starts the handling of a new response. + */ + init: function (listener, resInfo) { + this.resInfo = resInfo; + this.req = resInfo.request; + /* needed for this.req.referrer */ + this.req.QueryInterface(Ci.nsIHttpChannel); + this.listener = listener; + this.setData(); + this.setContentType(); + this.setUrls(); + }, + + /** + * Gather the data gathered from onDataAvailable. + */ + setData: function () { + this.data = this.resInfo.receivedData; + //console.debug("\n\nDump of whole data:\n\n", this.data, "\n\n end of dump"); + // Prevents the http response body from being empty, + // which would throw an error. + if (this.data == '' || this.data == undefined) { + this.data = " "; + } + }, + + /** + * Set a standardized lowercase mime type. + */ + setContentType: function() { + if (this.req.contentType != undefined) { + this.contentType = String(this.req.contentType).toLowerCase(); + } + }, + + /** + * setUrls + * Set the current URL of the response, and + * set referrer if applicable. + */ + setUrls: function() { + + if (this.req.URI != undefined) { + this.fragment = urlHandler.getFragment(this.req.URI.spec); + console.debug('fragment is', this.fragment); + this.url = urlHandler.removeFragment(this.req.URI.spec); + } + if (this.req.referrer != undefined) { + this.referrerFragment = urlHandler.getFragment(this.req.referrer.spec); + this.referrer = urlHandler.removeFragment(this.req.referrer.spec); + } + }, + + /** + * processHTML + * Modifies a string of html + */ + processHTML: function() { + var charset = this.req.contentCharset, myParser; + + if (this.req.contentCharset != undefined && this.req.contentCharset != "") { + charset = this.req.contentCharset; + } else { + charset = ""; + } + acceptedScripts.clearScripts(this.req.URI.spec); + removedScripts.clearScripts(this.req.URI.spec); + dryRunScripts.clearScripts(this.req.URI.spec); + + console.debug('charset is', charset); + console.debug( + 'responseStatus for', this.url, 'is', this.req.responseStatus); + + // send data to htmlParser, and pass on modified data to + // originalListener. + + myParser = htmlParser.htmlParser().parse( + this.data, + charset, + this.contentType, + this.url, + this.fragment, + this.req.responseStatus, + this.htmlParseCallback.bind(this)); + }, + + /** + * + * htmlParseCallback + * + * Passed on the callback result to + * the originalListener. + * + */ + htmlParseCallback: function(result) { + + var len = result.length; + + try { + + this.listener.onDataAvailable( + this.req, + this.resInfo.context, + result.newInputStream(0), 0, len); + + + } catch (e) { + + this.req.cancel(this.req.NS_BINDING_ABORTED); + + } + + this.listener.onStopRequest( + this.req, + this.resInfo.context, this.resInfo.statusCode); + + }, + + /** + * processJS + * Process and modify a string of JavaScript. + */ + processJS: function() { + var checker, check, jsCheckString, + that = this; + + try { + // make sure script isn't already listed as free + // in a JS web labels table. + if (this.checkJsWebLabelsForScript()) { + // this is free. we are done. + this.jsListenerCallback(); + return; + } + + // analyze javascript in response. + checker = jsChecker.jsChecker(); + check = checker.searchJs(this.data, function () { + //console.debug("Has been analyzing", that.data); + that.processJsCallback(checker); + }, that.url); + + } catch(e) { + + // any error is considered nontrivial. + console.debug('js error in js app, removing script', e); + console.debug("error", e, e.lineNumber); + // modify data that will be sent to the browser. + this.data = '// LibreJS: Script contents were removed when it was loaded from a page, because another script attempted to load this one dynamically. Please place your cursor in the url bar and press the enter key to see the source.'; + this.jsListenerCallback(); + } + + }, + + /** + * checkJsWebLabelsForScript + * + * check whether script that's been received has an entry + * in a js web labels table (lookup referrer.) + * + */ + checkJsWebLabelsForScript: function () { + + console.debug('checking script', this.url); + console.debug('current list is', JSON.stringify(jsWebLabelEntries)); + if (jsWebLabelEntries[this.referrer] != undefined) { + + var scriptList = jsWebLabelEntries[this.referrer], + i = 0, + len = scriptList.length; + + for (; i < len; i++) { + + if (scriptList[i].fileUrl === this.url && + scriptList[i].free === true) { + + console.debug(this.url, "is free and dynamic!"); + + var scriptObj = { + inline: false, + url: this.url, + contents: this.url, + reason: "This script is free (see JS Web Labels page for detail)" + }; + + acceptedScripts.addAScript( + this.req.referrer.spec, scriptObj, "Script is free"); + + return true; + + } + } + } + }, + + processJsCallback: function(checker) { + try { + var scriptObj; + + var jsCheckString = checker.parseTree.freeTrivialCheck; + console.debug("analyzing js callback for", this.url); + // for testing only. + //var jsCheckString = {'type': checkTypes.FREE_SINGLE_ITEM }; + console.debug('jscheckstring is', jsCheckString.type); + + if (jsCheckString.type === checkTypes.NONTRIVIAL) { + if (!allowedRef.urlInAllowedReferrers(this.req.referrer.spec)) { + //if (true) { + console.debug( + "url", + this.url, + " is found nontrivial", + "with reason", + jsCheckString.reason); + scriptObj = { + inline: false, + contents: '', + removalReason: 'nontrivial', + reason: jsCheckString.reason, + url: this.url, + hash: checker.hash + }; + removedScripts.addAScript(this.req.referrer.spec, scriptObj); + + // modify data that will be sent to the browser. + this.data = '// LibreJS: Script contents were removed when it was loaded from a page, because another script attempted to load this one dynamically and its contents appear to be nonfree/nontrivial. Please hit enter in the location bar to see the actual source.'; + } else { + console.debug("writing to dry run", this.url); + scriptObj = { + inline:false, + contents: '', + removalReason: 'nontrivial', + reason: jsCheckString.reason, + url: this.url, + hash:checker.hash + }; + dryRunScripts.addAScript(this.req.referrer.spec, scriptObj); + } + + this.jsListenerCallback(); + + } else if (jsCheckString.type === checkTypes.FREE || + jsCheckString.type === checkTypes.FREE_SINGLE_ITEM || + jsCheckString.type === checkTypes.TRIVIAL || + jsCheckString.type === checkTypes.TRIVIAL_DEFINES_FUNCTION || + jsCheckString.type === checkTypes.WHITELISTED) { + console.debug( + "found a free script for", + this.url, + this.req.referrer.spec, + jsCheckString.reason); + console.debug('found a free script', this.req.referrer.spec); + + scriptObj = {inline: false, + contents: '', + reason: jsCheckString.reason, + url: this.url, + hash:checker.hash}; + + acceptedScripts.addAScript(this.req.referrer.spec, scriptObj); + this.jsListenerCallback(); + } + + //var end = Date.now(); + console.debug('exec time', this.url, ' -- ', end - start); + } catch (x) { + console.debug('error', x); + } + }, + + /** + * ProcessAllTypes + * Calls processHTML or JS if it finds an appropriate content + * type. For everything else it just passes on the data to the + * original listener. + */ + processAllTypes: function() { + // toggle xlibrejs if X-LibreJS is set. + + // process HTML + if ((htmlMimeTypeRe.test(this.contentType) || + this.req.contentType === undefined)) { + this.processHTML(); + return; + } + + else { + // process external JS files that are called from another + // file (and hence have a referrer). + + if (this.referrer != undefined && + jsMimeTypeRe.test(this.contentType) && + !(acceptedScripts.isFound(this.referrer, { + inline: false, contents: this.url})) && + !(acceptedScripts.isFound(this.referrer, { + inline:false, contents:this.req.originalURI.spec}))) { + + // console.debug('process js triggered for', this.url); + this.processJS(); + + } else { + this.jsListenerCallback(); + } + + } + + }, + + jsListenerCallback: function () { + + var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + + if (typeof this.req.contentCharset !== 'undefined' && + this.req.contentCharset !== '' && + this.req.contentCharset !== null + ) { + converter.charset = this.req.contentCharset; + } else { + converter.charset = "UTF-8"; + } + + var stream = converter.convertToInputStream(this.data); + + try { + this.listener.onDataAvailable( + this.req, + this.resInfo.context, + stream, + 0, stream.available()); + } catch (e) { + this.req.cancel(this.req.NS_BINDING_ABORTED); + } + + this.listener.onStopRequest( + this.req, + this.resInfo.context, + this.resInfo.statusCode); + + } + + +}; + +// creates an instance of processResponseObject. +exports.ProcessResponse = function (listener, resInfo) { + console.debug('triggered'); + var procResponse = Object.create(processResponseObject); + procResponse.init(listener, resInfo); + return procResponse; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/stream_loader.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/http_observer/stream_loader.js @@ -0,0 +1,160 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +const processResponse = require('./process_response'); +const CHARSETS = [ + '866', 'ansi_x3.4-1968', 'arabic', 'ascii', 'asmo-708', 'big5', + 'big5-hkscs', 'chinese', 'cn-big5', 'cp1250', 'cp1251', 'cp1252', + 'cp1253', 'cp1254', 'cp1255', 'cp1256', 'cp1257', 'cp1258', + 'cp819', 'cp866', 'csbig5', 'cseuckr', 'cseucpkdfmtjapanese', + 'csgb2312', 'csibm866', 'csiso2022jp', 'csiso2022kr', 'csiso58gb231280', + 'csiso88596e', 'csiso88596i', 'csiso88598e', 'csiso88598i', 'csisolatin1', + 'csisolatin2', 'csisolatin3', 'csisolatin4', 'csisolatin5', 'csisolatin6', + 'csisolatin9', 'csisolatinarabic', 'csisolatincyrillic', + 'csisolatingreek', 'csisolatinhebrew', 'cskoi8r', 'csksc56011987', + 'csmacintosh', 'csshiftjis', 'cyrillic', 'dos-874', 'ecma-114', + 'ecma-118', 'elot_928', 'euc-jp', 'euc-kr', 'gb18030', 'gb2312', + 'gb_2312', 'gb_2312-80', 'gbk', 'greek', 'greek8', 'hebrew', + 'hz-gb-2312', 'ibm819', 'ibm866', 'iso-2022-cn', 'iso-2022-cn-ext', + 'iso-2022-jp', 'iso-2022-kr', 'iso88591', 'iso_8859-1', 'iso-8859-1', + 'iso8859-1', 'iso885910', 'iso-8859-10', 'iso8859-10', 'iso885911', + 'iso-8859-11', 'iso8859-11', 'iso_8859-1:1987', 'iso885913', 'iso-8859-13', + 'iso8859-13', 'iso885914', 'iso-8859-14', 'iso8859-14', 'iso885915', + 'iso-8859-15', 'iso8859-15', 'iso-8859-16', 'iso88592', 'iso_8859-2', + 'iso-8859-2', 'iso8859-2', 'iso_8859-2:1987', 'iso88593', 'iso_8859-3', + 'iso-8859-3', 'iso8859-3', 'iso_8859-3:1988', 'iso88594', 'iso_8859-4', + 'iso-8859-4', 'iso8859-4', 'iso_8859-4:1988', 'iso88595', 'iso_8859-5', + 'iso-8859-5', 'iso_8859-5:1988', 'iso88596', 'iso_8859-6', 'iso-8859-6', + 'iso8859-6', 'iso_8859-6:1987', 'iso-8859-6-e', 'iso-8859-6-i', 'iso88597', + 'iso_8859-7', 'iso-8859-7', 'iso8859-7', 'iso_8859-7:1987', 'iso88598', + 'iso_8859-8', 'iso-8859-8', 'iso8859-8', 'iso_8859-8:1988', 'iso-8859-8-e', + 'iso-8859-8i', 'iso-8859-8-i', 'iso88599', 'iso_8859-9', 'iso-8859-9', + 'iso8859-9', 'iso_8859-9:1989', 'iso-ir-100', 'iso-ir-101', 'iso-ir-109', + 'iso-ir-110', 'iso-ir-126', 'iso-ir-127', 'iso-ir-138', 'iso-ir-144', + 'iso-ir-148', 'iso-ir-149', 'iso-ir-157', 'iso-ir-58', 'koi', 'koi8', + 'koi8_r', 'koi8-r', 'koi8-u', 'korean', 'ksc5601', 'ksc_5601', + 'ks_c_5601-1987', 'ks_c_5601-1989', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', + 'l9', 'latin1', 'latin2', 'latin3', 'latin4', 'latin5', 'latin6', 'latin9', + 'logical', 'mac', 'macintosh', 'ms_kanji', 'replacement', 'shift_jis', + 'shift-jis', 'sjis', 'sun_eu_greek', 'tis-620', 'unicode-1-1-utf-8', + 'us-ascii', 'utf-16', 'utf-16be', 'utf-16le', 'utf8', 'utf-8', 'visual', + 'windows-1250', 'windows-1251', 'windows-1252', 'windows-1253', + 'windows-1254', 'windows-1255', 'windows-1256', 'windows-1257', + 'windows-1258', 'windows-31j', 'windows-874', 'windows-949', 'x-cp1250', + 'x-cp1251', 'x-cp1252', 'x-cp1253', 'x-cp1254', 'x-cp1255', 'x-cp1256', + 'x-cp1257', 'x-cp1258', 'x-euc-jp', 'x-gbk', 'x-mac-cyrillic', + 'x-mac-roman', 'x-mac-ukrainian', 'x-sjis', 'x-user-defined', 'x-x-big5' +]; + +var StreamLoader = function() { + this.loader = null; + this.listener = null; + this.originalListener = null; +}; + +StreamLoader.prototype.setOriginalListener = function(listener) { + this.originalListener = listener; +}; + +StreamLoader.prototype.init = function() { + try { + var that = this; + this.listener = new StreamListener(); + + this.listener.callback = function (loader, context, status, data) { + //console.debug("here is the data", data); + var responseInfo = {'request': loader.channel, + 'context': context, + 'statusCode': status, + 'receivedData': data}; + var responseHandler = processResponse.ProcessResponse(that.originalListener, responseInfo); + responseHandler.processAllTypes(); + + that.destroy(); + }; + + this.loader = Cc["@mozilla.org/network/unichar-stream-loader;1"]. + createInstance(Ci.nsIUnicharStreamLoader); + + this.loader.init(this.listener); + } catch (e) { + console.debug(e); + } +}; + +StreamLoader.prototype.destroy = function () { + this.loader = null; + this.listener = null; +}; + +var getRegexForContentType = function (contentType) { + if (/xhtml/i.test(contentType)) { + return /<\?[^>]*?encoding=(?:["']*)([^"'\s\?>]+)(?:["']*)/i; + } + + // return the regular html regexp for anything else. + return /<meta[^>]*?charset=(?:["']*)([^"'\s>]+)(?:["']*)/i; +}; + +var StreamListener = function() {}; + +StreamListener.prototype.QueryInterface = function listener_qi(iid) { + if (iid.equals(Ci.nsISupports) || + iid.equals(Ci.nsIUnicharStreamLoaderObserver)) { + return this; + } + throw Cr.NS_ERROR_NO_INTERFACE; +}; + +StreamListener.prototype.onStreamComplete = function onStreamComplete( + loader, context, status, data) { + this.callback(loader, context, status, data); +}; + +StreamListener.prototype.onDetermineCharset = function onDetermineCharset( + loader, context, data) { + var match, regex; + if (loader.channel.contentCharset !== undefined && + loader.channel.contentCharset !== "" + ) { + return loader.channel.contentCharset; + } else { + match = getRegexForContentType(loader.channel.contentType).exec(data); + if (typeof match !== 'undefined' && + match !== null && + match.length > 0 && + CHARSETS.indexOf(match[1].toLowerCase()) >= 0 + ) { + loader.channel.contentCharset = match[1]; + return match[1]; + } else { + return "UTF-8"; + } + } +}; + +exports.streamLoader = function () { + var l = new StreamLoader(); + l.init(); + return l; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/constant_types.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/constant_types.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/free_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/free_checker.js @@ -0,0 +1,246 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var licenses = require('./license_definitions'); +var simpleStorage = require("sdk/simple-storage"); +const LAZY = licenses.types.LAZY; +var licenseRegex = []; +const END_OF_SCRIPT = require('../html_script_finder/bug_fix').END_OF_SCRIPT; +const types = require("./constant_types"); + +const token = types.token; + +var patternUtils = require('./pattern_utils').patternUtils; + +var licStartLicEndRe = /@licstartThefollowingistheentirelicensenoticefortheJavaScriptcodeinthis(?:page|file)(.*)?@licendTheaboveistheentirelicensenoticefortheJavaScriptcodeinthis(?:page|file)/mi; +var licenseMagnet = /.*@license ?(magnet\:\?xt=urn\:btih\:[0-9A-Za-z]+).*/; +var licenseEndMagnet = /.*@license-end.*/i; +exports.freeCheck = { + initLicenses: function (licenses) { + for (var item in licenses) { + this.stripLicenseToRegexp(licenses[item]); + } + }, + + /** + * stripLicenseToRegexp + * + * Removes all non-alphanumeric characters except for the + * special tokens, and replace the text values that are + * hardcoded in license_definitions.js + * + */ + stripLicenseToRegexp: function (license) { + var max = license.licenseFragments.length; + var item; + + for (var i = 0; i < max; i++) { + item = license.licenseFragments[i]; + item.regex = patternUtils.removeNonalpha(item.text); + + if (license.licenseFragments[i].type === LAZY) { + + // do not permit words before. Since "Not" could be added + // and make it nonfree. e.g.: Not licensed under the GPLv3. + item.regex = '^(?!.*not).*' + item.regex; + + } + + item.regex = new RegExp( + patternUtils.replaceTokens(item.regex), 'i'); + } + + return license; + }, + + /** + * checkNodeFreeLicense + * + * Check if the node mentions a free license + * in one of its comments. + * + */ + checkNodeFreeLicense: function (n, queue) { + var strippedComment, + magnetLink, + comment = this.getComment(n), + list = licenses.licenses, + i, j, + max, + regex, + frag, + matchLicStart, + matchMagnet, + license, + isMagnetValid = false; + + if (n.counter === 2 && + typeof n.parent !== 'undefined' && + n.parent.type === token.SCRIPT && + typeof comment !== 'undefined' && + comment !== " " + ) { + strippedComment = patternUtils.removeNonalpha(comment); + matchLicStart = strippedComment.match(licStartLicEndRe); + console.debug("matchMagnet is", matchMagnet); + if (matchLicStart) { + strippedComment = matchLicStart[1]; + for (license in list) { + frag = list[license].licenseFragments; + max = list[license].licenseFragments.length; + for (i = 0; i < max; i++) { + if (frag[i].regex.test(strippedComment)) { + return { + licenseName: list[license].licenseName, + type: types.checkTypes.FREE + }; + + } + } + } + } + // check for @license -- @license-end notation. + return this.matchMagnet(comment, queue); + } + }, + + /** + * matchMagnet + * Attempts to find valid @license [magnet] + * and @license-end notation. + */ + matchMagnet: function (comment, queue) { + let matchMagnet = comment.match(licenseMagnet); + if (matchMagnet) { + let magnetLinkRe = new RegExp( + matchMagnet[1].replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + ); + let list = licenses.licenses; + let queue_end = queue.length; + + for (var license in list) { + frag = list[license].canonicalUrl; + console.debug("frag is ", frag); + if (typeof frag !== 'undefined') { + max = list[license].canonicalUrl.length; + console.debug("max is", max); + for (var i = 0; i < max; i++) { + console.debug("current frag is", frag[i]); + if (frag[i].match(magnetLinkRe)) { + // The magnet link has a recognized license. + // Now just look for the @license-end. + for (var j = 0; j < queue.length; j++) { + let n = queue[j]; + comment = this.getComment(n); + if (queue.length === 1 && + typeof comment === 'undefined' + ) { + // Didn't find a closing match, but + // there's only one node in the queue. + // Just accept this script. + return { + licenseName: list[license].licenseName, + type: types.checkTypes.FREE_SINGLE_ITEM + }; + } else if ( + typeof comment !== 'undefined' && + comment.match(licenseEndMagnet) && + this.checkIsLastNode(n) + ) { + // found a closing match. Just accept + // this script. + return { + licenseName: list[license].licenseName, + type: types.checkTypes.FREE_SINGLE_ITEM + }; + } + } + } + } + } + } + } + }, + + /** + * checkIsLastJsNode. + * returns true if n is the last node. + * Or if nodes before it are only comments etc (not valid code.) + * A special LibreJS node is appended at the end of a script tree to + * check if this is the last (and also for narcissus to keep the last comment + * in the tree.) + * TODO: Refactor LibreJS so that END nodes can have a comment. + */ + checkIsLastNode: function (n) { + // first check if the comment is part of the very last statement. + if (n.value === "this" && typeof n.next === 'undefined') { + // just make sure the last node is indeed our harmless bit of + // js. + if (n.tokenizer) { + let source = n.tokenizer.source; + let substring = source.substr(n.start, n.end+23); + if (substring === END_OF_SCRIPT) { + return true; + } + else { + console.debug("substring is ", substring); + return false; + } + } + console.debug("Hurra! This is the end of our script"); + return true; + } + + // isn't our last node. + return false; + }, + + /** + * getComment + * + * Grab the comment(s) from the node. Concatenates + * multiple comments. + * + */ + getComment: function (n) { + var i = 0, length, comment = ""; + + if (typeof n.blockComments === 'undefined' || + n.blockComments === " " + ) { + return; + } + + length = n.blockComments.length; + if (length > 0) { + for (; i < length; i++) { + comment += n.blockComments[i]; + } + } + if (comment === "") { + return; + } + return comment; + } +}; + +exports.freeCheck.initLicenses(licenses.licenses); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/js_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/js_checker.js @@ -0,0 +1,563 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * Copyright (C) 2015 Ruben Rodriguez + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +var narcissusWorker = require("../parser/narcissus_worker") + .narcissusWorker; + +const nonTrivialModule = require("./nontrivial_checker"); +const freeChecker = require("./free_checker"); +const relationChecker = require("./relation_checker"); +const types = require("./constant_types"); + +const scriptsCached = require("../script_entries/scripts_cache") + .scriptsCached; +var isDryRun = require("../addon_management/prefchange").isDryRun; + +var checkTypes = types.checkTypes; + +const token = types.token; + +// for setTimeout. +const timer = require("sdk/timers"); + +var callbackMap = {}; + +/** + * + * Pairs a hash with a given callback + * method from an object. + * + */ +var setHashCallback = function(hash, callback, notification) { + console.debug('setHashCallback', hash); + if (hash in callbackMap && isDryRun()) { + // workaround for issue with dryrun after checking box. + // do nothing. + callbackMap[hash] = callback; + } else if (hash in callbackMap) { + console.debug("callback", callbackMap[hash]); + if (notification && typeof notification.close === 'function') { + notification.close(); + } + throw Error("already being checked."); + } else { + console.debug('setting callbackMap for', hash, 'to', callback); + callbackMap[hash] = callback; + } + console.debug("callback is type: ", callback.constructor); + //callbackMap[hash] = callback; +}; + +var removeHashCallback = function(hash) { + if (hash in callbackMap) { + delete callbackMap[hash]; + } +}; + +/** + * find callback and return result (parse tree). + * + */ +exports.callbackHashResult = function(hash, result) { + console.debug('typeof callbackMap function:', typeof callbackMap[hash]); + console.debug('for hash', hash); + try { + callbackMap[hash](result, hash); + } catch (x) { + console.debug('error in jsChecker', x, 'hash:', hash); + // return tree as false. + console.debug("Error with", x); + if (typeof callbackMap[hash] === 'function') { + callbackMap[hash](false, hash); + } else { + console.debug('callbackHashResult Error', x); + } + } + // remove callback after it's been called. + console.debug('JsChecker.callbackHashResult: calling removeHashCallback'); + removeHashCallback(hash); +}; + +var JsChecker = function() { + this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + this.nonTrivialChecker = null; + this.freeToken = false; + this.nontrivialness = false; + this.parseTree = null; + this.relationChecker = null; + this.jsCode = null; + this.resultReady = null; + this.notification = null; + this.walkTreeCancelled = false; + this.shortText = null; + this.hash = null; + this.queue = null; // will contain the nodes of the script. +}; + +/** + * isFreeLicensed + * + * This function returns true if the input script is licensed under + * a free license. Otherwise, it returns false. + */ +JsChecker.prototype.isFreeLicensed = function(script) { + var magnets = '(' + + 'magnet:\\?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt|' + + 'magnet:\\?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt|' + + 'magnet:\\?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt|' + + 'magnet:\\?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt|' + + 'magnet:\\?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt|' + + 'magnet:\\?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt|' + + 'magnet:\\?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt|' + + 'magnet:\\?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt|' + + 'magnet:\\?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt|' + + 'magnet:\\?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt|' + + 'magnet:\\?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt|' + + 'magnet:\\?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt|' + + 'magnet:\\?xt=urn:btih:87f119ba0b429ba17a44b4bffcab33165ebdacc0&dn=freebsd.txt|' + + 'magnet:\\?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt|' + + 'magnet:\\?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt|' + + 'magnet:\\?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt' + + ')'; + + // Remove licensed parts + var re = new RegExp( + '@license +' + magnets + '.*([\n\r].*?)*@license-end', 'g'); + script = script.replace(re, ''); + + // Remove comments and empty lines + re = new RegExp('\/\/.*|/\\*.*?\\*/|^\s*[\n\r]*', 'gm'); + + script = script.replace(re, ""); + + // If only spaces remain, the file has a free license + return (script.match(/\S/) === null); +}; + +/** + * searchJs + * + * Takes in some javascript code (as string). + * Uses Narcissus parser to build an abstract syntax tree. + * Checks for trivialness. + * + */ +JsChecker.prototype.searchJs = function(jsCode, resultReady, url) { + var that = this; + var bugfix = require('../html_script_finder/bug_fix') + .narcissusBugFixLibreJS; + console.debug('JsChecker.searchJs for script url:', url); + this.url = url; + this.resultReady = resultReady; + this.jsCode = jsCode; + this.shortText = jsCode.replace(bugfix, '').substring(0,100); + this.notification = require("../ui/notification") + .createNotification(this.shortText).notification; + + var verbatimCode = this.jsCode.replace(bugfix, ''); + this.hash = scriptsCached.getHash(verbatimCode); + var isCached = scriptsCached.isCached(verbatimCode, this.hash); + if (isCached) { + console.debug("We have it cached indeed!"); + // there is an existing entry for this exact copy + // of script text. + console.debug('this script result is cached', this.hash, + isCached.result.type); + console.debug("Return right away"); + // we are not generating a parse tree. + this.parseTree = {}; + // fake the result is from parse tree. + this.parseTree.freeTrivialCheck = isCached.result; + + this.relationChecker = isCached.relationChecker; + // leave without doing parsing/analysis part. + this.resultReady(); + this.removeNotification(); + return; + } + + console.debug('url is not cached:', url); + + try { + // no cache, continue. + this.relationChecker = relationChecker.relationChecker(); + this.freeToken = types.emptyTypeObj(); + this.nontrivialness = types.emptyTypeObj(); + + // use this.hash to keep track of comments made by the nontrivial + // checker code about why/how the code is found to be nontrivial. + this.nonTrivialChecker = + nonTrivialModule.nonTrivialChecker(this.hash); + + // register callback and hash. So that result + // can be passed. + setHashCallback( + this.hash, this.handleTree.bind(this), this.notification); + + // parse using ChromeWorker. + console.debug( + 'JsChecker.searchJs(): starting narcissusWorker.parse()'); + narcissusWorker.parse(this.jsCode, this.hash); + } catch (x) { + console.debug('error', x); + this.handleTree(false, x); + this.removeNotification(); + } +}; + +JsChecker.prototype.handleTree = function(tree, errorMessage) { + var that = this; + + if (tree == false || tree == undefined) { + // error parsing tree. Just return nonfree nontrivial. + this.parseTree = {}; + this.parseTree.freeTrivialCheck = types.nontrivialWithComment( + 'error parsing: ' + errorMessage); + + // cache result with hash of script for future checks. + scriptsCached.addEntry(this.jsCode, this.parseTree.freeTrivialCheck, + this.relationChecker, true, this.url); + this.resultReady(); + } else { + try { + // no need to keep parseTree in property + this.parseTree = {}; //tree; + //console.debug(tree); + this.walkTree(tree); + } catch (x) { + console.debug(x, x.lineNumber, x.fileName); + } + } +}; + +/** + * getCheckerResult + * + * Callback to Assign result from walkTree to property. + * reset parse tree. create cache entry. + * + */ +JsChecker.prototype.getCheckerResult = function(result) { + // done with parse tree. Get rid of it. + this.parseTree = {}; + this.removeNotification(); + + this.parseTree.nonTrivialChecker = this.nonTrivialChecker; + + // actual result stored here. hack since we used parseTree before. + this.parseTree.freeTrivialCheck = result; + + // cache result with hash of script for future checks. + scriptsCached.addEntry(this.jsCode, this.parseTree.freeTrivialCheck, + this.relationChecker, true, this.url); + + this.resultReady(); +}; + +/** + * trivialCheck + * + * Runs nodes through a series of conditional statements + * to find out whether it is trivial or not. + * + * @param {object} n. The current node being studied. + * @param {string} t. The type of node being studied + * (initializer, functionbody, try block, ...) + * + */ +JsChecker.prototype.trivialCheck = function(n) { + return this.nonTrivialChecker.checkNontrivial(n); +}; + +/** + * freeCheck + * + * Check if comments above current node could be a free licence. + * If it is, then the script will be flagged as free. + * + * @param {object} n. The current node being studied. + * (initializer, functionbody, try block, ...) + * + */ +JsChecker.prototype.freeCheck = function(n, ntype) { + var check = freeChecker.freeCheck.checkNodeFreeLicense(n, this.queue); + return check; +}; + +/** + * walkTree + * + * An iterative functionwalking the parse tree generated by + * Narcissus. + * + * @param {object} node. The original node. + * + */ +JsChecker.prototype.walkTree = function(node) { + var queue = [node]; + var i, + len, + n, counter = 0, + result, + processQueue, + that = this; + + this.queue = queue; // set as property. + + // set top node as visited. + node.visited = true; + + /** + * functionwalking the tree for a given + * amount of time, before calling itself again. + */ + processQueue = function() { + var nodeResult, end; + + // record start time of functionexecution. + var start = Date.now(); + + if (that.walkTreeCancelled) { + // tree walking already completed. + return; + } + + while (queue.length) { + n = queue.shift(); + n.counter = counter++; + console.debug("Under review", n.type); + if (n.children != undefined) { + // fetch all the children. + len = n.children.length; + for (i = 0; i < len; i++) { + if (n.children[i] != undefined && + n.children[i].visited == undefined + ) { + // figure out siblings. + if (i > 0) { + n.children[i].previous = n.children[i-1]; + } + + if (i < len) { + n.children[i].next = n.children[i+1]; + } + // set parent property. + n.children[i].parent = n; + n.children[i].visited = true; + queue.push(n.children[i]); + } + } + } + + if (n.type != undefined) { + // fetch all properties that may have nodes. + for (var item in n) { + if (item != 'tokenizer' && + item != 'children' && + item != 'length' && + n[item] != null && + typeof n[item] === 'object' && + n[item].type != undefined && + n[item].visited == undefined + ) { + n[item].visited = true; + // set parent property + n[item].parent = n; + queue.push(n[item]); + } + } + } + + that.checkNode(n); + + if (that.freeToken.type === checkTypes.FREE || + that.freeToken.type === checkTypes.FREE_SINGLE_ITEM + ) { + // nothing more to look for. We are done. + that.walkTreeComplete(that.freeToken); + return; + } else if (that.nontrivialness.type === checkTypes.NONTRIVIAL) { + // nontrivial + // we are done. + that.walkTreeComplete(that.nontrivialness); + return; + } + // call processQueue again if needed. + end = Date.now(); + + if (queue.length) { + // there are more nodes in the queue. + + if ((end - start) > 30) { + + // been running more than 20ms, pause + // for 10 ms before calling processQueue + // again. + timer.setTimeout(processQueue, 8); + return; + } + } else { + // we are done. + that.removeNotification(); + that.walkTreeComplete(); + return; + } + } + }; + + if (node.type === token.SCRIPT) { + // this is the global scope. + node.global = true; + node.parent = null; + + this.relationChecker.storeGlobalDeclarations(node); + + queue.push(node); + processQueue(); + } +}; + +/** + * set walk tree cancelled bool as true. + * the walk tree method won't run after the variable + * is set to true. + */ +JsChecker.prototype.cancelWalkTree = function() { + // prevent any further work on node codes. + this.walkTreeCancelled = true; +}; + +/** + * walkTreeComplete + * + * Trigger when the walkTree has been completed or + * when it has been cut short. + * + */ +JsChecker.prototype.walkTreeComplete = function(result) { + var that = this; + this.removeNotification(); + + if (this.walkTreeCancelled) { + // we already triggered complete. + return; + } + + // we set the token to cancel further processing. + this.cancelWalkTree(); + + if (result != undefined) { + // walkTree was returned faster, use it instead. + this.getCheckerResult(result); + + // we are done. + return; + } + + // if all code was fully analyzed. + if (this.nontrivialness.type === checkTypes.NONTRIVIAL) { + this.getCheckerResult(this.nontrivialness); + } else if (this.freeToken.type === checkTypes.FREE) { + // this is free and may or may not define functions, we don't care. + this.getCheckerResult(this.freeToken); + } else if (this.nontrivialness.type === + checkTypes.TRIVIAL_DEFINES_FUNCTION) { + // trivial scripts should become nontrivial if an external script. + // it may or may not be trivial if inline. + this.getCheckerResult(this.nontrivialness); + } else { + // found no nontrivial constructs or free license, so it's + // trivial. + + this.getCheckerResult( + types.trivialFuncWithComment("This script is trivial")); + } +}; + + +/** + * checkNode + * + * checks a single node. + * + */ +JsChecker.prototype.checkNode = function(n) { + var sub; + var fc = this.freeCheck(n); + var tc = this.trivialCheck(n); + + var nodeResult; + + // check if identifier may be window property (assumption). + this.relationChecker.checkIdentifierIsWindowProperty(n); + + /*if (fc) { + console.debug("FC is", fc, "type is", fc.type); + }*/ + if (fc && fc.type == checkTypes.FREE) { + // this is free! + // freeToken is persistent across nodes analyzed and valid + // for an entire script. + this.freeToken = types.freeWithComment( + "Script appears to be free under the following license: " + + fc.licenseName); + return; + } else if (fc && fc.type == checkTypes.FREE_SINGLE_ITEM) { + console.debug("free single item"); + this.freeToken = types.singleFreeWithComment( + "Script appears to be free under the following license: " + + fc.licenseName); + return; + } + + if (tc) { + if (tc.type === checkTypes.NONTRIVIAL) { + // nontrivial_global is deprecated + this.nontrivialness = tc; + return; + } else if (tc.type === checkTypes.TRIVIAL_DEFINES_FUNCTION) { + this.nontrivialness = tc; + return; + } + } +}; + +JsChecker.prototype.removeNotification = function() { + console.debug('JsChecker.removeNotification()'); + if (this.notification && + typeof this.notification.close === 'function' + ) { + console.debug('removing', this.shortText); + // remove notification early on. + this.notification.close(); + this.notification = null; + } +}; + +exports.jsChecker = function() { + return new JsChecker(); +}; + +exports.removeHashCallback = removeHashCallback; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/license_definitions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/license_definitions.js @@ -0,0 +1,296 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +exports.types = { + SHORT: 'short', + LAZY: 'lazy', + FULL: 'full' +}; + +var type = exports.types; + +/** + * List of all the licenses. + * Currently only short substrings are used with regex. + * + * The licenses are indexed by their "Identifier", which, when possible, + * corresponds to their identifier as specified by SPDX here: + * https://spdx.org/licenses/ + */ +exports.licenses = { + 'CC0-1.0': { + licenseName: 'Creative Commons CC0 1.0 Universal', + identifier: 'CC0-1.0', + canonicalUrl: [ + 'http://creativecommons.org/publicdomain/zero/1.0/legalcode', + 'magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt' + ], + licenseFragments: [] + }, + + + 'GPL-2.0': { + licenseName: 'GNU General Public License (GPL) version 2', + identifier: 'GPL-2.0', + canonicalUrl: [ + 'http://www.gnu.org/licenses/gpl-2.0.html', + 'magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt' + ], + licenseFragments: [{text: "<THISPROGRAM> is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.", type: type.SHORT}, + {text:"Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the \"GPL\"), or the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL.", type: type.SHORT}] + }, + + 'GPL-3.0': { + licenseName: 'GNU General Public License (GPL) version 3', + identifier: 'GPL-3.0', + canonicalUrl: [ + 'http://www.gnu.org/licenses/gpl-3.0.html', + 'magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt' + ], + licenseFragments: [ + {text: "The JavaScript code in this page is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License (GNU GPL) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The code is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. As additional permission under GNU GPL version 3 section 7, you may distribute non-source (e.g., minimized or compacted) forms of that code without the copy of the GNU GPL normally required by section 4, provided you include this license notice and a URL through which recipients can access the Corresponding Source.", type: type.SHORT}, + {text: "<THISPROGRAM> is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.", type: type.SHORT}] + }, + + 'GNU-All-Permissive': { + licenseName: 'GNU All-Permissive License', + licenseFragments: [{text: "Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty.", type: type.SHORT}] + }, + + 'Apache-2.0': { + licenseName: 'Apache License, Version 2.0', + identifier: 'Apache-2.0', + canonicalUrl: [ + 'http://www.apache.org/licenses/LICENSE-2.0', + 'magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt' + ], + licenseFragments: [{text: "Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0", type: type.SHORT}] + }, + + 'LGPL-2.1': { + licenseName: 'GNU Lesser General Public License, version 2.1', + identifier: 'LGPL-2.1', + canonicalUrl: [ + 'http://www.gnu.org/licenses/lgpl-2.1.html', + 'magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt' + ], + licenseFragments: [{text: "<THISLIBRARY> is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.", type: type.SHORT}] + }, + + 'LGPL-3.0': { + licenseName: 'GNU Lesser General Public License, version 3', + identifier: 'LGPL-3.0', + canonicalUrl: [ + 'http://www.gnu.org/licenses/lgpl-3.0.html', + 'magnet:?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt' + ], + licenseFragments: [{text: "<THISPROGRAM> is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.", type: type.SHORT}] + }, + + 'AGPL-3.0': { + licenseName: 'GNU AFFERO GENERAL PUBLIC LICENSE version 3', + identifier: 'AGPL-3.0', + canonicalUrl: [ + 'http://www.gnu.org/licenses/agpl-3.0.html', + 'magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt' + ], + + licenseFragments: [{text: "<THISPROGRAM> is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.", type: type.SHORT}] + }, + + 'BSL-1.0': { + licenseName: 'Boost Software License 1.0', + identifier: 'BSL-1.0', + canonicalUrl: [ + 'http://www.boost.org/LICENSE_1_0.txt', + 'magnet:?xt=urn:btih:89a97c535628232f2f3888c2b7b8ffd4c078cec0&dn=Boost-1.0.txt' + ], + licenseFragments: [{text: "Boost Software License <VERSION> <DATE> Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the \"Software\") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following", type: type.SHORT}] + }, + + 'BSD-3-Clause': { + licenseName: "BSD 3-Clause License", + identifier: 'BSD-3-Clause', + canonicalUrl: [ + 'http://opensource.org/licenses/BSD-3-Clause', + 'magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt' + ], + licenseFragments: [{text: "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.", type: type.SHORT}] + }, + + 'BSD-2-Clause': { + licenseName: "BSD 2-Clause License", + identifier: 'BSD-2-Clause', + licenseFragments: [{text: "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.", type: type.SHORT}] + }, + + 'EPL-1.0': { + licenseName: "Eclipse Public License Version 1.0", + identifier: "EPL-1.0", + canonicalUrl: [ + "http://www.eclipse.org/legal/epl-v10.html", + "magnet:?xt=urn:btih:4c6a2ad0018cd461e9b0fc44e1b340d2c1828b22&dn=epl-1.0.txt" + ], + licenseFragments: [ + { + text: "THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.", + type: type.SHORT + } + ] + }, + + 'MPL-2.0': { + licenseName: 'Mozilla Public License Version 2.0', + identifier: 'MPL-2.0', + canonicalUrl: [ + 'http://www.mozilla.org/MPL/2.0', + 'magnet:?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt' + ], + licenseFragments: [{text: "This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.", type: type.SHORT }] + }, + + 'Expat': { + licenseName: 'Expat License (sometimes called MIT Licensed)', + identifier: 'Expat', + canonicalUrl: [ + 'http://www.jclark.com/xml/copying.txt', + 'magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt' + ], + licenseFragments: [{text: "Copyright <YEAR> <NAME> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", type: type.SHORT}] + }, + + 'UPL': { + licenseName: 'Universal Permissive License', + identifier: 'UPL-1.0', + canonicalUrl: [ + 'magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt' + ], + licenseFragments: [{ + text: "The Universal Permissive License (UPL), Version 1.0", + type: type.SHORT + }] + }, + + 'X11': { + licenseName: 'X11 License', + identifier: 'X11', + canonicalUrl: [ + 'magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt' + ], + licenseFragments: [{text: "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", type: type.SHORT}] + }, + + 'XFree86-1.1': { + licenseName: "XFree86 1.1 License", + identifier: 'XFree86-1.1', + canonicalUrl: [ + 'http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3', + 'http://www.xfree86.org/current/LICENSE4.html', + 'magnet:?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt' + ], + licenseFragments: [{text: "All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution, and in the same place and form as other copyright, license and disclaimer information.\n3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: \"This product includes software developed by The XFree86 Project, Inc (http://www.xfree86.org/) and its contributors\", in the same place and form as other third-party acknowledgments. Alternately, this acknowledgment may appear in the software itself, in the same form and location as other such third-party acknowledgments.4. Except as contained in this notice, the name of The XFree86 Project, Inc shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The XFree86 Project, Inc.", type: type.SHORT} + ] + }, + + 'FreeBSD': { + licenseName: "FreeBSD License", + identifier: 'FreeBSD', + canonicalUrl: [ + 'http://www.freebsd.org/copyright/freebsd-license.html', + 'magnet:?xt=urn:btih:87f119ba0b429ba17a44b4bffcab33165ebdacc0&dn=freebsd.txt' + ], + licenseFragments: [{text: "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.", type: type.SHORT}] + }, + + 'ISC': { + licenseName: "The ISC License", + identifier: 'ISC', + canonicalUrl: [ + 'https://www.isc.org/downloads/software-support-policy/isc-license/', + 'magnet:?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt' + ], + licenseFragments: [{text: "Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.", type: type.SHORT}, + {text: "Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.", type: type.SHORT}] + }, + + 'jQueryTools': { + licenseName: "jQuery Tools", + licenseFragments: [{ + text: 'NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.', + type: type.SHORT + }] + }, + + 'Artistic-2.0': { + licenseName: "Artistic License 2.0", + identifier: 'Artistic-2.0', + canonicalUrl: [ + "http://www.perlfoundation.org/artistic_license_2_0", + "magnet:?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt" + ], + licenseFragments: [] + }, + + 'PublicDomain': { + licenseName: "Public Domain", + canonicalUrl: [ + 'magnet:?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt' + ], + licenseFragments: [] + }, + + 'CPAL-1.0': { + licenseName: 'Common Public Attribution License Version 1.0 (CPAL)', + identifier: 'CPAL-1.0', + canonicalUrl: [ + 'http://opensource.org/licenses/cpal_1.0', + 'magnet:?xt=urn:btih:84143bc45939fc8fa42921d619a95462c2031c5c&dn=cpal-1.0.txt' + ], + licenseFragments: [ + { + text: 'The contents of this file are subject to the Common Public Attribution License Version 1.0', + type: type.SHORT + }, + { + text: 'The term "External Deployment" means the use, distribution, or communication of the Original Code or Modifications in any way such that the Original Code or Modifications may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Code or Modifications as a distribution under section 3.1 and make Source Code available under Section 3.2.', + type: type.SHORT + } + ] + }, + 'WTFPL': { + licenseName: 'Do What The F*ck You Want To Public License (WTFPL)', + identifier: 'WTFPL', + canonicalUrl: [ + 'http://www.wtfpl.net/txt/copying/', + 'magnet:?xt=urn:btih:723febf9f6185544f57f0660a41489c7d6b4931b&dn=wtfpl.txt' + ], + licenseFragments: [ + { + text: 'DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE', + type: type.SHORT + }, + { + text: '0. You just DO WHAT THE FUCK YOU WANT TO.', + type: type.SHORT + } + ] + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/nontrivial_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/nontrivial_checker.js @@ -0,0 +1,376 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +const types = require("./constant_types"); + +// constants from Narcissus for function types. +const DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2; + +const token = types.token; + +var checkTypes = types.checkTypes; + +var utils = { + /** + * nodeContains + * Checks that node contains both a type and a value. + * Shortcut to check for null/undefined. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if matching. + */ + nodeContains: function (n, type, value) { + if (n != undefined) { + return n.type === type && + n.value === value; + } + }, + + /** + * isType + * Checks that node is of a certain type. + * Shortcut to check for null/undefined. + * + * @param {object} n. The current node being studied. + * @return {boolean}. True if it's the right type. + */ + isType: function (n, type) { + return n != undefined && n.type === type; + }, + + isNotType: function (n, type) { + return n != undefined && n.type !== type; + }, + + /** + * hasChildren + * + * Checks the token on the left + * and on the right. + * + * @param {object} n. The current node being studied. + * @param {leftType} token constant. The type on the + * left. + * @param {rightType} token constant. The type of child + * on the right + * + */ + hasChildren: function (n, leftType, rightType) { + if (types == undefined) { + return false; + } + return this.isType(n.children[0], leftType) && + this.isType(n.children[1], rightType); + }, + + /** + * findScriptTag + * + * This method should probably be replaced with DOM testing + * as regex is rather insufficiant, and this wouldn't cover + * tricky constructs as shown in http://ha.ckers.org/xss.html. + */ + findScriptTag: function (n) { + return n.value != undefined && + /<script[^>]*?>/i.test(n.value); + } +}; + +var NonTrivialChecker = function() { + this.definesFunction = false; + this.hash = null; +}; + +/** + * definesFunctionFound + * + * Returns true if it finds a node of type FUNCTION + * that isn't a callback or an IIFE. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.definesFunctionFound = function (n) { + var isFunction = false; + if (n.type === token.FUNCTION && + n.body != undefined) { + + if (n.functionForm !== token.DECLARED_FORM && + ((n.parent.type === token.LIST && + n.parent.parent.type === token.CALL) || + n.parent.type === token.CALL) && + n.name == undefined) { + // this is a callback or an immediately + // invoked function expression "IIFE". + isFunction = false; + } else { + // this is a regular function declaration or + // function expression assigned to a variable. + //console.log("THIS DEFINES FUNCTION"); + isFunction = true; + } + } + + // look for Function constructor. + if (n.type === token.IDENTIFIER && + n.value === 'Function' && + (n.parent.type === token.NEW_WITH_ARGS || + n.parent.type === token.CALL)) { + // this is a Function constructor. + //console.log("THIS DEFINES FUNCTION"); + isFunction = true; + } + + return isFunction; +}; + + +/** + * invokesEval + * + * Returns true (nontrivial) if it finds any use of + * the eval function. For simplicity, we assume any + * use of an identifier "eval" is the eval function. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.invokesEval = function (n) { + return (n.type === token.CALL && + utils.nodeContains(n.children[0], token.IDENTIFIER, 'eval') || + n.type === token.IDENTIFIER && n.value === 'eval'); +}; + +/** + * evalIdentifier + * + * Returns true (nontrivial) if it finds any use of + * the eval function. For simplicity, we assume any + * use of an identifier "eval" is the eval function. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.evalIdentifier = function (n) { + return n.type === token.IDENTIFIER && n.value === 'eval'; +}; + + +/** + * invokesMethodBracketSuffix + * + * Finds a method being invoked using the bracket suffix notation + * rather than the dot notation. It is difficult without keeping track of + * variable values to check for what method is actually being called. + * So we're just flagging any use of this construct as nontrivial. + * e.g., should catch: xhr[a+b]('GET', 'http://www.example.com'); + * Should not catch other uses such as: myArray[num]; + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.invokesMethodBracketSuffix = function (n) { + return n.type === token.CALL && utils.isType(n.children[0], token.INDEX); +}; + +/** + * createsXhrObject + * + * Creates an xhr object. + * Since all "new XMLHttpRequest", "XMLHttpRequest()", + * and "new window.XMLHttpRequest" instantiate the xhr object, + * we assume (without further proof) that any use + * of the identifier "XMLHttpRequest" and "ActiveXObject" + * is an xhr object. + * Constructs like window[a+b]() are already caught by the + * bracket suffix check. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.createsXhrObject = function (n) { + return (n.type === token.IDENTIFIER) && + (n.value === 'XMLHttpRequest' || + n.value === 'ActiveXObject'); +}; + +/** + * invokesXhrOpen + * + * Here we assume the call of an open method must be an xhr request + * (and not some other object) by checking the number of arguments. + * In most cases this method won't be used since createsXhrObject + * will already have caught the xhr. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + */ +NonTrivialChecker.prototype.invokesXhrOpen = function (n) { + return n.type === token.CALL && + utils.hasChildren(n, token.DOT, token.LIST) && + utils.isType(n.children[0].children[0], token.IDENTIFIER) && + utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'open') && + n.children[1].children.length > 1; +}; + +/** + * createsScriptElement + * + * Checks for document.createElement() that create a script. In the case + * it creates an element from a variable, we assume it's a script. In the + * future we might want to check for the value of that string variable + * (e.g., if a variable is assigned 'script', raise a flag) + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + * + */ +NonTrivialChecker.prototype.createsScriptElement = function (n) { + return n.type === token.CALL && + utils.hasChildren(n, token.DOT, token.LIST) && + utils.isType(n.children[0].children[0], token.IDENTIFIER) && + utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'createElement') && + (utils.nodeContains(n.children[1].children[0], token.STRING, 'script') || + utils.isType(n.children[1].children[0], token.IDENTIFIER)); +}; + +/** + * writesScriptAsHtmlString + * + * catches myObj.write('<script></script>'); + * or any myObj.write(myStringVariable); + * or concatenation such as: + * myObj.write('<scri' + stringVariable); + * or 'something' + 'somethingelse'. + * + * To check for javascript here we might want to look at the list + * from ha.ckers.org/xss.html for the future. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + */ +NonTrivialChecker.prototype.writesScriptAsHtmlString = function (n) { + var listArg; + + if (n.type === token.CALL && + utils.hasChildren(n, token.DOT, token.LIST) && + utils.isType(n.children[0].children[0], token.IDENTIFIER) && + utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'write') + ) { + if (utils.isNotType(n.children[1].children[0], token.STRING)) { + // return true if any operation or concatenation. + // We are cautious (as it could + // embed a script) and flag this as nontrivial. + + return true; + } + return utils.findScriptTag(n.children[1].children[0]); + } else { + return false; + } +}; + +/** + * nontrivial anytime we see an identifier as innerHTML + */ +NonTrivialChecker.prototype.innerHTMLIdentifier = function (n) { + if ((n.type === token.IDENTIFIER || + n.type === token.STRING) && + n.value === 'innerHTML' + ) { + return true; + } +}; + +/** + * checkNontrivial + * + * Contains all the conditionals that try to identify, + * step by step, all code that could be flagged as + * nontrivial. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + */ +NonTrivialChecker.prototype.checkNontrivial = function (n, t) { + + if (n.type === token.IDENTIFIER && this.evalIdentifier(n)) { + //console.log("NONTRIVIAL: eval has been found in code"); + return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); + } + + if (this.innerHTMLIdentifier(n)) { + //console.log("NONTRIVIAL: innerHTML identifier"); + return types.nontrivialWithComment("NONTRIVIAL: innerHTML identifier"); + } + + // the node is an identifier + if (n.type === token.IDENTIFIER && this.createsXhrObject(n)) { + //console.log('NONTRIVIAL: Creates an xhr object'); + return types.nontrivialWithComment('NONTRIVIAL: Creates an xhr object'); + } + + // this is a method/function call + if (n.type === token.CALL) { + + if (this.invokesEval(n)) { + //console.log("NONTRIVIAL: eval has been found in code"); + return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); + } + + if (this.invokesMethodBracketSuffix(n)) { + //console.log('NONTRIVIAL: square bracket suffix method call detected'); + return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); + } + + if (this.invokesXhrOpen(n)) { + //console.log('NONTRIVIAL: an open method similar to xhr.open is used'); + return types.nontrivialWithComment('NONTRIVIAL: square bracket suffix method call detected'); + } + + if (this.createsScriptElement(n)) { + //console.log('NONTRIVIAL: creates script element dynamically.'); + return types.nontrivialWithComment('NONTRIVIAL: an open method similar to xhr.open is used'); + } + + if (this.writesScriptAsHtmlString(n)) { + //console.log('NONTRIVIAL: writes script as html dynamically.'); + return types.nontrivialWithComment('NONTRIVIAL: creates script element dynamically.'); + } + } + + // The node is a function definition. + // Most common occurence. + if (this.definesFunctionFound(n)) { + return types.trivialFuncWithComment("Script is trivial but defines one or more functions"); + } + + // found nothing else, so trivial. + return types.trivialWithComment("Script is trivial"); +}; + +exports.nonTrivialChecker = function () { + return new NonTrivialChecker(); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/pattern_utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/pattern_utils.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/privacy_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/privacy_checker.js @@ -0,0 +1,46 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +const privacyThreatJs = require('./privacy_threat_definitions.js'); +const patternUtils = require('./pattern_utils').patternUtils; + +exports.privacyCheck = { + checkScriptPrivacyThreat: function (currentScript) { + var list = privacyThreatJs.js; + var i; + var item; + var max; + + currentScript = patternUtils.removeWhitespace(currentScript); + + for (item in list) { + max = list[item].length; + + for (i = 0; i < max; i++) { + if (list[item][i].test(currentScript)) { + return true; + } + } + } + return false; + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/privacy_threat_definitions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/privacy_threat_definitions.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/relation_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_checker/relation_checker.js @@ -0,0 +1,291 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +/** + * relation_checker.js + * + * Finds out if two scripts are related to each other. + * + */ +const types = require("./constant_types"); + +const token = types.token; + +// all predefined window properties (methods and variables). +const windowPropertiesHash = { + "addEventListener": 1, "alert": 1, "applicationCache": 1, + "Array": 1, "ArrayBuffer": 1, "atob": 1, "back": 1, "blur": 1, + "Boolean": 1, "btoa": 1, "captureEvents": 1, "CharacterData": 1, + "clearInterval": 1, "clearTimeout": 1, "close": 1, "closed": 1, + "Components": 1, "confirm": 1, "console": 1, "constructor": 1, + "content": 1, "controllers": 1, "crypto": 1, + "CSSStyleDeclaration": 1, "Date": 1, "decodeURI": 1, + "decodeURIComponent": 1, "defaultStatus": 1, + "disableExternalCapture": 1, "dispatchEvent": 1, "Document": 1, + "document": 1, "DocumentType": 1, "dump": 1, "Element": 1, + "enableExternalCapture": 1, "encodeURI": 1, "encodeURIComponent": 1, + "Error": 1, "escape": 1, "eval": 1, "EvalError": 1, "Event": 1, + "find": 1, "Float32Array": 1, "Float64Array": 1, "focus": 1, + "forward": 1, "frameElement": 1, "frames": 1, "fullScreen": 1, + "Function": 1, "Generator": 1, "getComputedStyle": 1, + "getInterface": 1, "getSelection": 1, "globalStorage": 1, + "history": 1, "home": 1, "HTMLBodyElement": 1, "HTMLCollection": 1, + "HTMLDivElement": 1, "HTMLDocument": 1, "HTMLElement": 1, + "HTMLHeadElement": 1, "HTMLHeadingElement": 1, "HTMLHtmlElement": 1, + "HTMLStyleElement": 1, "HTMLUnknownElement": 1, "Infinity": 1, + "innerHeight": 1, "innerWidth": 1, "InstallTrigger": 1, + "Int16Array": 1, "Int32Array": 1, "Int8Array": 1, "InternalError": 1, + "isFinite": 1, "isNaN": 1, "isXMLName": 1, "Iterator": 1, + "JSON": 1, "length": 1, "localStorage": 1, "Location": 1, + "location": 1, "locationbar": 1, "matchMedia": 1, "Math": 1, + "menubar": 1, "moveBy": 1, "moveTo": 1, "mozAnimationStartTime": 1, + "mozIndexedDB": 1, "mozInnerScreenX": 1, "mozInnerScreenY": 1, + "mozPaintCount": 1, "mozRequestAnimationFrame": 1, "name": 1, + "Namespace": 1, "NaN": 1, "navigator": 1, "netscape": 1, + "Node": 1, "NodeList": 1, "Number": 1, "Object": 1, "open": 1, + "openDialog": 1, "opener": 1, "outerHeight": 1, "outerWidth": 1, + "pageXOffset": 1, "pageYOffset": 1, "parent": 1, "parseFloat": 1, + "parseInt": 1, "performance": 1, "personalbar": 1, "pkcs11": 1, + "postMessage": 1, "print": 1, "prompt": 1, "QName": 1, + "RangeError": 1, "ReferenceError": 1, "RegExp": 1, + "releaseEvents": 1, "removeEventListener": 1, "resizeBy": 1, + "resizeTo": 1, "routeEvent": 1, "screen": 1, "screenX": 1, + "screenY": 1, "scroll": 1, "scrollbars": 1, "scrollBy": 1, + "scrollByLines": 1, "scrollByPages": 1, "scrollMaxX": 1, + "scrollMaxY": 1, "scrollTo": 1, "scrollX": 1, "scrollY": 1, + "self": 1, "sessionStorage": 1, "setInterval": 1, "setResizable": 1, + "setTimeout": 1, "showModalDialog": 1, "sizeToContent": 1, + "status": 1, "statusbar": 1, "stop": 1, "StopIteration": 1, + "StorageList": 1, "String": 1, "SyntaxError": 1, "Text": 1, + "toolbar": 1, "top": 1, "TypeError": 1, "Uint16Array": 1, + "Uint32Array": 1, "Uint8Array": 1, "Uint8ClampedArray": 1, + "undefined": 1, "unescape": 1, "uneval": 1, "updateCommands": 1, + "URIError": 1, "URL": 1, "WeakMap": 1, "Window": 1, "window": 1, + "XML": 1, "XMLList": 1, "XPCNativeWrapper": 1}; + +// all predefined document properties. +const documentPropertiesHash = {'activeElement': 1, 'addBinding': 1, + 'addEventListener': 1, 'adoptNode': 1, 'alinkColor': 1, 'anchors': 1, + 'appendChild': 1, 'applets': 1, 'ATTRIBUTE_NODE': 1, 'attributes': 1, + 'baseURI': 1, 'bgColor': 1, 'body': 1, 'captureEvents': 1, + 'CDATA_SECTION_NODE': 1, 'characterSet': 1, 'childNodes': 1, 'clear': + 1, 'cloneNode': 1, 'close': 1, 'COMMENT_NODE': 1, + 'compareDocumentPosition': 1, 'compatMode': 1, 'contentType': 1, + 'cookie': 1, 'createAttribute': 1, 'createAttributeNS': 1, + 'createCDATASection': 1, 'createComment': 1, 'createDocumentFragment': + 1, 'createElement': 1, 'createElementNS': 1, 'createEvent': 1, + 'createExpression': 1, 'createNodeIterator': 1, 'createNSResolver': 1, + 'createProcessingInstruction': 1, 'createRange': 1, 'createTextNode': + 1, 'createTreeWalker': 1, 'currentScript': 1, 'defaultView': 1, + 'designMode': 1, 'dir': 1, 'dispatchEvent': 1, 'doctype': 1, + 'DOCUMENT_FRAGMENT_NODE': 1, 'DOCUMENT_NODE': 1, + 'DOCUMENT_POSITION_CONTAINED_BY': 1, 'DOCUMENT_POSITION_CONTAINS': 1, + 'DOCUMENT_POSITION_DISCONNECTED': 1, 'DOCUMENT_POSITION_FOLLOWING': 1, + 'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC': 1, + 'DOCUMENT_POSITION_PRECEDING': 1, 'DOCUMENT_TYPE_NODE': 1, + 'documentElement': 1, 'documentURI': 1, 'domain': 1, 'ELEMENT_NODE': + 1, 'elementFromPoint': 1, 'embeds': 1, 'enableStyleSheetsForSet': 1, + 'ENTITY_NODE': 1, 'ENTITY_REFERENCE_NODE': 1, 'evaluate': 1, + 'execCommand': 1, 'execCommandShowHelp': 1, 'fgColor': 1, + 'firstChild': 1, 'forms': 1, 'getAnonymousElementByAttribute': 1, + 'getAnonymousNodes': 1, 'getBindingParent': 1, 'getElementById': 1, + 'getElementsByClassName': 1, 'getElementsByName': 1, + 'getElementsByTagName': 1, 'getElementsByTagNameNS': 1, + 'getSelection': 1, 'getUserData': 1, 'hasAttributes': 1, + 'hasChildNodes': 1, 'hasFocus': 1, 'head': 1, 'images': 1, + 'implementation': 1, 'importNode': 1, 'inputEncoding': 1, + 'insertBefore': 1, 'isDefaultNamespace': 1, 'isEqualNode': 1, + 'isSameNode': 1, 'isSupported': 1, 'lastChild': 1, 'lastModified': 1, + 'lastStyleSheetSet': 1, 'linkColor': 1, 'links': 1, + 'loadBindingDocument': 1, 'localName': 1, 'location': 1, + 'lookupNamespaceURI': 1, 'lookupPrefix': 1, 'mozSetImageElement': 1, + 'mozSyntheticDocument': 1, 'namespaceURI': 1, 'nextSibling': 1, + 'nodeName': 1, 'nodeType': 1, 'nodeValue': 1, 'normalize': 1, + 'NOTATION_NODE': 1, 'open': 1, 'ownerDocument': 1, 'parentNode': 1, + 'plugins': 1, 'preferredStyleSheetSet': 1, 'prefix': 1, + 'previousSibling': 1, 'PROCESSING_INSTRUCTION_NODE': 1, + 'queryCommandEnabled': 1, 'queryCommandIndeterm': 1, + 'queryCommandState': 1, 'queryCommandSupported': 1, + 'queryCommandText': 1, 'queryCommandValue': 1, 'querySelector': 1, + 'querySelectorAll': 1, 'readyState': 1, 'referrer': 1, + 'releaseCapture': 1, 'releaseEvents': 1, 'removeBinding': 1, + 'removeChild': 1, 'removeEventListener': 1, 'replaceChild': 1, + 'routeEvent': 1, 'selectedStyleSheetSet': 1, 'setUserData': 1, + 'styleSheets': 1, 'styleSheetSets': 1, 'TEXT_NODE': 1, 'textContent': + 1, 'title': 1, 'URL': 1, 'vlinkColor': 1, 'write': 1, 'writeln': 1, + 'xmlEncoding': 1, 'xmlStandalone': 1, 'xmlVersion': 1}; + +var relationChecker = { + + // identifies scripts across modules. + scriptId: null, + + // stores all left-side identifier in 'assign' types. + assignments: null, + + // stores var declarations in global scope. + variableDeclarations: null, + + // stores top declarations in global scope. + functionDeclarations: null, + + nonWindowProperties: null, + + init: function (scriptId) { + this.scriptId = scriptId; + this.assignments = []; + this.variableDeclarations = {}; + this.functionDeclarations = {}; + this.nonWindowProperties = {}; + }, + + isWindowProperty: function (identifier) { + return (identifier in windowPropertiesHash) ? true : false; + }, + + isDocumentProperty: function (identifier) { + return (identifier in documentPropertiesHash) ? true : false; + }, + + storeNodeVars: function (n) { + if (n.varDecls != undefined) { + var i = 0, le = n.varDecls.length; + for (; i < le; i++) { + this.variableDeclarations[n.varDecls[i].value] = 1; + } + } + }, + + storeNodeFunctions: function (n) { + if (n.funDecls != undefined) { + var i = 0, le = n.funDecls.length; + for (; i < le; i++) { + this.functionDeclarations[n.funDecls[i].name] = 1; + } + } + }, + storeGlobalDeclarations: function (topNode) { + this.storeNodeVars(topNode); + this.storeNodeFunctions(topNode); + }, + storeNodeGlobalDeclarations: function (n) { + if (n.global === true) { + this.storeNodeVars(n); + this.storeNodeFunctions(n); + } + }, + + storeNodeAssignments: function (n) { + if (n.type === token.ASSIGN && + n.children != undefined && + n.children[0].type === token.IDENTIFIER) { + this.assignments.push(n.children[0].value); + } + }, + + // checks the parent script is in global scope. + isInGlobalScope: function (n) { + var currentNode = n; + + while (currentNode != undefined) { + if (currentNode.type === token.SCRIPT && + currentNode.global === true) { + return true; + } else if (currentNode.type === token.SCRIPT) { + return false; + } + currentNode = currentNode.parent; + } + }, + + // looks for an identifier being declared as either a + // variable or a function within the scope. Currently, + // we don't care about assignments. + lookForIdentifierInAllScopes: function (n, val) { + + var currentNode = n, i, le, vars, funcs; + while (currentNode != undefined) { + if (currentNode.varDecls != undefined) { + vars = currentNode.varDecls; + le = vars.length; + for (i = 0; i < le; i++) { + if (vars[i].value === val) { + console.debug('FOUND declaration for', val); + return true; + } + } + } + if (currentNode.funDecls != undefined) { + funcs = currentNode.funDecls; + le = funcs.length; + for (i = 0; i < le; i++) { + if (funcs[i].name === val) { + console.debug('FOUND function declaration for', val); + return true; + } + } + } + currentNode = currentNode.parent; + } + console.debug('did not find declaration or assignment for', val); + }, + + // Heuristic method for window properties. + // this doesn't prove they are window properties, but + // it allows to make a good guess. These variables could have + // been assigned to something else... + checkIdentifierIsWindowProperty: function (n) { + + if (n.type === token.IDENTIFIER && + (n.parent.type === token.CALL || + (n.parent.type === token.DOT && + n.previous != undefined && + (n.previous.type === token.THIS || + (n.previous.type === token.IDENTIFIER && + n.previous.value === 'window')))) && + n.value in windowPropertiesHash) { + + this.lookForIdentifierInAllScopes(n, n.value); + + } + + else if (n.type === token.IDENTIFIER && + n.parent != undefined && + n.parent.type === token.DOT && + n.previous != undefined && + n.previous.type === token.THIS && + this.isInGlobalScope(n)) { + console.debug(n.type, 'use of this in the global scope, seems ok.', n.value); + } + else if (n.type === token.IDENTIFIER) { + // not found. + console.debug(n.type, 'probably not a window prop', n.value); + this.nonWindowProperties[n.value] = 1; + } + } + +}; + +exports.relationChecker = function (scriptId) { + var obj = Object.create(relationChecker); + obj.init(scriptId); + return obj; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_load_observer/js_load_observer.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/js_load_observer/js_load_observer.js @@ -0,0 +1,147 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); + +var observerService = Cc["@mozilla.org/observer-service;1"] +.getService(Ci.nsIObserverService); + +var acceptedScripts = require("../script_entries/accepted_scripts") + .acceptedScripts; +var allowedRef = require('../http_observer/allowed_referrers') + .allowedReferrers; + +var urlHandler = require("../url_handler/url_handler"); + +var ScriptAnalyzer = function() { + // the URL of the current page. + this.pageURL = null; +}; + +/* + * analyzeScriptBeforeExec + * + * Ensure that the script is found in the acceptedScript before + * allowing to execute it. + * + */ +ScriptAnalyzer.prototype.analyzeScriptBeforeExec = function (e) { + if (typeof e.target.textContent === 'undefined') { + throw new TypeError('event.target must be a script element'); + } + console.debug('analyzeScriptBeforeExec executed'); + + var script = e.target, isAccepted; + var text = script.src ? + script.src : script.textContent.substring(0,100); + var notif = require("../ui/notification") + .createNotification(text).notification; + this.pageURL = urlHandler.removeFragment(script.ownerDocument.URL); + if (!allowedRef.urlInAllowedReferrers(this.pageURL)) { + + if (script.src !== undefined && script.src !== '') { + isAccepted = this.checkExternalScript(script); + } else { + isAccepted = this.checkInlineScript(script); + } + + if (isAccepted === false && + !(/^(file:\/\/|chrome:\/\/|about\:)/.test(this.pageURL)) + ) { + console.debug(this.pageURL); + // file:// types of pages are allowed. + + // set invalid type so that the script is detected + // by LibreJS as blocked (although it's blocked using + // preventDefault(). + script.setAttribute('type', 'librejs/blocked'); + //script.setAttribute('data-librejs-blocked', 'dynamically'); + script.setAttribute('data-librejs-blocked-src', script.src); + script.removeAttribute('src'); + + e.preventDefault(); + return false; + } else { + console.debug("script is accepted", script.src); + script.setAttribute('data-librejs-accepted', 'dynamically'); + return true; + } + + } else { + return true; + } + + return false; +}; + +ScriptAnalyzer.prototype.checkExternalScript = function (script) { + var url = urlHandler.resolve(this.pageURL, script.src); + + if (this.isScriptAccepted(url, false)) { + // url in src attribute is found as accepted. + return true; + } + + else { + // the script hasn't been accepted before. + // block it. + console.debug("script is not accepted", script.src); + return false; + } + +}; + +ScriptAnalyzer.prototype.checkInlineScript = function (script) { + return this.isScriptAccepted(script.text, true); +}; + +ScriptAnalyzer.prototype.isScriptAccepted = function (contents, inline) { + + if (!acceptedScripts.isFound(this.pageURL, {'inline': inline, 'contents': contents})) { + return false; + } + + else { + return true; + } +}; + +var scriptAnalyzer = new ScriptAnalyzer(); + +var jsLoadObserver = { + observe: function (domWindow) { + domWindow.document.addEventListener( + "beforescriptexecute", + scriptAnalyzer.analyzeScriptBeforeExec.bind(scriptAnalyzer), + false); + } +}; + +observerService.addObserver(jsLoadObserver, + 'content-document-global-created', + false); + +exports.removeJsLoadObserver = function () { + observerService.removeObserver(jsLoadObserver, + 'content-document-global-created'); + console.debug('removing jsLoadObserver'); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/main.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/main.js @@ -0,0 +1,71 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +// Uncomment the following to start debugging, or do it from about:config. +// var name = "extensions.jid1-KtlZuoiikVfFew@jetpack.sdk.console.logLevel"; +// require("sdk/preferences/service").set(name, "all"); + +const { Cc, Ci } = require("chrome"); + +const librejsStorage = require("./settings/storage").librejsStorage; +let addonManage = require("./addon_management/install_uninstall"); +let httpObserver = require("./http_observer/http_request_observer"); +let prefObserver = require("./pref_observer/pref_observer"); +let prefChange = require("./addon_management/prefchange"); +let uiInfo = require("./ui/ui_info"); +let scriptPanel = require("./ui/script_panel.js"); + +require('./ui'); + +// set whitelist at startup. +prefChange.init(); +var widgetIsOn = false; + +// read storage file. +var cachedResult = librejsStorage.init(); +librejsStorage.generateCacheFromDB(); + +exports.main = function(options, callbacks) { + if (options.loadReason === 'enable' || + options.loadReason === 'install' + ) { + addonManage.onLoad(); + } +}; + +exports.onUnload = addonManage.onUnload; +exports.onLoad = addonManage.onLoad; + +var prefs = require('sdk/preferences/service'); +var isJavaScriptEnabled = prefs.get('javascript.enabled'); +if (!isJavaScriptEnabled) { + console.debug('JS disabled in add-on init'); + // remove all http notifications + httpObserver.removeHttpObserver(); + // TODO: the narcissus worker could also be stopped at this + // point, but I'm not doing that right now because I don't + // know how to re-enable it. + //narcissusWorker.stopWorker(); +} else { + console.debug('JS enabled in add-on init'); +} +prefObserver.register(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/parser/narcissus_worker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/parser/narcissus_worker.js @@ -0,0 +1,81 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var data = require("sdk/self").data; +var {Cu} = require("chrome"); +var {ChromeWorker} = Cu.import("resource://gre/modules/Services.jsm", null); +var worker = new ChromeWorker( + data.url("chrome_worker/parser/parse.js")); + +var NarcissusWorker = function() { + this.worker = worker; + var that = this; + + this.worker.onmessage = function(e) { + var jsChecker = require("../js_checker/js_checker"); + + console.debug('onmessage', e.data.hash); + try { + console.debug('calling jsChecker.callbackHashResult() for hash:', + e.data.hash); + jsChecker.callbackHashResult(e.data.hash, e.data.tree); + } catch (x) { + console.debug('error on message', x); + jsChecker.callbackHashResult(e.data.hash, false); + } + jsChecker = null; + }; + + // Enabling the catch clause in data/chrome_worker/parser + // instead of here because we can get the hash from there. + /*this.worker.onerror = function (e) { + console.debug( + 'error', e.lineno, + 'in', e.filename, + 'e', e.message, + 'full message', e + ); + // can't get hash from this context + that.worker.postMessage(JSON.stringify({'hash': null})); + };*/ +}; + +NarcissusWorker.prototype.stopWorker = function() { + console.debug('stopping worker'); + this.worker.postMessage('stop'); +}; + +NarcissusWorker.prototype.parse = function(scriptText, hash) { + console.debug('parsing', hash); + try { + this.worker.postMessage(JSON.stringify({ + 'code': scriptText, + 'hash': hash + })); + } catch (x) { + console.debug('error in lib/narcissus_worker.js', x, x.lineNumber); + } + +}; + +var narcissusWorker = new NarcissusWorker(); +exports.narcissusWorker = narcissusWorker; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/pref_observer/pref_observer.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/pref_observer/pref_observer.js @@ -0,0 +1,72 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var {Cc, Ci} = require("chrome"); +const httpObserver = require("../http_observer/http_request_observer"); + +// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Preferences#Using_preference_observers +var prefObserver = { + register: function() { + // First we'll need the preference services to look for preferences. + var prefService = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService); + + // For this.branch we ask for the preferences for + // extensions.myextension. and children + this.branch = prefService.getBranch("javascript."); + + // Finally add the observer. + this.branch.addObserver("", this, false); + }, + + unregister: function() { + this.branch.removeObserver("", this); + }, + + observe: function(aSubject, aTopic, aData) { + // aSubject is the nsIPrefBranch we're observing (after appropriate QI) + // aData is the name of the pref that's been changed (relative to + // aSubject) + switch (aData) { + case "enabled": + var prefs = require('sdk/preferences/service'); + var isJavaScriptEnabled = prefs.get('javascript.enabled'); + if (!isJavaScriptEnabled) { + console.debug('JS disabled in observer'); + // remove all http notifications + httpObserver.removeHttpObserver(); + + // TODO: the narcissus worker could also be stopped at this + // point, but I'm not doing that right now because I don't + // know how to re-enable it. + // narcissusWorker.stopWorker(); + } else { + console.debug('JS enabled in observer'); + httpObserver.startHttpObserver(); + } + break; + } + } +}; + +exports.register = function() { + prefObserver.register(); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/preferences/preferences.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/preferences/preferences.js @@ -0,0 +1,74 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +var data = require("sdk/self").data; +var panel = require("sdk/panel"); +var simpleStorage = require("sdk/simple-storage"); + +/* + *Create pref panel + */ +exports.prefpanel = panel.Panel({ + contentURL: data.url("preferences_panel/preferences_panel.html"), + contentScriptFile: data.url("preferences_panel/contentscript.js"), + contentScriptWhen: "ready", + widht:400, + height:400, + onMessage: function(message) { + handlePrefPanelMessage(message); + }, + onShow: function() { + getAllPrefPanelPrefs(); + } +}); + +var prefpanel = exports.prefpanel; + +function handlePrefPanelMessage(message) { + var prefSplit = message.split(":"); + if(prefSplit[0] == "SETPREF") { + simpleStorage.storage[prefSplit[1]] = prefSplit[2]; + } else { + console.debug(message); + } +} + +function getAllPrefPanelPrefs() { + var allprefnames = ['INCOMING PREFS', 'nolazy']; + + var allprefvalues = []; + + allprefvalues[0] = "INCOMINGPREFS"; + + for(var i = 1; i < allprefnames.length+1; i++) { + var pref = simpleStorage.storage[allprefnames[i]]; + + if(typeof(pref) == 'undefined') { + // If it doesn't exist yet, default to false and set it for the future + simpleStorage.storage[allprefnames[i]] = "false"; + pref = "false"; + } + + allprefvalues[i] = allprefnames[i] + ":" + pref; + } + + prefpanel.postMessage(allprefvalues); +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/accepted_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/accepted_scripts.js @@ -0,0 +1,69 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var allScripts = require('./all_scripts').allScripts; + +var AcceptedScripts = function() { + this.scripts = {}; + this.truncateJsData = allScripts.truncateJsData; + this.getScripts = allScripts.getScripts; + this.isFound = allScripts.isFound; + this.returnWhenFound = allScripts.returnWhenFound; + this.getOrInitScripts = allScripts.getOrInitScripts; + this.setHash = allScripts.setHash; +}; + +AcceptedScripts.prototype.clearScripts = function (url) { + this.scripts[url] = []; +}; + +/** + * addAScript + * adds a single script to the scripts array. + * @param {string} url - the url of the page where it is loaded. + * @param {object} scriptObj - Additional data regarding this script, + * including: inline: boolean, + * contents: string, + * removalReason: string. + */ +AcceptedScripts.prototype.addAScript = function (url, scriptObj) { + var exists; + + if (this.scripts[url] === undefined) { + this.clearScripts(url); + } + + // check if content is actually js code. + if (scriptObj.inline === true) { + this.setHash(scriptObj); + this.truncateJsData(scriptObj); + } + exists = this.isFound(url, scriptObj); + if (!exists) { + this.scripts[url].push(scriptObj); + return true; + } else { + return false; + } +}; + +exports.acceptedScripts = new AcceptedScripts(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/all_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/all_scripts.js @@ -0,0 +1,110 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var crypto = require('./crypto'); + +var AllScripts = function() { + this.scripts = {}; +}; + +AllScripts.prototype.truncateJsData = function (scriptObj) { + if (scriptObj.contents === undefined) { + console.debug('this is an inline script', scriptObj.value); + console.debug('this is an src', scriptObj.url); + } + if (scriptObj.contents.length > 1000) { + scriptObj.contents = scriptObj.contents.substring(0, 1000); + scriptObj.contents += '…'; + } +}; + +AllScripts.prototype.setHash = function (scriptObj) { + scriptObj.hash = crypto.sha1Encrypt(scriptObj.contents); + return scriptObj.hash; +}; + +AllScripts.prototype.getScripts = function (url) { + if (!this.scripts[url]) { + return false; + } else { + return this.scripts[url]; + } +}; + +AllScripts.prototype.reverseArray = function (url) { + this.scripts[url].reverse(); +}; + +AllScripts.prototype.getOrInitScripts = function (url) { + if (this.scripts[url] === undefined) { + this.scripts[url] = []; + } + return this.scripts[url]; +}; + +AllScripts.prototype.returnWhenFound = function(url, data) { + var pageScripts = this.getOrInitScripts(url), + i = 0, + le = pageScripts.length; + + // check that entry doesn't exist. + if (data.inline === false) { + for (; i < le; i++) { + if (pageScripts[i].contents === data.url) { + return pageScripts[i]; + } + } + } else if (data.inline === true) { + for (; i < le; i++) { + if (pageScripts[i].hash === crypto.sha1Encrypt(data.contents)) { + return pageScripts[i]; + } + } + } + + return false; +}; + +AllScripts.prototype.isFound = function(url, data) { + var pageScripts = this.getOrInitScripts(url), + i = 0, + le = pageScripts.length; + + // check that entry doesn't exist. + if (data.inline === false) { + for (; i < le; i++) { + if (pageScripts[i].url === data.url) { + return true; + } + } + } else if (data.inline === true) { + for (; i < le; i++) { + if (pageScripts[i].hash === crypto.sha1Encrypt(data.contents)) { + return true; + } + } + } + + return false; +}; + +exports.allScripts = new AllScripts(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/crypto.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/crypto.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/dryrun_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/dryrun_scripts.js @@ -0,0 +1,78 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var allScripts = require('./all_scripts').allScripts; +const urlHandler = require('../url_handler/url_handler'); + +exports.dryRunScripts = { + scripts: {}, + + truncateJsData: allScripts.truncateJsData, + + getScripts: allScripts.getScripts, + + isFound: allScripts.isFound, + + returnWhenFound: allScripts.returnWhenFound, + + getOrInitScripts: allScripts.getOrInitScripts, + + reverseArray: allScripts.reverseArray, + + setHash: allScripts.setHash, + + clearScripts: function (url) { + this.scripts[url] = []; + }, + + /** + * addAScript + * adds a single script to the scripts array. + * @param {string} url - the url of the page where it is loaded. + * @param {object} scriptObj - Additional data regarding this script, + * including: inline: boolean, + * contents: string, + * removalReason: string. + */ + addAScript: function (url, scriptObj, absoluteUrl) { + var exists; + + if (this.scripts[url] === undefined) { + this.clearScripts(url); + } + if (scriptObj.inline === true) { + this.setHash(scriptObj); + this.truncateJsData(scriptObj); + } else if (absoluteUrl !== undefined && + scriptObj.inline === false) { + scriptObj.contents = urlHandler.resolve(absoluteUrl, scriptObj.contents); + } + exists = this.isFound(url, scriptObj); + + if (!exists) { + this.scripts[url].push(scriptObj); + return true; + } else { + return false; + } + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/free_libraries.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/free_libraries.js @@ -0,0 +1,69 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +// THIS MODULE IS DEPRECATED IN FAVOR OF THE NEW WHITELISTING MODULE (LibreJS 6.0) + +var relationChecker = require("../js_checker/relation_checker") + .relationChecker; +var checkTypes = require("../js_checker/constant_types").checkTypes; +var scriptsCached = require("./scripts_cache").scriptsCached; + + +// find the json database path. +var dbContents = require("sdk/self").data.load( + "script_libraries/script-libraries.json"); + +const AUTHOR_REASON = "This script has been tagged as free software by LibreJS authors."; + +var freeLibraries = JSON.parse(dbContents); /* a database of the free libraries recognized by default */ + +/* + * List of free libraries and their SHA256 hash. + * This is used to recognize the most common free libraries. + */ + +var init = function () { + + // relationChecker, which roughly checks if variables are window + // variables or not, is useless in this case. Use the same + // object for all entries. + var rc = relationChecker(); + var library, hash; + var freeObj = { "type": 4, "reason": AUTHOR_REASON}; + console.debug("Building init"); + for (hash in freeLibraries) { + library = freeLibraries[hash]; + + // assign empty relationChecker object. + library.relationChecker = rc; + + // make them free and nontrivial. + library.result = freeObj; + + scriptsCached.addObjectEntry(hash, library); + } +}; + +//init(); + +exports.init = init; +exports.AUTHOR_REASON = AUTHOR_REASON; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/removed_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/removed_scripts.js @@ -0,0 +1,73 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var allScripts = require('./all_scripts').allScripts; +const urlHandler = require('../url_handler/url_handler'); + +var RemovedScripts = function() { + this.scripts = {}; + this.truncateJsData = allScripts.truncateJsData; + this.getScripts = allScripts.getScripts; + this.isFound = allScripts.isFound; + this.returnWhenFound = allScripts.returnWhenFound; + this.getOrInitScripts = allScripts.getOrInitScripts; + this.reverseArray = allScripts.reverseArray; + this.setHash = allScripts.setHash; +}; + +RemovedScripts.prototype.clearScripts = function (url) { + this.scripts[url] = []; +}; + +/** + * addAScript + * adds a single script to the scripts array. + * @param {string} url - the url of the page where it is loaded. + * @param {object} scriptObj - Additional data regarding this script, + * including: inline: boolean, + * contents: string, + * removalReason: string. + */ +RemovedScripts.prototype.addAScript = function (url, scriptObj, absoluteUrl) { + var exists; + + if (this.scripts[url] === undefined) { + this.clearScripts(url); + } + if (scriptObj.inline === true) { + this.setHash(scriptObj); + this.truncateJsData(scriptObj); + } else if (absoluteUrl !== undefined && + scriptObj.inline === false) { + scriptObj.contents = urlHandler.resolve(absoluteUrl, scriptObj.contents); + } + exists = this.isFound(url, scriptObj); + + if (!exists) { + this.scripts[url].push(scriptObj); + return true; + } else { + return false; + } +}; + +exports.removedScripts = new RemovedScripts(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/scripts_cache.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/script_entries/scripts_cache.js @@ -0,0 +1,193 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +var relationCheckerObj = require("../js_checker/relation_checker") + .relationChecker; + +// import free_libraries to populate the cache hash map. +var free_libraries = require("../script_entries/free_libraries"); + +var crypto = require('./crypto'); +const checkTypes = require("../js_checker/constant_types").checkTypes; + +// cachedResults contains objects with result/relationChecker for +// scripts entries indexed by SHA1sum +var cachedResults = {}; + +/** + * ScriptsCached keeps a cache of whitelisted scripts in the browser + * session. + */ +var ScriptsCached = function() { +}; + +ScriptsCached.prototype.getHash = function(scriptText) { + require('../ui/notification').createNotification( + scriptText.substring(0,100)); + + return crypto.sha1Encrypt(scriptText); +}; + +/** + * resetCache + * Resets the full cache and re-initialize + * the free libraries list. + */ +ScriptsCached.prototype.resetCache = function () { + cachedResults = {}; + free_libraries.init(); +}; + +/** + * + * addEntry + * + * Adds a script entry to the cache by providing the results + * and the actual script text. + * + */ +ScriptsCached.prototype.addEntry = function( + scriptText, result, relationChecker, allowTrivial, url) { + console.debug("result addEntry is", JSON.stringify(result)); + cachedResults[this.getHash(scriptText)] = { + 'result': result, + 'relationChecker': relationCheckerObj(), + 'allowTrivial': allowTrivial, + 'url': url + }; +}; + +/** + * + * addEntry + * + * Adds a script entry to the cache by providing the results + * using the script's hash. + * + */ +ScriptsCached.prototype.addEntryByHash = function( + hash, result, relationChecker, allowTrivial, url) { + cachedResults[hash] = { + 'result': result, + 'relationChecker': relationCheckerObj(), + 'allowTrivial': allowTrivial, + 'url': url || '' + }; +}; + +/** + * removeEntryByHash + * + * Remove an entry from the cache using hash key. + */ +ScriptsCached.prototype.removeEntryByHash = function(hash) { + delete cachedResults[hash]; +}; + +/** + * addEntryIfNotCached + * + * Checks first if entry is cached before attempting to cache result. + */ +ScriptsCached.prototype.addEntryIfNotCached = function( + scriptText, result, relationChecker, allowTrivial, url) { + // save a bit of computing by getting hash once. + var hash = this.getHash(scriptText); + console.debug('hash is then', hash); + if (!this.isCached(scriptText, hash)) { + cachedResults[hash] = { + 'result': result, + 'relationChecker': relationCheckerObj(), + 'allowTrivial': allowTrivial, + 'url': url || '' + }; + } + return hash; +}; + +/** + * + * addObjectEntry + * + * Adds a script entry by providing an object. + * Used to provide free library hashes from free_libraries.js + * + */ +ScriptsCached.prototype.addObjectEntry = function(hash, script) { + cachedResults[hash] = script; +}; + +ScriptsCached.prototype.isCached = function(scriptText, hash) { + var scriptHash; + console.debug("Is CACHED start?"); + try { + if (typeof hash === 'string') { + scriptHash = hash; + } else { + scriptHash = this.getHash(scriptText); + } + if (typeof scriptHash === 'string') { + let cachedResult = cachedResults[scriptHash]; + if (cachedResult) { + // exact copy of file has already been cached. + console.debug('scriptHash is', cachedResult); + if (cachedResult.relationChecker == "[rl]") { + cachedResult.relationChecker = {}; //relationCheckerObj(); + } + console.debug("Is Cached ENd TRUE"); + return cachedResult; + } + } + return false; + } catch (e) { + console.debug("an error", scriptHash, e, e.linenumber, e.filename); + } +}; + +/** + * Writes allowed scripts to the cache. + * nonfree/nontrivial scripts are not added to the cache. + */ +ScriptsCached.prototype.getCacheForWriting = function() { + var formattedResults = {}; + for (let item in cachedResults) { + let type = cachedResults[item].result.type; + if (type != checkTypes.NONTRIVIAL && + type != checkTypes.TRIVIAL_DEFINES_FUNCTION + ) { + formattedResults[item] = cachedResults[item]; + } + } + return formattedResults; +}; + +/** + * Import data from database into cachedResults. + * Calling this function replaces the current cache if it exists. + */ +ScriptsCached.prototype.bulkImportCache = function(data) { + cachedResults = data; + console.debug("Imported data. Number of keys ISSS ", + Object.keys(cachedResults).length); + console.debug("It looks like ", JSON.stringify(cachedResults)); +}; + +exports.scriptsCached = new ScriptsCached(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/settings/settings.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/settings/settings.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/settings/settings_tab.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/settings/settings_tab.js @@ -0,0 +1,79 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +const tabs = require("sdk/tabs"); +const data = require("sdk/self").data; +const storage = require("./storage").librejsStorage; +const scriptsCached = require("../script_entries/scripts_cache") + .scriptsCached; + +let settingsManager = { + settingsTab: { + url: data.url("settings/index.html"), + onReady: function (tab) { + console.debug("populating form"); + var that = this; + let cache_data = scriptsCached.getCacheForWriting(); + let worker = tab.attach({ + contentScriptFile: [ + data.url('settings/js/pagescript-listener.js'), + data.url('settings/js/pagescript-emitter.js') + ] + }); + worker.port.emit("populate-form", cache_data); + worker.port.on("rules-form-delete", function (hash) { + try { + scriptsCached.removeEntryByHash(hash); + } catch (e) { + console.log('caught!', e, e.lineNumber, e.filename); + } + //worker.port.emit("populate-form", scriptsCached.getCacheForWriting()); + }); + worker.port.on("rules-form-delete-all", function () { + scriptsCached.resetCache(); + }); + }, + onActivate: function (tab) { + // just reload the form. + console.debug("Tab is activated again"); + var that = this; + let cache_data = scriptsCached.getCacheForWriting(); + let worker = tab.attach({ + contentScriptFile: [ + data.url('settings/js/pagescript-listener.js'), + data.url('settings/js/pagescript-emitter.js') + ] + }); + worker.port.emit("populate-form", cache_data); + } + }, + + init: function () { + settings.onLoad(function (data) {}); + }, + + open: function () { + console.debug("settings tab data url is", this.settingsTab.url); + tabs.open(this.settingsTab); + } +}; + +exports.settingsManager = settingsManager; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/settings/storage.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/settings/storage.js @@ -0,0 +1,181 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ +/*jshint esnext: true */ + +const { Cc, Ci, Cu, components } = require("chrome"); + +const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm"); +const { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm"); +var relationChecker = require("../js_checker/relation_checker") + .relationChecker; +var rc = relationChecker(); // a dummy object for legacy module. +const AUTHOR_REASON = require("../script_entries/free_libraries") + .AUTHOR_REASON; +var relationChecker = require("../js_checker/relation_checker") + .relationChecker; + +const scriptsCached = require("../script_entries/scripts_cache") + .scriptsCached; + +let librejsStorage = { + + file: null, + filename: 'librejs-whitelist.json', + data: [], + + onLoad: function (callback) { + // will read the json file. + this.init(); + this.read(callback); + }, + + init: function () { + // get the "librejs-whitelist.json" file in the profile directory + this.file = FileUtils.getFile("ProfD", [this.filename]); + }, + + read: function (callback) { + // Content type hint is useful on mobile platforms where the filesystem + // would otherwise try to determine the content type. + var channel = NetUtil.newChannel(this.file); + var that = this; + channel.contentType = "application/json"; + try { + NetUtil.asyncFetch(channel, function(inputStream, status) { + + if (!components.isSuccessCode(status)) { + require("../script_entries/free_libraries").init(); + that.initialWrite(); + } + + var raw_data = NetUtil.readInputStreamToString( + inputStream, inputStream.available()); + // expand json file back to original contents. + var re = new RegExp( + "[freelib]".replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), + 'g' + ); + raw_data = raw_data.replace(re, AUTHOR_REASON); + //console.debug("raw_data is ", raw_data); + // The file data is contained within inputStream. + // You can read it into a string with + // get string into json also + that.data = JSON.parse(raw_data); + + callback(that.data); + }); + } catch (e) { + that.initialWrite(); + } + }, + + initialWrite: function (callback) { + console.debug("About to write free libraries"); + // our file is not populated with default contents. + // use free_libraries.js to populate. + require("../script_entries/free_libraries").init(); + this.writeCacheToDB(callback); + }, + + /** + * writes the contents of scriptsCached to the persistent + * JSON file. + */ + writeCacheToDB: function (callback) { + console.debug("writing to db"); + data = scriptsCached.getCacheForWriting(); + json = JSON.stringify(data); + + // make json file smaller. + var re = new RegExp( + AUTHOR_REASON.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'); + json = json.replace(re, "[freelib]"); + + var rc = JSON.stringify(relationChecker()); + re = new RegExp(rc.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'); + json = json.replace(re, "\"[rl]\""); + //console.debug("this.data is now", this.data); + this.write(callback, json); + }, + generateCacheFromDB: function (callback) { + if (typeof callback === 'undefined') { + callback = function () { + // nothing to do. + }; + } + this.read(function (data) { + scriptsCached.bulkImportCache(data); + }); + }, + write: function (onDataWritten, json) { + + this.init(); + var str; + if (typeof json === 'undefined') { + str = JSON.stringify(this.data); + } else { + // we are passing json already formatted. + str = json; + } + var ostream = FileUtils.openSafeFileOutputStream(this.file); + var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + var istream = converter.convertToInputStream(str); + // The last argument (the callback) is optional. + NetUtil.asyncCopy(istream, ostream, function(status) { + if (!components.isSuccessCode(status)) { + // Handle error! + return; + } + if (!onDataWritten) { + console.debug("onDataWritten is not defined"); + onDataWritten = function () { + console.debug("onDataWritten dummy callback triggered"); + }; + } + // Data has been written to the file. + onDataWritten(); + }); + }, + + /** + * getEntry -- Returns a storage entry if it is present. + */ + getEntry: function (hash) { + var entry = this.data[hash]; + if (entry) { + if (entry.result === '[freelib]') { + entry.result = { + 'type': 4, + 'reason': 'This script has been tagged as free ' + + 'software by LibreJS authors.' + }; + } + entry.relationChecker = rc; + return entry; + } + return false; + } +}; + +exports.librejsStorage = librejsStorage; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui.js @@ -0,0 +1,190 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +let data = require("sdk/self").data; +let panel = require('sdk/panel'); +let tabs = require("sdk/tabs"); +let {getMostRecentBrowserWindow} = require('sdk/window/utils'); +let {ToggleButton} = require('sdk/ui/button/toggle'); + +let settings_tab = require('./settings/settings_tab'); +let allowedRef = require("./http_observer/allowed_referrers") + .allowedReferrers; +let urlHandler = require("./url_handler/url_handler"); +let removedScripts = require("./script_entries/removed_scripts") + .removedScripts; +let acceptedScripts = require("./script_entries/accepted_scripts") + .acceptedScripts; +let jsLabelsPagesVisited = require('./html_script_finder/web_labels/js_web_labels') + .jsLabelsPagesVisited; +let dryRunScripts = require("./script_entries/dryrun_scripts").dryRunScripts; +let types = require("./js_checker/constant_types"); +const removeHashCallback = require("./js_checker/js_checker").removeHashCallback; + +// move to sub-module later +const scriptsCached = require("./script_entries/scripts_cache").scriptsCached; + +function generateDataURI (encodedText) { + return "data:text/html;charset=UTF-8;base64," + encodedText; +} + +/** + * UI + * + * A singleton that starts the user interface content scripts. + */ +let UI = exports.UI = { + init: function() { + var mainPanel = panel.Panel({ + contentURL: data.url('display_panel/content/display-panel.html'), + width: 800, + height: 500, + contentScriptFile: [ + data.url('settings/third-party/jquery/jquery.min.js'), + data.url('display_panel/main_panel.js') + ], + onShow: this.showPanelContent, + onHide: function() { + toggleButton.state('window', { checked: false }); + } + }); + + mainPanel.port.on('hideMainPanel', function () { + mainPanel.hide(); + }); + + mainPanel.port.on('allowAllClicked', function (url) { + url = urlHandler.removeFragment(url); + allowedRef.addPage(url); + tabs.activeTab.reload(); + }); + + mainPanel.port.on('disallowAllClicked', function (url) { + console.debug('url is', url); + url = urlHandler.removeFragment(url); + console.debug('before clear, url is in allowedRef', + allowedRef.urlInAllowedReferrers(url)); + allowedRef.clearSinglePageEntry(url); + console.debug('after clear, url is in allowedRef', + allowedRef.urlInAllowedReferrers(url)); + mainPanel.hide(); + tabs.activeTab.reload(); + }); + + mainPanel.port.on('openInTab', function (text) { + var str = generateDataURI(text); + tabs.open(str); + mainPanel.hide(); + }); + + mainPanel.port.on('whitelistByHash', function( + hash, url, name, reason + ) { + console.debug("hash is", hash); + url = urlHandler.removeFragment(url); + /* var cached_result = scriptsCached.isCached(hash); + if (cached_results) { + reason = cached_result['reason']; + }*/ + scriptsCached.addEntryByHash( + hash, types.whitelisted(reason), {}, true, url); + }); + + mainPanel.port.on('removeFromWhitelistByHash', function (hash) { + scriptsCached.removeEntryByHash(hash); + removeHashCallback(hash); + }); + + mainPanel.port.on('openSesame', function () { + // open the settings tab. + settings_tab.settingsManager.open(); + mainPanel.hide(); + }); + + var toggleButton = ToggleButton({ + id: 'librejs-toggle-switch', + label: 'LibreJS', + icon: { + '16': './widget/images/librejs.png', + '32': './widget/images/librejs-32.png', + '64': './widget/images/librejs-64.png' + }, + panel: mainPanel, + onChange: function(state) { + if (state.checked) { + mainPanel.show({ + position: toggleButton + }); + } + } + }); + + var menuitem = require("menuitem").Menuitem({ + id: 'librejs_settings', + menuid: 'menu_ToolsPopup', + label: 'LibreJS Whitelist', + onCommand: function() { + settings_tab.settingsManager.open(); + }, + insertBefore: "menu_pageInfo" + }); + }, + + showPanelContent: function() { + let that = this; + var message, externalEntries, + externalScripts, urlTabIndex, tabData; + + var worker = tabs.activeTab.attach({ + contentScriptFile: [ + data.url('complain/contact_regex.js'), + data.url('complain/link_types.js'), + data.url('settings/third-party/jquery/jquery.min.js'), + data.url('complain/contact_finder.js'), + data.url('complain/pagemod_finder.js'), + data.url('script_detector/script_detector.js') + ], + contentScriptWhen: 'ready', + onMessage: function(respData) { + var url = urlHandler.removeFragment(tabs.activeTab.url); + + if (respData.event === 'scriptsFetched') { + var scriptsData = { + 'jsLabelsPagesVisited': jsLabelsPagesVisited, + 'removed': removedScripts.getScripts(url), + 'accepted': acceptedScripts.getScripts(url), + 'dryRun': dryRunScripts.getScripts(url) + }; + that.postMessage({ + 'pageURL': url, + 'urlData': scriptsData, + 'isAllowed': allowedRef.urlInAllowedReferrers(url) + }); + worker.port.emit('pageUrl', url); + } else { + that.postMessage(respData); + } + } + }); + } +}; + +UI.init(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui/notification.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui/notification.js @@ -0,0 +1,78 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +// this module is used to display a notification when LibreJS +// is running to inform the user it is indeed busy working. +const timer = require("sdk/timers"); +const self = require("sdk/self"); +const isDisplayNotifications = require("../addon_management/prefchange") + .isDisplayNotifications; + +exports.createCriticalNotification = function (text) { + if (text === undefined) { + text = ""; + } + var self = require('sdk/self'); + var notif = require("notification-box").NotificationBox({ + 'value': 'librejs-critical-notification-js-web-labels', + 'label': text, + 'priority': 'CRITICAL_LOW', + 'image': self.data.url("assets/images/torchy2.png"), + }); + return notif; +}; + +var fakeNotification = { + 'close': function () { + return; + } +}; + +exports.createNotification = function (jsValue) { + if (!isDisplayNotifications()) { + return fakeNotification; + } + if (jsValue === undefined) { + jsValue = ""; + } + var self = require('sdk/self'); + var notif = require("notification-box").NotificationBox({ + 'value': 'librejs-message', + 'label': 'LibreJS is analyzing: ' + jsValue + " ...", + 'priority': 'INFO_LOW', + 'image': self.data.url("assets/images/torchy2.png"), + /*'buttons': [{'label': "Fine", + 'onClick': function () { }}]*/ + }); + timer.setTimeout(function () { + // ensure notifications are ALWAYS removed at some point. + console.debug("removing after 2 seconds"); + try { + var n = notif.notificationbox + .getNotificationWithValue('librejs-message'); + n.close(); + } catch(x) { + // do nothing + } + }, 2000); + return notif; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui/script_panel.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui/script_panel.js @@ -0,0 +1,75 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +var urlHandler = require("../url_handler/url_handler"); + +/** + * addScriptsToPanelList + * + * Looks for scripts that are either valid or flagged with libreJS + * + */ +exports.addScriptsToPanelList = function (url, respData) { + + var panelRemovedScripts = []; + var panelAcceptedScripts = []; + var panelDryRunScripts = []; + + // use url. remove fragment. + url = urlHandler.removeFragment(url); + var contents, i, reason; + + for (i = 0; i < respData.value.blocked.length; i++) { + // if external script only. + pathToUrl(respData.value.blocked[i], url); + panelRemovedScripts.push(respData.value.blocked[i]); + } + + for (i = 0; i < respData.value.accepted.length; i++) { + + // if external script only. + pathToUrl(respData.value.accepted[i], url); + panelAcceptedScripts.push(respData.value.accepted[i]); + } + for (i = 0; i < respData.value.dryRun.length; i++) { + // if external script only. + pathToUrl(respData.value.dryRun[i], url); + panelDryRunScripts.push(respData.value.dryRun[i]); + } + + return {'removed': panelRemovedScripts, + 'accepted': panelAcceptedScripts, + 'dryRun': panelDryRunScripts}; +}; + + +/** + * pathToUrl + * + * convert a relative path to a url. + * + */ +var pathToUrl = function (scriptEntry, url) { + if (scriptEntry.inline === false) { + scriptEntry.url = urlHandler.resolve(url, scriptEntry.url); + } +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui/ui_info.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/ui/ui_info.js @@ -0,0 +1,205 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +// page mod executing content script at every page load. + +var data = require("sdk/self").data; +var pageMod = require("sdk/page-mod"); +var urlHandler = require("../url_handler/url_handler"); +var pageWorker = require("sdk/page-worker"); +var tabs = require("sdk/tabs"); +var prefs = require("../addon_management/prefchange"); + +// contain list of recently found contact links or email addresses. +var contactList = {}; + +// constants. Also available in lib/ui_info.js +const CERTAIN_EMAIL_ADDRESS_FOUND = 'certainEmailAddressFound'; +const UNCERTAIN_EMAIL_ADDRESS_FOUND = 'uncertainEmailAddresFound'; + +// Looking for contact links +const CERTAIN_LINK_FOUND = 'certainLinkFound'; +const PROBABLE_LINK_FOUND = 'probableLinkFound'; +const UNCERTAIN_LINK_FOUND = 'uncertainLinkFound'; +const LINK_NOT_FOUND = 'contactLinkNotFound'; + +// Looking for identi.ca and twitter accounts. +const TWITTER_LINK_FOUND = 'twitterLinkFound'; +const IDENTICA_LINK_FOUND = 'identicaLinkFound'; + +// phone number and address +const PHONE_NUMBER_FOUND = 'phoneNumberFound'; +const SNAIL_ADDRESS_FOUND = 'snailAddressFound'; + +/** + * main pageMod. + * Find blocked script in all pages being opened. + * Launch the scripts that search for a complaint contact. + * + */ + +pageMod.PageMod({ + include: ['file://*', '*', 'data:*', 'about:*'], + contentScriptWhen: 'end', + + contentScriptFile: [ + data.url('complain/contact_regex.js'), + data.url('complain/link_types.js'), + data.url('settings/third-party/jquery/jquery.min.js'), + data.url('complain/contact_finder.js'), + data.url('complain/pagemod_finder.js'), + data.url('script_detector/script_detector.js') + ], + + onAttach: function onAttach(worker) { + if (worker.tab !== undefined && prefs.isComplaintTab()) { + // this is a tab. + if (!foundInContactList(worker.url)) { + // the hostname doesn't appear in the object literal. + // run script fetching/complaint feature if applicable. + tabProcess(worker); + } else { + worker.postMessage(foundInContactList(worker.url)); + } + } + } +}); + +/** + * foundInContactList + * + * Provides link if contact link is found for given url, or else + * false. + */ +var foundInContactList = function (url) { + var hostname = urlHandler.getHostname(url); + if (contactList[hostname] !== undefined) { + return contactList[hostname]; + } else { + return false; + } +}; + +/** + * tabProcess + * Find blocked/accepted scripts, prepare + * display panel and complaint panel. + */ +var tabProcess = function (worker) { + var visitedUrl = {}; + + // webmaster email is better than a webpage. + worker.emailFound = false; + var modUrl = '', + searchUrl = ''; + + modUrl = worker.url; + console.debug('pagemod triggered'); + + worker.port.emit('prefs', { + complaintEmailSubject: prefs.complaintEmailSubject(), + complaintEmailBody: prefs.complaintEmailBody() + }); + + // send local path to complain button graphic. + worker.port.emit('assetsUri', + {'event': 'assets-uri', + 'value': data.url('assets/')}); + worker.port.emit('pageUrl', + {'event': 'page-url', + 'value': modUrl}); + + worker.on('message', function (respData) { + console.debug('worker is receiving a message', respData.event); + var pw; + + worker.on('detach', function () { + console.debug('detaching worker'); + if (pw) { + pw.destroy(); + } + }); + if (respData.contact !== undefined) { + // pass the message to the complaint display panel. + worker.port.emit('complaintLinkFound', respData); + } else if (respData.event === 'complaintSearch') { + if (worker.tab) { + console.debug('worker tab url', worker.tab.url); + } + if (!(respData.urlSearch.linkValue in visitedUrl)) { + visitedUrl[respData.urlSearch.linkValue] = 1; + respData.urlSearch.linkValue = urlHandler.addFragment( + respData.urlSearch.linkValue, 'librejs=true'); + pw = searchSecondLevelPage( + this, respData.urlSearch.linkValue, this.url); + } + // currently not needed. + /*else { + console.debug(respData.urlSearch.linkValue, 'already visited'); + }*/ + } + }); +}; + +var searchSecondLevelPage = function( + worker, urlToSearch, originalUrl) { +/* + var originalWorker = worker; + + console.debug('searchSecondLevelPage'); + console.debug(urlToSearch, 'and', originalUrl); + + if (urlHandler.haveSameHostname(urlToSearch, originalUrl)) { + return pageWorker.Page({ + contentURL: urlToSearch, + contentScriptFile: [ + data.url('complain/contact_regex.js'), + data.url('complain/link_types.js'), + data.url('settings/third-party/jquery/jquery.min.js'), + data.url('complain/contact_finder.js'), + data.url('complain/worker_finder.js') + ], + contentScriptWhen: "end", + onMessage: function (respData) { + console.debug(JSON.stringify(respData)); + console.debug(originalWorker.url); + originalWorker.postMessage(respData); + + if (respData.event === 'destroy') { + try { + console.debug('destroying worker', this.contentURL); + this.destroy(); + } catch (e) { + console.debug('in worker', e); + } + } + } + }); + } +*/ +}; + +exports.testModule = { + 'contactList': contactList, + 'foundInContactList': foundInContactList, + 'tabProcess': tabProcess +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_punycode.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/url_handler/node_punycode.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_querystring.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/url_handler/node_querystring.js diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/url_handler/node_url.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/url_handler/node_url.js @@ -0,0 +1,691 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var punycode = require('./node_punycode'); + +exports.parse = urlParse; +exports.resolve = urlResolve; +exports.resolveObject = urlResolveObject; +exports.format = urlFormat; + +exports.Url = Url; + +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; +} + +// Reference: RFC 3986, RFC 1808, RFC 2396 + +// define these here so at least they only have to be +// compiled once on the first module load. +var protocolPattern = /^([a-z0-9.+-]+:)/i, + portPattern = /:[0-9]*$/, + + // RFC 2396: characters reserved for delimiting URLs. + // We actually just auto-escape these. + delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], + + // RFC 2396: characters not allowed for various reasons. + unwise = ['{', '}', '|', '\\', '^', '~', '`'].concat(delims), + + // Allowed by RFCs, but cause of XSS attacks. Always escape these. + autoEscape = ['\''].concat(delims), + // Characters that are never ever allowed in a hostname. + // Note that any invalid chars are also handled, but these + // are the ones that are *expected* to be seen, so we fast-path + // them. + nonHostChars = ['%', '/', '?', ';', '#'] + .concat(unwise).concat(autoEscape), + hostEndingChars = ['/', '?', '#'], + hostnameMaxLen = 255, + hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/, + hostnamePartStart = /^([a-z0-9A-Z_-]{0,63})(.*)$/, + // protocols that can allow "unsafe" and "unwise" chars. + unsafeProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that never have a hostname. + hostlessProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that always contain a // bit. + slashedProtocol = { + 'http': true, + 'https': true, + 'ftp': true, + 'gopher': true, + 'file': true, + 'http:': true, + 'https:': true, + 'ftp:': true, + 'gopher:': true, + 'file:': true + }, + querystring = require('./node_querystring'); + +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url && typeof(url) === 'object' && url instanceof Url) return url; + + var u = new Url; + u.parse(url, parseQueryString, slashesDenoteHost); + return u; +} + +Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { + if (typeof url !== 'string') { + throw new TypeError("Parameter 'url' must be a string, not " + typeof url); + } + + // Copy chrome, IE, opera backslash-handling behavior. + // See: https://code.google.com/p/chromium/issues/detail?id=25916 + var hashSplit = url.split('#'); + hashSplit[0] = hashSplit[0].replace(/\\/g, '/'); + url = hashSplit.join('#'); + + var rest = url; + + // trim before proceeding. + // This is to support parse stuff like " http://foo.com \n" + rest = rest.trim(); + + var proto = protocolPattern.exec(rest); + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.substr(proto.length); + } + + // figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { + var slashes = rest.substr(0, 2) === '//'; + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.substr(2); + this.slashes = true; + } + } + + if (!hostlessProtocol[proto] && + (slashes || (proto && !slashedProtocol[proto]))) { + + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:c path:/?@c + + // v0.12 TODO(isaacs): This is not quite how Chrome does things. + // Review our test case against browsers more comprehensively. + + // find the first instance of any hostEndingChars + var hostEnd = -1; + for (var i = 0; i < hostEndingChars.length; i++) { + var hec = rest.indexOf(hostEndingChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + + // at this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + var auth, atSign; + if (hostEnd === -1) { + // atSign can be anywhere. + atSign = rest.lastIndexOf('@'); + } else { + // atSign must be in auth portion. + // http://a@b/c@d => host:b auth:a path:/c@d + atSign = rest.lastIndexOf('@', hostEnd); + } + + // Now we have a portion which is definitely the auth. + // Pull that off. + if (atSign !== -1) { + auth = rest.slice(0, atSign); + rest = rest.slice(atSign + 1); + this.auth = decodeURIComponent(auth); + } + + // the host is the remaining to the left of the first non-host char + hostEnd = -1; + for (var i = 0; i < nonHostChars.length; i++) { + var hec = rest.indexOf(nonHostChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + // if we still have not hit it, then the entire thing is a host. + if (hostEnd === -1) + hostEnd = rest.length; + + this.host = rest.slice(0, hostEnd); + rest = rest.slice(hostEnd); + + // pull out port. + this.parseHost(); + + // we've indicated that there is a hostname, + // so even if it's empty, it has to be present. + this.hostname = this.hostname || ''; + + // if hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + var ipv6Hostname = this.hostname[0] === '[' && + this.hostname[this.hostname.length - 1] === ']'; + + // validate a little. + if (!ipv6Hostname) { + var hostparts = this.hostname.split(/\./); + for (var i = 0, l = hostparts.length; i < l; i++) { + var part = hostparts[i]; + if (!part) continue; + if (!part.match(hostnamePartPattern)) { + var newpart = ''; + for (var j = 0, k = part.length; j < k; j++) { + if (part.charCodeAt(j) > 127) { + // we replace non-ASCII char with a temporary placeholder + // we need this to make sure size of hostname is not + // broken by replacing non-ASCII by nothing + newpart += 'x'; + } else { + newpart += part[j]; + } + } + // we test again with ASCII char only + if (!newpart.match(hostnamePartPattern)) { + var validParts = hostparts.slice(0, i); + var notHost = hostparts.slice(i + 1); + var bit = part.match(hostnamePartStart); + if (bit) { + validParts.push(bit[1]); + notHost.unshift(bit[2]); + } + if (notHost.length) { + rest = '/' + notHost.join('.') + rest; + } + this.hostname = validParts.join('.'); + break; + } + } + } + } + + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); + } + + if (!ipv6Hostname) { + // IDNA Support: Returns a punycoded representation of "domain". + // It only converts parts of the domain name that + // have non-ASCII characters, i.e. it doesn't matter if + // you call it with a domain that already is ASCII-only. + this.hostname = punycode.toASCII(this.hostname); + } + + var p = this.port ? ':' + this.port : ''; + var h = this.hostname || ''; + this.host = h + p; + this.href += this.host; + + // strip [ and ] from the hostname + // the host field still retains them, though + if (ipv6Hostname) { + this.hostname = this.hostname.substr(1, this.hostname.length - 2); + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } + + // now rest is set to the post-host stuff. + // chop off any delim chars. + if (!unsafeProtocol[lowerProto]) { + + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + for (var i = 0, l = autoEscape.length; i < l; i++) { + var ae = autoEscape[i]; + var esc = encodeURIComponent(ae); + if (esc === ae) { + esc = escape(ae); + } + rest = rest.split(ae).join(esc); + } + } + + + // chop off from the tail first. + var hash = rest.indexOf('#'); + if (hash !== -1) { + // got a fragment string. + this.hash = rest.substr(hash); + rest = rest.slice(0, hash); + } + var qm = rest.indexOf('?'); + if (qm !== -1) { + this.search = rest.substr(qm); + this.query = rest.substr(qm + 1); + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + rest = rest.slice(0, qm); + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + this.search = ''; + this.query = {}; + } + if (rest) this.pathname = rest; + if (slashedProtocol[lowerProto] && + this.hostname && !this.pathname) { + this.pathname = '/'; + } + + //to support http.request + if (this.pathname || this.search) { + var p = this.pathname || ''; + var s = this.search || ''; + this.path = p + s; + } + + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; + +// format a parsed object into a url string +function urlFormat(obj) { + // ensure it's an object, and not a string url. + // If it's an obj, this is a no-op. + // this way, you can call url_format() on strings + // to clean up potentially wonky urls. + if (typeof(obj) === 'string') obj = urlParse(obj); + if (!(obj instanceof Url)) return Url.prototype.format.call(obj); + return obj.format(); +} + +Url.prototype.format = function() { + var auth = this.auth || ''; + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; + } + + var protocol = this.protocol || '', + pathname = this.pathname || '', + hash = this.hash || '', + host = false, + query = ''; + + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + (this.hostname.indexOf(':') === -1 ? + this.hostname : + '[' + this.hostname + ']'); + if (this.port) { + host += ':' + this.port; + } + } + + if (this.query && typeof this.query === 'object' && + Object.keys(this.query).length) { + query = querystring.stringify(this.query); + } + + var search = this.search || (query && ('?' + query)) || ''; + + if (protocol && protocol.substr(-1) !== ':') protocol += ':'; + + // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + if (this.slashes || + (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; + } else if (!host) { + host = ''; + } + + if (hash && hash.charAt(0) !== '#') hash = '#' + hash; + if (search && search.charAt(0) !== '?') search = '?' + search; + + pathname = pathname.replace(/[?#]/g, function(match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); + + return protocol + host + pathname + search + hash; +}; + +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); +} + +Url.prototype.resolve = function(relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; + +function urlResolveObject(source, relative) { + if (!source) return relative; + return urlParse(source, false, true).resolveObject(relative); +} + +Url.prototype.resolveObject = function(relative) { + if (typeof relative === 'string') { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } + + var result = new Url(); + Object.keys(this).forEach(function(k) { + result[k] = this[k]; + }, this); + + // hash is always overridden, no matter what. + // even href="" will remove it. + result.hash = relative.hash; + + // if the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; + } + + // hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + Object.keys(relative).forEach(function(k) { + if (k !== 'protocol') + result[k] = relative[k]; + }); + + //urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol[result.protocol] && + result.hostname && !result.pathname) { + result.path = result.pathname = '/'; + } + + result.href = result.format(); + return result; + } + + if (relative.protocol && relative.protocol !== result.protocol) { + // if it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol[relative.protocol]) { + Object.keys(relative).forEach(function(k) { + result[k] = relative[k]; + }); + result.href = result.format(); + return result; + } + + result.protocol = relative.protocol; + if (!relative.host && !hostlessProtocol[relative.protocol]) { + var relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())); + if (!relative.host) relative.host = ''; + if (!relative.hostname) relative.hostname = ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // to support http.request + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } + + var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), + isRelAbs = ( + relative.host || + relative.pathname && relative.pathname.charAt(0) === '/' + ), + mustEndAbs = (isRelAbs || isSourceAbs || + (result.host && relative.pathname)), + removeAllDots = mustEndAbs, + srcPath = result.pathname && result.pathname.split('/') || [], + relPath = relative.pathname && relative.pathname.split('/') || [], + psychotic = result.protocol && !slashedProtocol[result.protocol]; + + // if the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + if (psychotic) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host; + else srcPath.unshift(result.host); + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host; + else relPath.unshift(relative.host); + } + relative.host = null; + } + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); + } + + if (isRelAbs) { + // it's absolute. + result.host = (relative.host || relative.host === '') ? + relative.host : result.host; + result.hostname = (relative.hostname || relative.hostname === '') ? + relative.hostname : result.hostname; + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + if (!srcPath) srcPath = []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (relative.search !== null && relative.search !== undefined) { + // just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (psychotic) { + result.hostname = result.host = srcPath.shift(); + //occationaly the auth can get stuck only in host + //this especialy happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + result.search = relative.search; + result.query = relative.query; + //to support http.request + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; + } + + if (!srcPath.length) { + // no path at all. easy. + // we've already handled the other stuff above. + result.pathname = null; + //to support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; + } + + // if a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = ( + (result.host || relative.host) && (last === '.' || last === '..') || + last === ''); + + // strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = srcPath.length; i >= 0; i--) { + last = srcPath[i]; + if (last == '.') { + srcPath.splice(i, 1); + } else if (last === '..') { + srcPath.splice(i, 1); + up++; + } else if (up) { + srcPath.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } + } + + if (mustEndAbs && srcPath[0] !== '' && + (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } + + if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { + srcPath.push(''); + } + + var isAbsolute = srcPath[0] === '' || + (srcPath[0] && srcPath[0].charAt(0) === '/'); + + // put the host back + if (psychotic) { + result.hostname = result.host = isAbsolute ? '' : + srcPath.length ? srcPath.shift() : ''; + //occationaly the auth can get stuck only in host + //this especialy happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + + mustEndAbs = mustEndAbs || (result.host && srcPath.length); + + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } + + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); + } + + //to support request.http + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; +}; + +Url.prototype.parseHost = function() { + var host = this.host; + var port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.substr(1); + } + host = host.substr(0, host.length - port.length); + } + if (host) this.hostname = host; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/url_handler/url_handler.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/lib/url_handler/url_handler.js @@ -0,0 +1,116 @@ +/** + * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. + * * + * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby + * + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNU LibreJS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * url_handler + * A module using the url tool from Node.js to perform operations on + * urls at various spots (tabs, caching, ...) in the add-on. + * + */ + +// node.js url module. Makes it easier to resolve +// urls in that datauri loaded dom +var nodeJsUrl = require("./node_url"); + +var urlUtils = { + getFragment: function (url) { + var parse = nodeJsUrl.parse(url); + if (parse.hash !== undefined) { + return(parse.hash); + } + }, + + removeFragment: function (url) { + var parse = nodeJsUrl.parse(url); + if (parse.hash !== undefined) { + // Amazon track package bug fix. + // when url has query string and fragment + // the add-on wouldn't remove cache entry + // properly. + delete parse.hash; + } + return nodeJsUrl.format(parse); + }, + + addFragment: function (url, query) { + var parse = nodeJsUrl.parse(url); + + // replace hash if it exists. + parse.hash = '#' + query; + + return nodeJsUrl.format(parse); + }, + + addQuery: function (url, query) { + var parse = nodeJsUrl.parse(url); + console.debug('my parse search', parse.search); + if (parse.search === undefined) { + parse.search = '?' + query; + } else { + parse.search = parse.search + '&' + query; + console.debug('parse search is now' + parse.search); + } + return nodeJsUrl.format(parse); + }, + + getHostname: function (url) { + return nodeJsUrl.parse(url).hostname; + }, + + /** + * remove www from hostname. + */ + removeWWW: function (str) { + if (str !== undefined) { + return str.replace("www.", "", 'i'); + } + return ""; + }, + + /** + * + * haveSameHostname + * Compare that two urls have the same hostname. + * + */ + haveSameHostname: function (url1, url2) { + try { + var host1 = this.removeWWW(this.getHostname(url1)).toLowerCase(); + var host2 = this.removeWWW(this.getHostname(url2)).toLowerCase(); + return host1 === host2; + } catch (x) { + console.debug('error with url_handler', x, x.fileName, x.lineNumber); + } + } +}; + +exports.parse = nodeJsUrl.parse; +exports.resolve = nodeJsUrl.resolve; +exports.resolveObject = nodeJsUrl.resolveObject; +exports.format = nodeJsUrl.format; +exports.removeFragment = urlUtils.removeFragment; +exports.addQuery = urlUtils.addQuery; +exports.getFragment = urlUtils.getFragment; +exports.addFragment = urlUtils.addFragment; +exports.getHostname = urlUtils.getHostname; +exports.haveSameHostname = urlUtils.haveSameHostname; +exports.removeWWW = urlUtils.removeWWW; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/locales.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/locales.json @@ -1 +0,0 @@ -{"locales": []} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/.npmignore b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/.npmignore @@ -0,0 +1,7 @@ +.DS_Store +*.xpi +.project +.settings +*.zip +node_modules + diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/.travis.yml b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/.travis.yml @@ -0,0 +1,22 @@ +language: node_js +node_js: +- "0.10" + +before_install: +- "export DISPLAY=:99.0" +- "sh -e /etc/init.d/xvfb start" +- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 -extension RANDR" + +before_script: +- npm install jpm -g +- rm -r node_modules/addon-pathfinder/test +- cd .. +- url="http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-trunk/firefox-36.0a1.en-US.linux-x86_64.tar.bz2" +- wget -O firefox.tar.bz2 "$url" +- bzip2 -cd firefox.tar.bz2 | tar xvf - +- cd $TRAVIS_BUILD_DIR + +script: +- export JPM_FIREFOX_BINARY=$TRAVIS_BUILD_DIR/../firefox/firefox +- jpm test -v + diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/README.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/README.md @@ -0,0 +1,28 @@ +# Menuitem + +[](https://travis-ci.org/jetpack-labs/menuitem) + +[](https://nodei.co/npm/menuitem/) +[](https://nodei.co/npm/menuitem) + +The menuitems API is a simple way to create a menuitem, +which can perform an action when clicked, and display state. + +## Example + + // create menuitem for the File menu, + // and insert it before the 'Quit' menuitem + require("menuitem").Menuitem({ + id: "myextprefix-some-mi-id", + menuid: "menu_FilePopup", + insertbefore: "menu_FileQuitItem", + "label": _("label"), + "accesskey": _("label.ak"), + image: self.data.url("icon.png"), + className: 'pizazz', + disabled: false, + checked: false, + onCommand: function() { + // do something + } + }); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/index.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/index.js @@ -0,0 +1,218 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const windowUtils = require("sdk/deprecated/window-utils"); +const { Class } = require("sdk/core/heritage"); +const { validateOptions } = require("sdk/deprecated/api-utils"); +const { on, emit, once, off } = require("sdk/event/core"); +const { isBrowser } = require("sdk/window/utils"); +const { EventTarget } = require('sdk/event/target'); +const menuitemNS = require("sdk/core/namespace").ns(); + +const { unload } = require('pathfinder/lib/addon/unload'); + +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +function MenuitemOptions(options) { + return validateOptions(options, { + id: { is: ['string'] }, + menuid: { is: ['undefined', 'string'] }, + insertbefore: { is: ['undefined', 'string', 'object', 'number'] }, + label: { is: ["string"] }, + include: { is: ['string', 'undefined'] }, + disabled: { is: ["undefined", "boolean"], map: function(v) !!v}, + accesskey: { is: ["undefined", "string"] }, + key: { is: ["undefined", "string"] }, + checked: { is: ['undefined', 'boolean'] }, + className: { is: ["undefined", "string"] }, + onCommand: { is: ['undefined', 'function'] }, + useChrome: { map: function(v) !!v } + }); +} + +let Menuitem = Class({ + extends: EventTarget, + initialize: function(options) { + options = menuitemNS(this).options = MenuitemOptions(options); + EventTarget.prototype.initialize.call(this, options); + + menuitemNS(this).destroyed = false; + menuitemNS(this).unloaders = []; + menuitemNS(this).menuitems = addMenuitems(this, options).menuitems; + }, + get id() menuitemNS(this).options.id, + get label() menuitemNS(this).options.label, + set label(val) updateProperty(this, 'label', val), + get checked() menuitemNS(this).options.checked, + set checked(val) updateProperty(this, 'checked', !!val), + get disabled() menuitemNS(this).options.disabled, + set disabled(val) updateProperty(this, 'disabled', !!val), + get key() menuitemNS(this).options.key, + set key(val) updateProperty(this, 'key', val), + clone: function (overwrites) { + let opts = Object.clone(menuitemNS(this).options); + for (let key in overwrites) { + opts[key] = overwrites[key]; + } + return Menuitem(opts); + }, + get menuid() menuitemNS(this).options.menuid, + set menuid(val) { + let options = menuitemNS(this).options; + options.menuid = val; + + forEachMI(function(menuitem, i, $) { + updateMenuitemParent(menuitem, options, $); + }); + }, + destroy: function() { + if (!menuitemNS(this).destroyed) { + menuitemNS(this).destroyed = true; + menuitemNS(this).unloaders.forEach(function(u) u()); + menuitemNS(this).unloaders = null; + menuitemNS(this).menuitems = null; + } + return true; + } +}); + +function addMenuitems(self, options) { + let menuitems = []; + + // setup window tracker + windowUtils.WindowTracker({ + onTrack: function (window) { + if (menuitemNS(self).destroyed) return; + if (options.include) { + if (options.include != window.location) return; + } + else if (!isBrowser(window)) { + return; + } + + // add the new menuitem to a menu + var menuitem = updateMenuitemAttributes( + window.document.createElementNS(NS_XUL, "menuitem"), options); + var menuitems_i = menuitems.push(menuitem) - 1; + + // add the menutiem to the ui + let added = updateMenuitemParent(menuitem, options, function(id) window.document.getElementById(id)); + + menuitem.addEventListener("command", function() { + if (!self.disabled) + emit(self, 'command', options.useChrome ? window : null); + }, true); + + // add unloader + let unloader = function unloader() { + menuitem.parentNode && menuitem.parentNode.removeChild(menuitem); + menuitems[menuitems_i] = null; + }; + + menuitemNS(self).unloaders.push(function() { + remover(); + unloader(); + }); + + let remover = unload(unloader, window); + } + + }); + + return { menuitems: menuitems }; +} + +function updateMenuitemParent(menuitem, options, $) { + // add the menutiem to the ui + if (Array.isArray(options.menuid)) { + let ids = options.menuid; + for (var len = ids.length, i = 0; i < len; i++) { + if (tryParent($(ids[i]), menuitem, options.insertbefore)) + return true; + } + } + else { + return tryParent($(options.menuid), menuitem, options.insertbefore); + } + + return false; +} + +function updateMenuitemAttributes(menuitem, options) { + menuitem.setAttribute("id", options.id); + menuitem.setAttribute("label", options.label); + + if (options.accesskey) + menuitem.setAttribute("accesskey", options.accesskey); + + if (options.key) + menuitem.setAttribute("key", options.key); + + menuitem.setAttribute("disabled", !!options.disabled); + + if (options.image) { + menuitem.classList.add("menuitem-iconic"); + menuitem.style.listStyleImage = "url('" + options.image + "')"; + } + + if (options.checked) + menuitem.setAttribute('checked', options.checked); + + if (options.className) + options.className.split(/\s+/).forEach(function(name) menuitem.classList.add(name)); + + return menuitem; +} + +function updateProperty(menuitem, key, val) { + menuitemNS(menuitem).options[key] = val; + + forEachMI(function(menuitem) { + menuitem.setAttribute(key, val); + }, menuitem); + return val; +} + +function forEachMI(callback, menuitem) { + menuitemNS(menuitem).menuitems.forEach(function(mi, i) { + if (!mi) return; + callback(mi, i, function(id) mi.ownerDocument.getElementById(id)); + }); +} + +function tryParent(parent, menuitem, before) { + if (parent) { + if (!before) { + parent.appendChild(menuitem); + return true; + } + + parent.insertBefore(menuitem, insertBefore(parent, before)); + return true; + } + + return false; +} + +function insertBefore(parent, insertBefore) { + if (typeof insertBefore == "number") { + switch (insertBefore) { + case MenuitemExport.FIRST_CHILD: + return parent.firstChild; + } + return null; + } + else if (typeof insertBefore == "string") { + return parent.querySelector("#" + insertBefore); + } + return insertBefore; +} + +function MenuitemExport(options) { + return Menuitem(options); +} +MenuitemExport.FIRST_CHILD = 1; + +exports.Menuitem = MenuitemExport; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/package.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/package.json @@ -0,0 +1,82 @@ +{ + "_args": [ + [ + "menuitem@0.0.5", + "/home/nik/src/librejs" + ] + ], + "_from": "menuitem@0.0.5", + "_id": "menuitem@0.0.5", + "_inCache": true, + "_location": "/menuitem", + "_nodeVersion": "4.0.0", + "_npmUser": { + "email": "accounts.npm@overbythere.co.uk", + "name": "overbythere" + }, + "_npmVersion": "2.14.2", + "_phantomChildren": {}, + "_requested": { + "name": "menuitem", + "raw": "menuitem@0.0.5", + "rawSpec": "0.0.5", + "scope": null, + "spec": "0.0.5", + "type": "version" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/menuitem/-/menuitem-0.0.5.tgz", + "_shasum": "c170347dcc0cc7195af645f300acd8f99522f896", + "_shrinkwrap": null, + "_spec": "menuitem@0.0.5", + "_where": "/home/nik/src/librejs", + "author": { + "name": "Erik Vold" + }, + "bugs": { + "url": "https://github.com/OverByThere/menuitem/issues" + }, + "dependencies": { + "pathfinder": "git+https://github.com/OverByThere/addon-pathfinder.git" + }, + "description": "[](https://travis-ci.org/jetpack-labs/menuitem)", + "devDependencies": {}, + "directories": { + "test": "test" + }, + "dist": { + "shasum": "c170347dcc0cc7195af645f300acd8f99522f896", + "tarball": "http://registry.npmjs.org/menuitem/-/menuitem-0.0.5.tgz" + }, + "gitHead": "bb3f05ea29164bf673a4cdd076fc620266028e53", + "homepage": "https://github.com/OverByThere/menuitem#readme", + "installable": true, + "keywords": [ + "firefox", + "gecko", + "jetpack", + "menu", + "menuitem", + "ui" + ], + "license": "MPL-2.0", + "main": "index.js", + "maintainers": [ + { + "name": "overbythere", + "email": "accounts.npm@overbythere.co.uk" + } + ], + "name": "menuitem", + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/OverByThere/menuitem.git" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "version": "0.0.5" +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/test/test-menuitems.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/menuitem/test/test-menuitems.js @@ -0,0 +1,169 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict' + +const windowUtils = require('sdk/deprecated/window-utils'); +const menuitems = require('../index'); + +let window = windowUtils.activeBrowserWindow; +let document = window.document; +function $(id) document.getElementById(id); + +function createMI(options, test) { + test.equal(!$(options.id), true); + var mi = new menuitems.Menuitem(options); + return mi; +} + +exports.testMIDoesNotExist = function(assert) { + var options = { + id: "test-mi-dne", + label: "test" + }; + createMI(options, assert); + assert.equal(!!$(options.id), false, 'menuitem does not exists'); +}; + +exports.testMIDoesExist = function(assert) { + var options = { + id: "test-mi-exists", + label: "test", + menuid: 'menu_FilePopup' + }; + let mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.id, options.id, 'menuitem id is ok'); + assert.equal(menuitem.getAttribute('label'), options.label, 'menuitem label is ok'); + assert.equal(menuitem.parentNode.id, options.menuid, 'in the file menu'); + assert.equal(menuitem.getAttribute('disabled'), 'false', 'menuitem not disabled'); + assert.equal(menuitem.getAttribute('accesskey'), '', 'menuitem accesskey is ok'); + assert.equal(menuitem.getAttribute('class'), '', 'menuitem class is ok'); + assert.equal(menuitem.nextSibling, undefined, 'menuitem is last'); + assert.equal(menuitem.hasAttribute("checked"), false, 'menuitem not checked'); + mi.destroy(); + assert.ok(!$(options.id), 'menuitem is gone'); + assert.equal(menuitem.parentNode, null, 'menuitem has no parent'); +}; + +exports.testMIOnClick = function(assert, done) { + let options = { + id: "test-mi-onclick", + label: "test", + menuid: 'menu_FilePopup', + onCommand: function() { + mi.destroy(); + assert.pass('onCommand worked!'); + done(); + } + }; + + let e = document.createEvent("UIEvents"); + e.initUIEvent("command", true, true, window, 1); + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + menuitem.dispatchEvent(e); +}; + +exports.testMIDisabled = function(assert, done) { + let commandIsOK = false; + let count = 0; + let options = { + id: "test-mi-disabled", + label: "test", + disabled: true, + menuid: 'menu_FilePopup', + onCommand: function() { + count++; + if (!commandIsOK) { + assert.fail('onCommand was called, that is not ok'); + return; + } + + mi.destroy(); + assert.equal(count, 1, 'onCommand was called the correct number of times!'); + done(); + } + }; + + let e = document.createEvent("UIEvents"); + e.initUIEvent("command", true, true, window, 1); + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.getAttribute('disabled'), 'true', 'menuitem not disabled'); + menuitem.dispatchEvent(e); + mi.disabled = false; + assert.equal(menuitem.getAttribute('disabled'), 'false', 'menuitem not disabled'); + commandIsOK = true; + menuitem.dispatchEvent(e); +}; + +exports.testMIChecked = function(assert) { + let options = { + id: "test-mi-checked", + label: "test", + disabled: true, + menuid: 'menu_FilePopup', + checked: true + }; + + let mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.getAttribute("checked"), "true", 'menuitem checked'); + mi.checked = false; + assert.equal(menuitem.getAttribute("checked"), "false", 'menuitem checked'); + mi.destroy(); +}; + +exports.testMIClass = function(assert) { + let options = { + id: "test-mi-class", + label: "pizazz", + className: "pizazz", + menuid: 'menu_FilePopup', + }; + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.getAttribute('class'), 'pizazz', 'menuitem not disabled'); + mi.destroy(); +}; + +exports.testInsertBeforeExists = function(assert) { + let options = { + id: 'test-mi-insertbefore', + label: 'insertbefore', + insertbefore:'menu_FileQuitItem', + menuid: 'menu_FilePopup', + }; + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.nextSibling, $('menu_FileQuitItem'), 'menuitem not disabled'); + mi.destroy(); +}; + +exports.testInsertBeforeDoesNotExist = function(assert) { + let options = { + id: 'test-mi-insertbefore', + label: 'insertbefore', + insertbefore:'menu_ZZZDNE', + menuid: 'menu_FilePopup', + }; + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.nextSibling, null, 'menuitem not disabled'); + mi.destroy(); +}; + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/mpl-2.0.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/LICENSE diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/README.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/README.md @@ -0,0 +1,5 @@ +NotificationBox implements some of the notificationbox element functionality in Firefox and Mozilla-based browsers using the Addon SDK. For any question or feedback please email lduros--at--member.fsf.org + +It is released under the MPL 2.0. + +See [doc/main.md](https://github.com/lduros/notificationbox/blob/master/doc/main.md) for more information. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/images/gnu-icon.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/data/gnu-icon.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/doc/images/critical-notification.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/doc/images/critical-notification.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/doc/images/info-low-priority.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/doc/images/info-low-priority.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/doc/main.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/doc/main.md @@ -0,0 +1,53 @@ +NotificationBox implements some of the notificationbox element functionality in Firefox and Mozilla-based browsers using the Addon SDK. For any question or feedback please email lduros--at--member.fsf.org + +You can create a notification as follows: +```javascript +var self = require("self"); +var notification = require("notification-box").NotificationBox({ + 'value': 'important-message', + 'label': 'This is a very important message!', + 'priority': 'CRITICAL_BLOCK', + // Automatically close notification in 5s + 'timeout': 5000, + // How many page changes the notification will stay active for + 'persistence': 2, + 'image': self.data.url("gnu-icon.png"), + 'buttons': [{'label': "Do something about it!", + 'onClick': function () { console.log("You clicked the important button!"); }}] +}); +``` + +It implements the following options: + + - value: value used to identify the notification + - label: label to appear on the notification + - image: URL of image to appear on the notification. You can also + load a local image from the data folder, like in the example + - timeout: How many milliseconds until the notification will automatically close + - persistence: How many page changes the notification will stay active for + - eventCallback: Function to call when notification closes (arg1: reason) + - priority: notification priority. Use one of the following: + - INFO_LOW + - INFO_MEDIUM + - INFO_HIGH + - WARNING_LOW + - WARNING_MEDIUM + - WARNING_HIGH + - CRITICAL_LOW + - CRITICAL_MEDIUM + - CRITICAL_HIGH + - CRITICAL_BLOCK + - buttons: array of buttons to appear on the notification. + You can use the following options: + - accessKey: the accesskey to appear on the button + - onClick: the callback function to trigger when button is activated. + - label: the text to display on the button + + +Here is an overview of what the example above with the critical notification looks like: + + +When using 'INFO_LOW' for the priority instead, you would see: + + +For more information on notificationbox: https://developer.mozilla.org/en-US/docs/XUL/notificationbox diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/lib/main.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/lib/main.js @@ -0,0 +1,16 @@ +/* + * Copyrights Loic J. Duros 2012 + * lduros@member.fsf.org + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var self = require("self"); +var notification = require("notification-box").NotificationBox({ + 'value': 'important-message', + 'label': 'You have been warned...', + 'priority': 'WARNING_HIGH', + 'image': self.data.url("gnu-icon.png"), + 'buttons': [{'label': "Gotcha", + 'onClick': function () { console.log("You clicked the important button!"); }}] +}); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/lib/notification-box.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/lib/notification-box.js @@ -0,0 +1,147 @@ +/* + * Copyright 2014 + * @author Loic J. Duros lduros@member.fsf.org + * @author Joshua Cornutt jcornutt@gmail.com + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const { Cc, Ci } = require("chrome"); +const { getMostRecentBrowserWindow } = require('sdk/window/utils'); + +/* I haven't found this sort of validation functions in the SDK, +except for the deprecated api-utils module. */ +let isString = function (str) { + if ( !str ) return false; + return typeof(str) == 'string' || str instanceof String; +}; + +let isArray = function (obj) { + if ( !obj || typeof(obj) === 'undefined' ) return false; + return Object.prototype.toString.call(obj) === '[object Array]'; +}; + +let isObject = function(obj) { + if ( !obj || typeof(obj) === 'undefined' ) return false; + return obj instanceof Object; +} + +let isInteger = function(val) { + if ((undefined === val) || (null === val)) return false; + return !isNaN(val); +} + +let isFunction = function(obj) { + if ( !obj || typeof(obj) === 'undefined' ) return false; + return {}.toString.call(obj) === '[object Function]'; +} + +exports.NotificationBox = function (options) { + options = options || {}; + let mainWindow = getMostRecentBrowserWindow(); + let nbObj = mainWindow.gBrowser.getNotificationBox(); + let priority = nbObj[PRIORITY.INFO_LOW], + label = '', + image = 'chrome://browser/skin/Info.png', + value = '', + persistence = 0, + eventCallback = function(){}, + buttons = []; + + if (options.value && isString(options.value)) + value = options.value; + + // Set how many page changes the notification will remain active for. + if ( options.persistence && isInteger(options.persistence) ) + persistence = options.persistence; + + // Set if the user wants to be notified when the notification closes + if ( options.eventCallback && isFunction(options.eventCallback) ) + eventCallback = options.eventCallback; + + // Add label or create empty notification. + if (options.label && isString(options.label)) + label = options.label; + + // Set priority of the notification (from INFO_LOW to CRITICAL_BLOCK) + if (options.priority && options.priority in PRIORITY) + priority = nbObj[PRIORITY[options.priority]]; + + // Set a custom icon for the notification or use the stock info icon. + if (options.image && isString(options.image)) + image = options.image; + + // Sanitize and format each notification button + if ( isArray(options.buttons) ) + for (let i = 0, length = options.buttons.length; i < length; i++) + buttons.push(NotificationButton(options.buttons[i])); + else if ( isObject(options.buttons) ) + // If it's not an array of buttons, then it should be a single button. + buttons.push(NotificationButton(options.buttons)); + else + buttons = null; + + // Add a new notification to the notificationbox. + var nObj = nbObj.appendNotification(label, value, + image, priority, buttons, eventCallback); + + // Set how many page changes the notification will stay active for + nObj.persistence = persistence; + + // Timeout for closing the notification automatically + if( options.timeout && isInteger(options.timeout) ) { + require('sdk/timers').setTimeout( function() { + if( isFunction(nObj.close) ) + nObj.close(); + }, options.timeout ); + } + + // Expose both the NotificationBox and Notification itself + return {'notificationbox': nbObj, 'notification': nObj}; +}; + + +// Notification button santizing function +var NotificationButton = function (options) { + options = options || {}; + let accessKey = '', + onClick = function(){}, + label = "", + popup = null, // no popup for now... maybe we can use a panel later. + timeout = 0; + + if ( options.accessKey ) + accessKey = options.accessKey; + + if ( isFunction(options.onClick) ) + onClick = options.onClick; + + if ( options.label ) + label = options.label; + + if ( isInteger(options.timeout) ) + timeout = options.timeout; + + return {label: label, + accessKey: accessKey, + callback: onClick, + popup: popup, + timeout: timeout}; +}; + +const PRIORITY = { + 'INFO_LOW': 'PRIORITY_INFO_LOW', + 'INFO_MEDIUM': 'PRIORITY_INFO_MEDIUM', + 'INFO_HIGH': 'PRIORITY_INFO_HIGH', + 'WARNING_LOW': 'PRIORITY_WARNING_LOW', + 'WARNING_MEDIUM': 'PRIORITY_WARNING_MEDIUM', + 'WARNING_HIGH': 'PRIORITY_WARNING_HIGH', + 'CRITICAL_LOW': 'PRIORITY_CRITICAL_LOW', + 'CRITICAL_MEDIUM': 'PRIORITY_CRITICAL_MEDIUM', + 'CRITICAL_HIGH': 'PRIORITY_CRITICAL_HIGH', + 'CRITICAL_BLOCK': 'PRIORITY_CRITICAL_BLOCK' +}; + +exports.PRIORITY = PRIORITY; +\ No newline at end of file diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/package.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/package.json @@ -0,0 +1,61 @@ +{ + "_args": [ + [ + "notification-box@0.1.1", + "/home/nik/src/librejs" + ] + ], + "_from": "notification-box@0.1.1", + "_id": "notification-box@0.1.1", + "_inCache": true, + "_location": "/notification-box", + "_nodeVersion": "0.10.25", + "_npmUser": { + "email": "nikolas@gnu.org", + "name": "nnyby" + }, + "_npmVersion": "2.11.2", + "_phantomChildren": {}, + "_requested": { + "name": "notification-box", + "raw": "notification-box@0.1.1", + "rawSpec": "0.1.1", + "scope": null, + "spec": "0.1.1", + "type": "version" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/notification-box/-/notification-box-0.1.1.tgz", + "_shasum": "b82020c859001846bef65b33766d9f6915cf0498", + "_shrinkwrap": null, + "_spec": "notification-box@0.1.1", + "_where": "/home/nik/src/librejs", + "author": { + "name": "Loic Duros" + }, + "dependencies": {}, + "description": "a basic add-on", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "b82020c859001846bef65b33766d9f6915cf0498", + "tarball": "http://registry.npmjs.org/notification-box/-/notification-box-0.1.1.tgz" + }, + "fullName": "notification-box", + "gitHead": "28d8d3ca6b766691d99941293e5f3d1fba47f9f7", + "id": "jid1-dyFGGJB0CjoDMA", + "installable": true, + "license": "MPL 2.0", + "maintainers": [ + { + "name": "nnyby", + "email": "nikolas@gnu.org" + } + ], + "name": "notification-box", + "optionalDependencies": {}, + "scripts": {}, + "version": "0.1.1" +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/test/test-main.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/notification-box/test/test-main.js @@ -0,0 +1,12 @@ +var main = require("main"); + +exports["test main"] = function(assert) { + assert.pass("Unit test running!"); +}; + +exports["test main async"] = function(assert, done) { + assert.pass("async Unit test running!"); + done(); +}; + +require("test").run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/.npmignore b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/.npmignore @@ -0,0 +1,6 @@ +.DS_Store +*.xpi +.project +.settings +*.zip + diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/README.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/README.md @@ -0,0 +1,22 @@ +# Add-on Pathfinder + +The Add-on Pathfinder is the collection of Jetpack modules made to be used with the +[Add-on SDK](https://github.com/mozilla/addon-sdk). + +## Highlights + +* Toolbar buttons +* Menuitems +* GCLI +* Downloads +* About/Resource Schemes +* UserStyles +* UserScripts +* XUL Help +* ZIP Utilities +* Content policies +* Content Permissions +* Awesomebar +* Modifying Request Headers +* Redirects +* Much much more!... diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning-mod.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning-mod.js @@ -0,0 +1,19 @@ +'use strict'; + +let $ = function(id) document.getElementById(id); + +function doAndClose(func) { + func(); + window.close(); +} + +$('cancel-btn').addEventListener('click', doAndClose(function() self.port.emit("cancel")), false); +$('ok-btn').addEventListener('click', doAndClose(function() self.port.emit("accept")), false); + +self.port.on('load', function(data) { + $('errorTitle').innerHTML = data.errorTitle || ''; + $('errorShortDesc').innerHTML = data.errorShortDesc || ''; + $('errorLongDesc').innerHTML = data.errorLongDesc || ''; + $('cancel-btn').setAttribute('value', data.cancelButtonLabel || 'Decline'); + $('ok-btn').setAttribute('value', data.okButtonLabel || 'Accept'); +}); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.css @@ -0,0 +1,47 @@ +html, body { + background-color: white; + color: #222; + font-family: helvetica, arial, sans-serif; + height: 100%; + padding: 0; + margin: 0; +} + +#content { + height: 100%; + width: 90%; + margin: auto; +} + +#banner { + background: url("/content/gfx/jetpack.png") no-repeat right center; + height: 138px; + font-size: 22pt; + font-weight: normal; + padding-left: 0; + padding-right: 300px; + padding-top: 20px; + padding-bottom: 20px; +} + +#banner a { + color: black; +} + +#featureName { + font-style: italic; +} + +#featureContentContainer { + height: 100%; +} + +#featureContent { + height: 100%; + min-height: 200px; + width: 100%; +} + +#confirmationShortDesc { + font-size: 14pt; +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html class="blacklist"> + <head> + <title></title> + <script type="application/javascript;version=1.8" src="warning.js"></script> + <link rel="stylesheet" type="text/css" media="all" href="chrome://global/skin/netError.css"/> + <link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/blacklist_favicon.png"/> + </head> + <body> + <div id="errorPageContainer"> + <div> + <h1 id="errorTitle"></h1> + </div> + + <div id="errorLongContent"> + <div id="errorShortDesc"></div> + + <div id="errorLongDesc"></div> + + <div id="buttons"> + <p> + <input id="cancel-btn" type="button" value="#cancelButtonLabel#"/> + <input id="ok-btn" type="button" value="#okButtonLabel#"/> + </p> + </div> + </div> + </div> + </body> +</html> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/data/warning.js @@ -0,0 +1,3 @@ +'use strict'; + + diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon-warning.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon-warning.md diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addon.md @@ -0,0 +1,28 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + + +The `addon` API provides a simple way to create +Add-on wrapper instances for the [Extension Manager](about:addons). + +## Example ## + + exports.main = function(options) { + + }; + +<api name="Addon"> +@class + +Module exports `Addon` constructor allowing users to create a +add-on category provider to the Extension Manager. + +<api name="Addon"> +@constructor +Creates a add-on wrapper instance. + +@param options {Object} +Options for the add-on wrapper, with the following parameters: + +</api> + +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addonprovider.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/addonprovider.md @@ -0,0 +1,50 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + + +The `addonprovider` API provides a simple way to create +new Add-on types for the [Extension Manager](about:addons). + +## Example ## + + exports.main = function(options) { + + }; + +<api name="AddonProvider"> +@class + +Module exports `AddonProvider` constructor allowing users to create a +add-on category provider to the Extension Manager. + +<api name="AddonProvider"> +@constructor +Creates a add-on provider. + +@param options {Object} +Options for the add-on provider, with the following parameters: + +@prop type {String} +A unique string that will identify the type of add-ons that your provider +will provide. This is internal users never see it. + +@prop localeKey {String} +A label to be used in the Extension Manager, which users see. + +@prop uiPriority {Number} +A number to represent the order to display your Add-on type in the Extension +Manager side navigation. + +@prop getAddonByID {Function} +A function that returns the appropriate `Addon`. + +@prop getAddons {Function} +A function that returns the appropriate `Addon`s. + +</api> + +<api name="destroy"> +@method +Removes the add-on provider. +</api> + +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/awesomebar.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/awesomebar.md @@ -0,0 +1,61 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + + +The `awesomebar` API provides a simple way to create AwesomeBar suggestions. + +## Example ## + + // add github search + AwesomeBarSuggestion({ + icon: self.data.url("github_16.png"), + matches: /^(?:@[\w\d_-]+|github\s)/i, + onSearch: function(query, suggest) { + query = query.trim(); + if (/^github\s/i.test(query)) { + query = query.replace(/^github\s/i, ""); + suggest({ + title: 'Search Github for: ' + query, + favicon: self.data.url("github_16.png"), + url: 'https://github.com/search?q=' + encodeURIComponent(query) + }, true); + } else { + var username = query.match(/^@([\w\d_-]+)/)[1]; + suggest({ + title: 'Github user: ' + username, + label: "View user profile for @" + username, + favicon: self.data.url("github_16.png"), + url: 'https://github.com/' + username + }, true); + } + } + }); + +<api name="AwesomeBarSuggestion"> +@class + A `AwesomeBarSuggestion` constructor is exported, which allows one to create a + AwesomeBar suggestions. + +<api name="AwesomeBarSuggestion"> +@constructor + Creates a AwesomeBar suggestion handler. + +@param options {object} + Options for the AwesomeBar suggester, with the following parameters: + +@prop matches {string} + A regular expression which is tested againsted the location bar input string. + +@prop [icon] {string} + A URL for a 16x16 icon image. + +@prop onSearch {function} + Function that is invoked when the match pattern matches the location bar input + string. If will receive too arguments, `query` which is the input string, and + `suggest` which is a function that can be made to return suggestions. +</api> + +<api name="destroy"> +@method + Removes the AwesomeBar suggester. +</api> +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/content-policy.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/content-policy.md diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/l10n.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/l10n.md @@ -0,0 +1,41 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + +The `l10n` module allows one to localize their Jetpack. + +## Example ## + + var _ = require("l10n").l10n({ + filename: "text.properties", + baseURL: require("self").data.url("locale") + }); + console.log(_("hello.world")); + +<api name="l10n"> +@function + Creates and returns a function which can be used to access translations by + key. + + Translations should be grouped together in a folder which contains a folder + for each locale being supported whose name is the locale being supported + (examples: "en", "en-US", "ja", "ja-JP"). Inside each locale's folder should + be a `.properties` file with a name that is the same for every locale. Here + is a example of how you might organize things: + + - data/ + - locale/ + - en/ + - text.properties + - ja/ + - text.properties + +@param options {object} + + +@prop filename {string} + The name of the file storing the translations. +@prop baseURL {string} + The url to the folder containing the locale folders. +@prop [defaultLocale] {string} + Defines the locale to use when you don't have translations for the user's + locale. The default is `"en"`. +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/listen.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/listen.md @@ -0,0 +1,23 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + +The `listen` module allows modules to register listeners to elements that are +automatically removed when the module unloads. + +<api name="listen"> +@function + Add listeners to run when unloading in a unload queue. Optionally scope the + callback to a container, e.g., window. Provide a way to run all the callbacks. + +@param container {object} + A container for the node, which a "unload" event will be attached to, this is + used to cancel the unload magic that would occur, to avoid memory leaks. +@param node {object} + The node to listen to. +@param event {string} + The event type, for example: "load", "click", ... +@param callback {function} + A function to be called when the event occurs on the node. +@param [capture] {boolean} + Indicates if the event should be captured. [See the `useCapture` + documentation here](https://developer.mozilla.org/en/DOM/element.addEventListener). +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/menuitems.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/menuitems.md @@ -0,0 +1,66 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + + +The `menuitems` API is a simple way to create +[Menuitems](https://developer.mozilla.org/en/XUL/PopupGuide/MenuItems), which +can perform an action when clicked, and display state. + +## Example ## + + exports.main = function(options) { + // create menuitem for the File menu, + // and insert it before the 'Quit' menuitem + require("menuitems").Menuitem({ + id: "myextprefix-some-mi-id", + menuid: "menu_FilePopup", + insertbefore: "menu_FileQuitItem", + "label": _("label"), + "accesskey": _("label.ak"), + image: self.data.url("icon.png"), + className: 'pizazz', + disabled: false, + checked: false, + onCommand: function() { + // do something + } + }); + }; + +<api name="Menuitem"> +@class + +Module exports `Menuitem` constructor allowing users to create a +[`menuitem`](https://developer.mozilla.org/en/XUL/menuitem). + +<api name="Menuitem"> +@constructor +Creates a `menuitem`. + +@param options {Object} + Options for the `menuitem`, with the following parameters: + +@prop id {String} +A id for the `menuitem`, this should be namespaced. + +@prop menuid {String} +The id of the parent `<menu>` node. + +@prop label {String} +A label for the `menuitem`. + +@prop image {String} +A image url for the `menuitem`. + +@prop className {String} +A default space delimited list of class names for the menuitem. + +@prop disabled {Boolean} +When a menuitem is disabled it cannot be used, but is still displayed. + +@prop checked {Boolean} +Displays a check beside the menuitem. + +@prop [onCommand] {Function} + A option function that is invoked when the `menuitem` is executed. +</api> +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/panic.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/panic.md @@ -0,0 +1,45 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + +The `panic` API provides a simple way to create a panic, which +can be used to anything that is desired in a panic situation, like entering +private browsing mode, closing/replacing/hiding tabs, or anything else you +can imagine. + +## Example ## + + // create a panic that lasts 5 mins + require('panic').panic(5*60*1000); + +<api name="inPanic"> +@property {boolean} + This read-only boolean is true if there is a panic going on. +</api> + +<api name="panic"> +@function + Starts a panic. +@param milliseconds {Number} + Optional number of milliseconds that the panic should last for, this would + be useful if you want ensure that certain things are but on hold until the + panic subsides. +</api> + +<api name="start"> +@event +Emitted immediately after a panic begins + + var panic = require('panic'); + panic.on("start", function() { + // Do something when a panic starts + }); +</api> + +<api name="end"> +@event +Emitted immediately after the panic ends + + var panic = require('panic'); + panic.on("start", function() { + // Do something when a panic ends + }); +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/toolbarbutton.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/toolbarbutton.md @@ -0,0 +1,84 @@ +The `toolbarbutton` API provides a simple way to create +[toolbar buttons](https://developer.mozilla.org/en/XUL/toolbarbutton), which +can perform an action when clicked. + +## Example ## + + // create toolbarbutton + var tbb = require("toolbarbutton").ToolbarButton({ + id: "TBB-TEST", + label: "TBB TEST", + onCommand: function () { + tbb.destroy(); // kills the toolbar button + } + }); + + if (require('self').loadReason == "install") { + tbb.moveTo({ + toolbarID: "nav-bar", + forceMove: false // only move from palette + }); + } + +<api name="ToolbarButton"> +@class + +Module exports `ToolbarButton` constructor allowing users to create a +toolbar button. + +<api name="ToolbarButton"> +@constructor +Creates a toolbarbutton. + +@param options {Object} + Options for the toolbarbutton, with the following parameters: + +@prop id {String} +A id for the toolbar button, this should be namespaced. + +@prop label {String} +A label for the toolbar button. + +@prop image {String} +A image url for the toolbar button. + +@prop [onCommand] {Function} + A option function that is invoked when the toolbar button is pressed. + +@prop [panel] {Panel} + A optional panel. +</api> + +<api name="destroy"> +@method +Removes the toolbar button from all open windows and no longer adds the +toolbar button to new windows. +</api> + +<api name="moveTo"> +@method +Moves the toolbar button on all open windows to the desired location. + +@param options {Object} +Options which describe the position to move the toolbar button to, with the +following parameters: + +@prop toolbarID {String} +The id of the toolbar which you want to add the toolbar button to. + +Example toolbar IDs: + +- **toolbar-menubar**: The menu bar. +- **nav-bar**: The navigation bar. +- **TabsToolbar**: The tabs bar. +- **addon-bar**: The addon bar. + +@prop insertbefore {String} +The id of the element which the toolbar button should be inserted before. + +@prop forceMove {Boolean} +If `forceMove` is `false`, then the move will only occur if the toolbar button +is not already being used. If `true`, then the move will happen no matter where +the toolbar button is. +</api> +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/unload+.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/unload+.md @@ -0,0 +1,20 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + +The `unload+` module allows modules to register callbacks that are called +when they are unloaded, and associate unload functions to containers to have the +unloader automatically deleted when the container unloads. + +<api name="unload"> +@function + Save callbacks to run when unloading in a unload queue. Optionally scope the + callback to a container, e.g., window. Provide a way to run all the callbacks. + +@param callback {function} + A function to be called when the module unloads. +@param [container] {object} + Optional container object; if the container "unloads" before the module + unloads, then the associated callback is removed from the unload queue. +@returns {function} + Returns a function which will allow one to remove the callback from the unload + queue. +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userscript.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userscript.md @@ -0,0 +1,44 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + +The `userscript` module allows modules to create user scripts which automatically +start running on windows opened after the user script is created. + + +## Example ## + var scripts = ["test.user.js"]; + var self = require("self"); + var {UserScript} = require("userscript"); + exports.main = function() { + scripts.forEach(function(scriptName, index) { + UserScript(self.data.url(scriptName)); + }); + }; + + +<api name="UserScript"> +@class + +The module exports a `UserScript` constructor which allowing one to create a +user script. + +<api name="UserScript"> +@constructor +Creates a user script. + +@param aURL {String} + The url of a user script on the local file system, so this url can be a + `resource:`, `file:`, or `chrome:` for example. +</api> + +<api name="enabled"> +@property {Boolean} +Allows one to get and change the status of the a user script. A disabled user +script will not be injected in to newly opened windows. +</api> + +<api name="destroy"> +@method +The user script will no longer be injected into new windows, you will have to +create a new user script in order to run the script again. +</api> +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userstyles.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/userstyles.md @@ -0,0 +1,26 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + +The `userstyles` module allows one to load css/userstyles for content or chrome +pages. + +## Example ## + + // loads a user stylesheet + require("userstyles").load(require("self").data.url("style.css")); + +<api name="load"> +@function + Loads css (aka userstyles) to the browser which will be automatically removed + when the add-on unloads. + +@param url {string} + The url of a css file. + +@param options {object} + Some options for the stylesheet. + +@prop type {String} + The type for the stylesheet, there are two types 'agent' and 'user'. + The default should be used when possible, which is 'user'. + +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/xulkeys.md b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/docs/xulkeys.md @@ -0,0 +1,55 @@ +<!-- contributed by Erik Vold [erikvvold@gmail.com] --> + +Some add-ons may wish to define keyboard shortcuts for certain operations. This +module exposes an API to create +[xul based hotkeys](https://developer.mozilla.org/en/XUL/key). + +## Example ## + + var keyID = "ADDON:EXAMPLE-HOTKEY@ERIKVOLD.COM:CMD-ALT-R"; + const { XulKey } = require("xulkeys"); + + XulKey({ + id: keyID, + modifiers: "accel,alt", + key: "R", + onCommand: function() { + console.log("pressed"); + } + }); + +<api name="XulKey"> +@class + +This module exports a `XulKey` constructor which allows one to create xul based +hotkeys. + +<api name="XulKey"> +@constructor +Creates a hotkey whose `onCommand` listener method is invoked when the key +comboination provided is pressed. + +@param options {Object} + Options that define the hotkey, with the following properties: + +@prop [id] {string} + A namespaced unique id for the key element. +@prop key {string} + The key to listen for. +@prop [modifiers] {string} + A list of modifier keys that should be pressed to invoke the hotkey. + Multiple keys may be separated by spaces or commas. + + "accel" + "meta,shift" + "control alt" + + See the [MDN documentation on the modifiers + attribute](https://developer.mozilla.org/en/XUL/Attribute/modifiers) for a + full list of acceptable values. + +@prop onCommand {function} + A function that is invoked when the hotkey is pressed. +</api> + +</api> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/data/test.user.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/data/test.user.js @@ -0,0 +1,6 @@ +// ==UserScript== +// @name test +// @namespace test +// @include http://erikvold.com/* +// @exclude *google* +// ==/UserScript== diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/lib/main.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/lib/main.js @@ -0,0 +1,11 @@ + +var scripts = [ "test.user.js"]; + +var self = require("self"); +var {UserScript} = require("userscript"); + +exports.main = function() { + scripts.forEach(function(scriptName, index) { + var script = UserScript(self.data.url(scriptName)); + }); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/package.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/examples/test/package.json @@ -0,0 +1,8 @@ +{ + "name": "test", + "fullName": "test", + "author": "Erik Vold <erikvvold@gmail.com>", + "id": "superbgwo@erikvold.com", + "version": "0.0.1", + "dependencies": ["addon-kit", "api-utils", "userscripts", "vold-utils"] +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/folder.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/folder.js @@ -0,0 +1,51 @@ +'use strict'; + +const JETPACK_DIR_BASENAME = "jetpack"; +const PATH_TEST = /^[\s\.\\\/]/; + +const { Cc, Ci } = require('chrome'); +const file = require('sdk/io/file'); +const jpSelf = require('sdk/self'); + +let storeFile = Cc['@mozilla.org/file/directory_service;1'] + .getService(Ci.nsIProperties) + .get('ProfD', Ci.nsIFile); +storeFile.append(JETPACK_DIR_BASENAME); +storeFile.append(jpSelf.id); +storeFile.append('addon-folder'); + +const ADDON_FOLDER_PATH = storeFile.path + '/'; + +// make the addon-folder container folder +file.mkpath(ADDON_FOLDER_PATH); + +function ioFileWrap(funcName, preMode) { + preMode = preMode || ""; + return function(filepath, mode) { + filepath = filepath || ''; + if (PATH_TEST.test(filepath)) { + throw 'The provided filepath "' + filepath + '"" is not valid'; + } + return file[funcName](ADDON_FOLDER_PATH + filepath, preMode + mode); + } +} +exports.isFile = ioFileWrap('isFile'); +exports.exists = ioFileWrap('exists'); + +exports.remove = function(filepath) { + if (exports.isFile(filepath)) { + file.remove(ADDON_FOLDER_PATH + filepath); + } + else { + file.rmdir(ADDON_FOLDER_PATH + filepath); + } +}; +exports.read = ioFileWrap('read'); +exports.write = ioFileWrap('open', 'w'); +exports.mkpath = ioFileWrap('mkpath'); +exports.list = ioFileWrap('list'); + +exports.destroy = function destroy() { + // remove the addon-folder container folder + file.rmdir(ADDON_FOLDER_PATH); +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/unload.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/addon/unload.js @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Class } = require("sdk/core/heritage"); +const unloadNS = require("sdk/core/namespace").ns(); +const { when: unload } = require("sdk/system/unload"); + +var Unloader = exports.Unloader = Class({ + initialize: function Unloader() { + unloadNS(this).unloaders = []; + unloadNS(this).unloadersUnload = unloadersUnload.bind(null, unloadNS(this).unloaders); + + // run the unloaders on unload + unload(unloadNS(this).unloadersUnload); + }, + unload: function unload(callback, container) { + // Calling with no arguments runs all the unloader callbacks + if (callback == null) { + unloadNS(this).unloadersUnload(); + return null; + } + + let windowRemover = windowUnloader.bind(null, unloader, unloadNS(this).unloaders); + + // The callback is bound to the lifetime of the container if we have one + if (container != null) { + // Remove the unloader when the container unloads + container.addEventListener("unload", windowRemover, false); + + // Wrap the callback to additionally remove the unload listener + let origCallback = callback; + callback = function() { + container.removeEventListener("unload", windowRemover, false); + origCallback(); + } + } + + // Wrap the callback in a function that ignores failures + function unloader() { + try { + callback(); + } + catch(e) { + console.error(e); + } + } + unloadNS(this).unloaders.push(unloader); + + // Provide a way to remove the unloader + return removeUnloader.bind(null, unloader, unloadNS(this).unloaders); + } +}); + +function sliceUnloader(unloader, unloaders) { + let index = unloaders.indexOf(unloader); + if (index < 0) + return []; + return unloaders.splice(index, 1); +} +// wraps sliceUnloader and doesn't return anything +function removeUnloader(unloader, unloaders) { + sliceUnloader.apply(null, arguments); +} +function windowUnloader(unloader, unloaders) { + sliceUnloader.apply(null, arguments).forEach(function(u) u()); +} +function unloadersUnload(unloaders) { + // run all the pending unloaders + unloaders.slice().forEach(function(u) u()); + // clear the unload array + unloaders.length = 0; +} + +/** + * Save callbacks to run when unloading. Optionally scope the callback to a + * container, e.g., window. Provide a way to run all the callbacks. + * + * @usage unload(): Run all callbacks and release them. + * + * @usage unload(callback): Add a callback to run on unload. + * @param [function] callback: 0-parameter function to call on unload. + * @return [function]: A 0-parameter function that undoes adding the callback. + * + * @usage unload(callback, container) Add a scoped callback to run on unload. + * @param [function] callback: 0-parameter function to call on unload. + * @param [node] container: Remove the callback when this container unloads. + * @return [function]: A 0-parameter function that undoes adding the callback. + */ +const gUnload = Unloader(); +exports.unload = gUnload.unload.bind(gUnload); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/addon.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/addon.js @@ -0,0 +1,80 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const {Cc, Ci, Cu} = require("chrome"); +const {AddonManager, AddonAuthor} = require("../utils/addonmanager"); +const DO_NOTHING = function(){}; + +// https://developer.mozilla.org/en/Addons/Add-on_Manager/Addon +function Addon(options) { + + this.appDisabled = !!options.appDisabled || false; + this.blocklistState = (options.blocked) ? 2 : 0; + if (options.creator) { + this.creator = new AddonAuthor(options.creator.name); + } + this.id = options.id; + if (typeof options.isActive != "undefined") this.isActive = !!options.isActive; + if (typeof options.isCompatible != "undefined") this.isCompatible = !!options.isCompatible; + if (typeof options.isPlatformCompatible != "undefined") this.isPlatformCompatible = !!options.isPlatformCompatible; + this.name = options.name || ""; + //this.pendingOperations = + this.description = options.description || ""; + if (options.iconURL) this.iconURL = options.iconURL; + + // METHODS + this.uninstall = function() { + options.uninstall && options.uninstall(); + }; + this.cancelUninstall = function() { + options.cancelUninstall && options.cancelUninstall(); + }; + + if (options.getResourceURI) { + this.getResourceURI = function(aPath) { + return options.getResourceURI(aPath); + }; + this.getXPI = function() { + return options.getResourceURI("").QueryInterface(Ci.nsIFileURL).file; + } + } + + return this; +}; + +Addon.prototype = { + // req'd + appDisabled: false, + blocklistState: 0, + creator: null, + id: null, + isActive: true, + isCompatible: true, + isPlatformCompatible: true, + name: null, + pendingOperations: AddonManager.PENDING_NONE, + permissions: AddonManager.PERM_CAN_UNINSTALL, + providesUpdatesSecurely: false, + scope: AddonManager.SCOPE_PROFILE, + type: null, + userDisabled: false, + version: null, + + //not reqd + applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE, + contributors: [], + description: "", + translators: [], + sourceURI: null, + + + // METHODS + uninstall: DO_NOTHING, + findUpdates: DO_NOTHING, + cancelUninstall: DO_NOTHING, + hasResource: DO_NOTHING +}; + +exports.Addon = Addon; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/manager.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/manager.js @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const {AddonManager, AddonManagerPrivate} = require("../utils/addonmanager"); +const Addon = require("addon").Addon; + +exports.getAddonByID = exports.getAddonById = function(aID, aCallback) { + // get the addon obj + AddonManager.getAddonByID(aID, function (addon) { + // return a wrapped addon + aCallback(new Addon(addon)); + }); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/provider.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/aom/provider.js @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const unload = require("sdk/system/unload").when; + +const {AddonManager, AddonManagerPrivate, AddonType} = require("../utils/addonmanager"); + +var defaultUIPriority = 6001; // this increases when it is used + +exports.AddonProvider = function(options) { + var types = null; + + // AddonManagerPrivate.AddonType DNE in Gecko (FF) < 6 + if (AddonType) { + types = [new AddonType( + options.type, // TODO: RANDOMIZE? + null, + options.localeKey, + AddonManager.VIEW_TYPE_LIST, + options.uiPriority || defaultUIPriority++)]; + } + + var provider = { + getAddonByID: function(aId, aCallback) { + aCallback(options.getAddonByID(aId)); + }, + + getAddonsByTypes: function(aTypes, aCallback) { + if (aTypes && aTypes.indexOf(options.type) < 0) { + // not the right type, return nothing + aCallback([]); + } + else { + // the right type, return all addons + aCallback(options.getAddons()); + } + }, + + getInstallsByTypes: function(aTypes, aCallback) { + aCallback([]); + } + }; + AddonManagerPrivate.registerProvider(provider, types); + + unload(function() { + AddonManagerPrivate.unregisterProvider(provider); + }); + + return this; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/application/restart.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/application/restart.js @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci } = require("chrome"); + +exports.restart = function restart() { + let canceled = Cc["@mozilla.org/supports-PRBool;1"] + .createInstance(Ci.nsISupportsPRBool); + + Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService) + .notifyObservers(canceled, "quit-application-requested", "restart"); + + if (canceled.data) return false; // somebody canceled our quit request + + // restart + Cc['@mozilla.org/toolkit/app-startup;1'].getService(Ci.nsIAppStartup) + .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart); + + return true; +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/instances.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/instances.js @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci, Cu } = require("chrome"); + +var Instances = exports.Instances = { + get bis() Cc["@mozilla.org/binaryinputstream;1"] + .createInstance(Ci.nsIBinaryInputStream), + get ch() Cc["@mozilla.org/security/hash;1"] + .createInstance(Ci.nsICryptoHash), + get dp() Cc["@mozilla.org/xmlextras/domparser;1"] + .createInstance(Ci.nsIDOMParser), + get ds() Cc["@mozilla.org/xmlextras/xmlserializer;1"] + .createInstance(Ci.nsIDOMSerializer), + get fos() Cc["@mozilla.org/network/file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream), + get sfos() Cc["@mozilla.org/network/safe-file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream) + .QueryInterface(Ci.nsISafeOutputStream), + get fp() Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker), + get lf() Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile), + get process() Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess), + get se() Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError) + .QueryInterface(Ci.nsIScriptError2), + get ss() Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString), + get suc() Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter), + get timer() Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer), + get wbp() Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist), + get xhr() Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Ci.nsIXMLHttpRequest) +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/net-utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/net-utils.js @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +require("chrome").Cu.import("resource://gre/modules/NetUtil.jsm", this); +exports.NetUtil = NetUtil; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/services.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/services.js @@ -0,0 +1,57 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci, Cu } = require("chrome"); +Cu.import("resource://gre/modules/Services.jsm", this); + +const global = this; +var Services = exports.Services = {}; +(function(inc, tools){ + inc("resource://gre/modules/XPCOMUtils.jsm", global); + inc("resource://gre/modules/Services.jsm", tools); + Services.__proto__ = tools.Services; +})(Cu.import, {}); + +XPCOMUtils.defineLazyServiceGetter( + Services, "as", "@mozilla.org/alerts-service;1", "nsIAlertsService"); + +XPCOMUtils.defineLazyServiceGetter( + Services, "ass", "@mozilla.org/appshell/appShellService;1", + "nsIAppShellService"); + +XPCOMUtils.defineLazyServiceGetter( + Services, "cb", "@mozilla.org/widget/clipboardhelper;1", + "nsIClipboardHelper"); + +XPCOMUtils.defineLazyServiceGetter( + Services, "cs", "@mozilla.org/consoleservice;1", "nsIConsoleService"); + +XPCOMUtils.defineLazyServiceGetter( + Services, "eps", "@mozilla.org/uriloader/external-protocol-service;1", + "nsIExternalProtocolService"); + +if (Cc["@mozilla.org/privatebrowsing;1"]) { + XPCOMUtils.defineLazyServiceGetter( + Services, "pbs", "@mozilla.org/privatebrowsing;1", + "nsIPrivateBrowsingService"); +} else { + Services.pbs = {privateBrowsingEnabled: false}; +} + +XPCOMUtils.defineLazyServiceGetter( + Services, "sis", "@mozilla.org/scriptableinputstream;1", + "nsIScriptableInputStream"); + +XPCOMUtils.defineLazyServiceGetter( + Services, "suhtml", "@mozilla.org/feed-unescapehtml;1", + "nsIScriptableUnescapeHTML"); + +XPCOMUtils.defineLazyServiceGetter( + Services, "tld", "@mozilla.org/network/effective-tld-service;1", + "nsIEffectiveTLDService"); + +XPCOMUtils.defineLazyServiceGetter( + Services, "uuid", "@mozilla.org/uuid-generator;1", + "nsIUUIDGenerator"); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/xpcom-utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/chrome/xpcom-utils.js @@ -0,0 +1,3 @@ + +require("chrome").Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); +exports.XPCOMUtils = XPCOMUtils; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/events.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/events.js @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const events = require('sdk/system/events'); +const { on, once, off, emit } = require('sdk/event/core'); + +function onRequest(evt) { + emit(exports, 'modify-request', evt); +} +events.on('http-on-modify-request', onRequest); + +/* +function onResponse(evt) { + emit(exports, 'examine-response', evt); +} +events.on('http-on-examine-response', onResponse); +*/ + +exports.on = on.bind(null, exports); +exports.once = once.bind(null, exports); +exports.off = off.bind(null, exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/request.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/request.js @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Ci } = require('chrome'); +const { List, addListItem, removeListItem } = require('sdk/util/list'); +const { ns } = require('sdk/core/namespace'); +const { Class } = require('sdk/core/heritage'); +const { Disposable } = require('sdk/core/disposable'); + +const events = require('./events'); + +const REQUEST_RULES = List(); +const requestNS = ns(); + +function onRequest(evt) { + for each (let rule in REQUEST_RULES) { + applyRequestHeaders(rule, evt) + } +} +events.on('modify-request', onRequest); + +const RequestRule = Class({ + implements: [ Disposable ], + initialize: function(details) { + requestNS(this).details = details; + addListItem(REQUEST_RULES, this); + }, + dispose: function() { + removeListItem(REQUEST_RULES, this); + } +}); +exports.RequestRule = RequestRule; + +function applyRequestHeaders(rule, evt) { + let channel = evt.subject.QueryInterface(Ci.nsIHttpChannel); + let requestURL = channel.URI.spec + + let details = requestNS(rule).details; + let { headers: rules } = details; + for each (let key in Object.keys(rules)) { + channel.setRequestHeader(key, rules[key] + '', false); + } +} +\ No newline at end of file diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/response.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connection/response.js @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Ci } = require('chrome'); +const { List, addListItem, removeListItem } = require('sdk/util/list'); +const { ns } = require('sdk/core/namespace'); +const { Class } = require('sdk/core/heritage'); + +const events = require('./events'); + +const RESPONSE_RULES = List(); + +const requestNS = ns(); + +function onResponse(evt) { + for each (let rule in RESPONSE_RULES) { + applyResponseHeaders(rule, evt) + } +} +events.on('examine-response', onResponse); + +const ResponseRule = Class({ + initialize: function(details) { + requestNS(this).details = details; + addListItem(RESPONSE_RULES, this); + }, + destroy: function() { + removeListItem(RESPONSE_RULES, this); + } +}); +exports.ResponseRule = ResponseRule; + +function applyResponseHeaders(rule, evt) { + let channel = evt.subject.QueryInterface(Ci.nsIHttpChannel); + let requestURL = channel.URI.spec + + let details = requestNS(rule).details; + let { headers: rules } = details; + for each (let key in Object.keys(rules)) { + channel.setResponseHeader(key, rules[key], false); + } +} +\ No newline at end of file diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connections.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/connections.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +exports.RequestRule = require('./connection/request').RequestRule; +//exports.ResponseRule = require('./connection/response').ResponseRule; + diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/permissions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/permissions.js @@ -0,0 +1,88 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci, Cu } = require('chrome'); +const { List, addListItem } = require('sdk/util/list'); +const { URL } = require('sdk/url'); + +const { Services } = require('../chrome/services'); + +const { nsIPermissionManager } = Ci; + +const UNKNOWN = nsIPermissionManager.UNKNOWN_ACTION; // 0 +const ALLOW = nsIPermissionManager.ALLOW_ACTION; // 1 +const BLOCK = nsIPermissionManager.DENY_ACTION; // 2 +const SESSION = Ci.nsICookiePermission.ACCESS_SESSION; // 8 + +function getKey(obj, val) { + for (let key in obj) + if (obj[key] == val) + return key; + + return undefined; +} + +const PERMISSIONS = { + 'session': SESSION, + 'allow': ALLOW, + 'deny': BLOCK +}; + +const TYPES = { + 'images': 'image', + 'popups': 'popup', + 'desktop-notifications': 'desktop-notification', + 'installs': 'install', + 'location': 'geo', + 'fullscreen': 'fullscreen', + 'pointer-lock': 'pointerLock' +} + +const PM = Cc['@mozilla.org/permissionmanager;1']. + getService(nsIPermissionManager); + +function add(options) { + let uri = Services.io.newURI(options.url, null, null); + if (!/^https?/.test(uri.scheme)) { + throw new Error('invalid content url, only https or http schemes are accepted'); + } + + PM.add(uri, + TYPES[options.type], + PERMISSIONS[options.permission]); +} + +function remove(options) { + PM.remove(URL(options.url).host, TYPES[options.type]); +} + +function removeAll() { + PM.removeAll(); +} + +// TODO: cache entries after first request, and observe new additions with the "perm-changed" event + +exports.permissions = { + add: add, + remove: remove, + removeAll: removeAll, + get permissions() { + let list = List(); + let permissions = PM.enumerator; + while (permissions.hasMoreElements()) { + let permission = permissions.getNext().QueryInterface(Ci.nsIPermission); + + addListItem(list, { + type: getKey(TYPES, permission.type), + host: String(permission.host), + permission: getKey(PERMISSIONS, Number(permission.capability)) + //'expire-time': Number(permission.expireTime), + }); + } + return list; + }, + TYPES: TYPES, + PERMISSIONS: PERMISSIONS +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/policy.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/content/policy.js @@ -0,0 +1,143 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci } = require('chrome'); +const { Class } = require('sdk/core/heritage'); +const CP_NS = require('sdk/core/namespace').ns(); +const { ensure } = require('sdk/system/unload'); +const { validateOptions } = require('sdk/deprecated/api-utils'); +const { id: ADDON_ID } = require('sdk/self'); +const xpcom = require('sdk/platform/xpcom'); + +const CM = Cc["@mozilla.org/categorymanager;1"] + .getService(Ci.nsICategoryManager); + +const ACCEPT = exports.ACCEPT = Ci.nsIContentPolicy.ACCEPT; +const REJECT = exports.REJECT = Ci.nsIContentPolicy.REJECT_REQUEST; + +const accept = function() ACCEPT; + +let ContentPolicy_ID = 0; + +const RULES = { + description: { + map: function(v) { + return v ? v : ''; + }, + is: ['string'] + }, + contract: { + map: function(v) { + if (v === undefined) { + v = '@erikvold.com/content-policy.' + ADDON_ID + ';' + ContentPolicy_ID++; + } + return v; + }, + is: ['string'] + }, + entry: { + is: ['string', 'undefined'] + }, + shouldLoad: { + is: ['function', 'undefined'] + }, + shouldProcess: { + is: ['function', 'undefined'] + }, +}; + +function getType(aType) { + switch (aType) { + case Ci.nsIContentPolicy.TYPE_SCRIPT: + return 'script'; + case Ci.nsIContentPolicy.TYPE_IMAGE: + return 'image'; + case Ci.nsIContentPolicy.TYPE_STYLESHEET: + return 'stylesheet'; + case Ci.nsIContentPolicy.TYPE_OBJECT: + return 'object'; + case Ci.nsIContentPolicy.TYPE_DOCUMENT: + return 'document'; + case Ci.nsIContentPolicy.TYPE_SUBDOCUMENT: + return 'subdocument'; + case Ci.nsIContentPolicy.TYPE_REFRESH: + return 'refresh'; + case Ci.nsIContentPolicy.TYPE_XBL: + return 'xbl'; + case Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST: + return 'xhr'; + case Ci.nsIContentPolicy.TYPE_PING: + return 'ping'; + // TODO: support more types + } + return 'other'; +} +const getTypeMemod = memoize(getType, 12, 1); + +function makeDetails(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess) { + return { + type: getTypeMemod(aContentType), + location: aContentLocation.spec, + origin: aRequestOrigin.spec, + context: null, // TODO: support this in a safe way somehow.. + mimeTypeGuess: String(aMimeTypeGuess) + }; +} + +let ContentPolicy = exports.ContentPolicy = Class({ + initialize: function(options) { + const self = this; + options = CP_NS(self).options = validateOptions(options, RULES); + CP_NS(self).shouldLoad = options.shouldLoad || accept; + CP_NS(self).shouldProcess = options.shouldProcess || accept; + + let factory = CP_NS(this).factory = xpcom.Factory({ + Component: getProvider(self), + description: options.description, + contract: options.contract + }); + + let entry = options.entry || options.contract; + CM.addCategoryEntry('content-policy', entry, factory.contract, false, true); + ensure(this, 'destroy'); + }, + destroy: function() { + // already destroyed? + if (!CP_NS(this).options) + return; + + let options = CP_NS(this).options; + CP_NS(this).options = null; + CP_NS(this).shouldLoad = accept; + CP_NS(this).shouldProcess = accept; + + CM.deleteCategoryEntry('content-policy', options.entry || options.contract, false); + } +}); + +function getProvider(self) { + return Class({ + extends: xpcom.Unknown, + interfaces: ['nsIContentPolicy'], + shouldLoad: function (aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aExtra) { + let load = CP_NS(self).shouldLoad(makeDetails.apply(null, arguments)); + return (load == REJECT || (!load && load !== undefined)) ? REJECT : ACCEPT; + }, + shouldProcess: function (aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aExtra) { + let load = CP_NS(self).shouldProcess(makeDetails.apply(null, arguments)); + return (load == REJECT || (!load && load !== undefined)) ? REJECT : ACCEPT; + } + }); +} + +function memoize(func) { + let cache = Object.create(null); + return function(a) { + let key = a.toString(); + if (key in cache) + return cache[key]; + return cache[key] = func.call(null, a); + }; +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/devtools/gcli.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/devtools/gcli.js @@ -0,0 +1,23 @@ +'use strict'; + +const { Cu } = require('chrome'); +const { when: unload } = require('unload'); + +try { + // Starting with FF 23, gcli.jsm moved to another location + Cu.import("resource://gre/modules/devtools/gcli.jsm"); +} catch(e) { + try { + Cu.import("resource:///modules/devtools/gcli.jsm"); + } catch(e) { + console.error("Unable to load gcli.jsm"); + } +} + +function addCommand(cmd) { + let name = cmd.name; + gcli.addCommand(cmd); + unload(gcli.removeCommand.bind(gcli, name)); +} +exports.addCommand = addCommand; +exports.removeCommand = gcli.removeCommand; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/download.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/download.js @@ -0,0 +1,95 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Ci, Cc, Cu } = require('chrome'); +const { Class } = require('sdk/core/heritage'); +const { on, off, emit, setListeners } = require('sdk/event/core'); +const { EventTarget } = require("sdk/event/target"); +const { ns } = require("sdk/core/namespace"); +const { validateOptions } = require("sdk/deprecated/api-utils"); +const { isValidURI } = require("sdk/url"); + +const PROGRESS_LISTENER_NS = ns(); + +const { Services } = Cu.import('resource://gre/modules/Services.jsm', {}); + +const rules = { + url: { + // Also converts a URL instance to string, bug 857902 + map: function (url) url.toString(), + ok: isValidURI + }, + destination: { + is: ['string'] + } +}; + +const Download = Class({ + extends: EventTarget, + initialize: function(options) { + // Setup listeners. + setListeners(this, options); + + options = validateOptions(options, rules); + + const wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist); + let listener = ProgressListener({ + download: this + }); + + wbp.progressListener = listener; + + let localFile = Cc["@mozilla.org/file/local;1"] + .createInstance(Ci.nsILocalFile); + localFile.initWithPath(options.destination); + localFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8)); + localFile = localFile.QueryInterface(Ci.nsIFile); + + let uri = Services.io.newURI(options.url, null, null); + wbp.saveURI(uri, null, null, null, null, localFile, null); + } +}); +exports.Download = Download; + +const ProgressListener = Class({ + initialize: function(options) { + const internals = PROGRESS_LISTENER_NS(this); + internals.options = options; + this.onStateChange = this.onStateChange.bind(this); + }, + get options() PROGRESS_LISTENER_NS(this).options, + get download() this.options.download, + onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) { + }, + onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) { + emit(this.download, 'progress', { + current: aCurTotalProgress, + total: aMaxTotalProgress + }) + }, + onSecurityChange: function(aWebProgress, aRequest, aState) { + }, + onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) { + if (!(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP)) + return; + + try { + var { responseStatus, requestSucceeded } = aRequest.QueryInterface(Ci.nsIHttpChannel); + } + catch (e) { + //console.exception(e); + } + + emit(this.download, 'complete', { + responseStatus: responseStatus, + requestSucceeded: requestSucceeded + }); + + return; + }, + onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) { + } +}); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/l10n.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/l10n.js @@ -0,0 +1,76 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const global = this; +const {Cc,Ci,Cu} = require("chrome"); +Cu.import("resource://gre/modules/Services.jsm", global); + +exports.locale = Cc["@mozilla.org/chrome/chrome-registry;1"] + .getService(Ci.nsIXULChromeRegistry).getSelectedLocale("global"); + +exports.l10n = (function(global) { + let splitter = /(\w+)-\w+/; + + // get user's locale + let locale = exports.locale; + + function getStr(aStrBundle, aKey) { + if (!aStrBundle) return false; + try { + return aStrBundle.GetStringFromName(aKey); + } catch (e) { + //console.log(e); + } + return ""; + } + + function l10n(options) { + var filename = options.filename; + var baseURL = options.baseURL; + var defaultLocale = options.defaultLocale || "en"; + function filepath(locale) { + var path = baseURL + "/" + locale + "/" + filename; + //console.log(path); + return path; + } + + let defaultBundle = Services.strings.createBundle(filepath(locale)); + + let defaultBasicBundle; + let (locale_base = locale.match(splitter)) { + if (locale_base) { + defaultBasicBundle = Services.strings.createBundle( + filepath(locale_base[1])); + } + } + + let addonsDefaultBundle = + Services.strings.createBundle(filepath(defaultLocale)); + + return _ = function l10n_underscore(aKey, aLocale) { + let localeBundle, localeBasicBundle; + if (aLocale) { + localeBundle = Services.strings.createBundle(filepath(aLocale)); + + let locale_base = aLocale.match(splitter) + if (locale_base) + localeBasicBundle = Services.strings.createBundle( + filepath(locale_base[1])); + } + + var x = getStr(localeBundle, aKey) + || getStr(localeBasicBundle, aKey) + || getStr(defaultBundle, aKey) + || getStr(defaultBasicBundle, aKey) + || getStr(addonsDefaultBundle, aKey); + return x; + } + } + + return l10n; +})(this); + +require("unload").when(Services.strings.flushBundles); + diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/panic.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/panic.js @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { setTimeout } = require('sdk/timers'); +const { get, set } = require('sdk/preferences/service'); +const { add, notify } = require('sdk/deprecated/observer-service'); +const { on, once, emit, off } = require('sdk/event/core'); +const { loadReason } = require('sdk/self'); + +const { unload } = require('./addon/unload'); + +const PREF_NAME = 'security.addon.panic'; +function inPanic() get(PREF_NAME, false); +function setPanic(value) set(PREF_NAME, value); + +const PREF_END_NAME = 'security.addon.panic_end'; +function getEndTime() get(PREF_END_NAME, 0) * 1; +function setEndTime(timestamp) set(PREF_END_NAME, timestamp + ""); + +Object.defineProperty(exports, "inPanic", { + get: function() inPanic() +}); + +const panic = function (ms) { + ms = ms || 0; + let endTime = Date.now() + ms; + + // check that the current end timestamp is not greater + if (getEndTime() >= endTime) + return; + + // set the end timestamp (to handle the reboot situation) + setEndTime(endTime); + + // notify system of a panic + notify('panic-start'); + + // end the panic + setTimeout(function() { + // check that the end timestamp was not extended by another panic + // NOTE: another instance of panic module could have caused the old panic + if (getEndTime() != endTime) return; + + notify('panic-end'); + }, ms); +}; +exports.panic = panic; + +// internal object used to emit on, instead of `exports`, so that outside code +// cannot emit on this object. +const panicEmitter = {}; + +// create and expose event listener related methods for this module +exports.on = on.bind(null, panicEmitter); +exports.once = once.bind(null, panicEmitter); +exports.off = off.bind(null, panicEmitter); + +// listen to 'panic-start' events in the observer-service since they may come +// from other instances of this module +add('panic-start', function () { + setPanic(true); + emit(panicEmitter, 'start'); +}); +// listen to 'panic-end' events for the same reason as for 'panic-start' +add('panic-end', function () { + setPanic(false); + emit(panicEmitter, 'end'); +}); + +// cleanup prefs on startup, since the add-on could be installed before or +// during startup +if (loadReason == 'startup') { + // check the end timestamp (for the reboot situation) + if (getEndTime() <= Date.now()) { + setEndTime(0); + + if (inPanic()) { + setPanic(false); + } + } +} + +// clean up prefs on shutdown, don't do cleanup on other reasons because there +// may be other instances of the module running +unload(function(reason) { + if (reason == 'shutdown') { + setPanic(false); + setEndTime(0); + } +}); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/redirect.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/redirect.js @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Ci } = require('chrome'); +const { List, addListItem, removeListItem } = require('sdk/util/list'); +const { ns } = require('sdk/core/namespace'); +const { Class } = require('sdk/core/heritage'); +const { Disposable } = require('sdk/core/disposable'); +const { newURI } = require('sdk/url/utils'); + +const events = require('./connection/events'); + +const REDIRECTS = List(); +const requestNS = ns(); + +function onRequest({ subject }) { + let channel = subject.QueryInterface(Ci.nsIHttpChannel); + for each (let redirect in REDIRECTS) + if (applyRedirect(redirect, channel)) + break; + return; +} +events.on('modify-request', onRequest); + +const Redirect = Class({ + implements: [ Disposable ], + initialize: function(details) { + details.to = newURI(details.to.toString()); + requestNS(this).details = details; + + addListItem(REDIRECTS, this); + }, + dispose: function() { + removeListItem(REDIRECTS, this); + }, + get from() requestNS(this).details.from, + get to() requestNS(this).details.to.spec +}); +exports.Redirect = Redirect; + +function applyRedirect(redirect, channel) { + let { from, to } = requestNS(redirect).details; + + if (channel.URI.spec == from) { + channel.redirectTo(to); + // emit(rule, 'redirect', {}); + return true; + } + return false; +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/about.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/about.js @@ -0,0 +1,84 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cr, Cu, Ci, Cc, Cm } = require('chrome'); +const { when: unload } = require('sdk/system/unload'); +const { validateOptions : validate } = require('sdk/deprecated/api-utils'); +const { uuid } = require('sdk/util/uuid'); +const { URL, isValidURI } = require('sdk/url'); +const tabs = require('sdk/tabs'); + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const validOptions = { + what: { + is: ['string'], + ok: function(what) { + if (what.match(/^[a-z0-9-]+$/i)) + return true; + return false; + }, + map: function(url) url.toLowerCase() + }, + url: { + map: function(url) url.toString(), + ok: isValidURI + }, + useChrome: { + is: ['undefined', 'null', 'boolean'], + map: function(use) !!use + } +}; + +function add(options) { + let { what, url, useChrome } = validate(options, validOptions); + let classID = uuid(); + + let aboutModule = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]), + newChannel: function (aURI) { + let chan = Services.io.newChannel(url, null, null); + if (useChrome) + chan.owner = Services.scriptSecurityManager.getSystemPrincipal(); + return chan; + }, + getURIFlags: function () Ci.nsIAboutModule.ALLOW_SCRIPT + }; + + let factory = { + createInstance: function(aOuter, aIID) { + if (aOuter) + throw Cr.NS_ERROR_NO_AGGREGATION; + return aboutModule.QueryInterface(aIID); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]) + }; + + // register about:what + Cm.QueryInterface(Ci.nsIComponentRegistrar). + registerFactory(classID, '', '@mozilla.org/network/protocol/about;1?what='+what, factory); + + let remover = unloader.bind(null, what, factory, classID); + unload(remover); + + return undefined; +} +exports.add = add; + +function unloader(what, factory, classID) { + // unregister about:what + Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(classID, factory); + let regEx = new RegExp('^' + what, 'i'); + + // AMO policy, see http://maglione-k.users.sourceforge.net/bootstrapped.xhtml + // close about:what tabs + for each (let tab in tabs) { + let url = URL(tab.url); + if (url.scheme === 'about' && url.path.match(regEx)) { + tab.close(); + } + } +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/resource.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/scheme/resource.js @@ -0,0 +1,43 @@ +/*jshint asi:true globalstrict:true*/ +'use strict'; + +const { Cc, Ci } = require('chrome') +const ioService = Cc['@mozilla.org/network/io-service;1']. + getService(Ci.nsIIOService); +const resourceHandler = ioService.getProtocolHandler('resource'). + QueryInterface(Ci.nsIResProtocolHandler) + +function get(root) { + /** + Gets the substitution for the `root` key. + **/ + try { + return resourceHandler.getSubstitution(root).spec; + } + catch (error) {} + return null; +} +exports.get = get; + +function has(root) { + /** + Returns `true` if the substitution exists and `false` otherwise. + **/ + return resourceHandler.hasSubstitution(root); +} +exports.has = has; + +function set(root, uri) { + /** + Sets the substitution for the root key: + + resource://root/path ==> baseURI.resolve(path) + + A `null` `uri` removes substitution. A root key should + always be lowercase. However, this may not be enforced. + **/ + uri = !uri ? null : + uri instanceof Ci.nsIURI ? uri : ioService.newURI(uri, null, null); + resourceHandler.setSubstitution(root, uri); +} +exports.set = set; 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/storage.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/storage.js @@ -0,0 +1,126 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci, Cu, components } = require('chrome'); +const { id } = require('sdk/self'); +const unload = require('sdk/system/unload'); +const { defer } = require('sdk/core/promise'); + +const { Instances } = require('./chrome/instances'); +const { Services } = require('./chrome/services'); +const { NetUtil } = require('./chrome/net-utils'); + +const { FileUtils } = Cu.import('resource://gre/modules/FileUtils.jsm', {}); + +const JETPACK_DIR_BASENAME = "jetpack"; + +let saving = false; + +function getStorageFile() { + const file = Services.dirsvc.get('ProfD', Ci.nsIFile); + file.append(JETPACK_DIR_BASENAME); + file.append(id); + file.append('pathfinder'); + file.append('storage'); + + if (!file.exists()) + file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0755', 8)); + + file.append('storage.blob'); + return file; +} + +function get(options) { + options = options || {}; + let charset = options.charset || 'UTF-8'; + + const { promise, resolve } = defer(); + const file = getStorageFile(); + const channel = NetUtil.newChannel(file); + + if (!file.exists()) { + resolve({ data: '' }); + } + else { + NetUtil.asyncFetch(channel, function(iStream, aResult) { + if (!components.isSuccessCode(aResult)) { + reject(); + } + else { + let text = NetUtil.readInputStreamToString(iStream, iStream.available()); + + let conv = Instances.suc; + conv.charset = charset; + + text = conv.ConvertToUnicode(text); + + resolve({ + data: text, + charset: charset + }); + } + }); + } + + return promise; +} +exports.get = get; + +function set({ data, charset }) { + charset = charset || 'UTF-8'; + data = data || ''; + const { promise, resolve, reject } = defer(); + const file = getStorageFile(); + + if (data == '') { + if (file.exists()) { + file.remove(false); + } + + resolve({ + data: '', + charset: charset + }); + } + else { + const converter = Instances.suc; + converter.charset = "UTF-8"; + + if (isSaving()) { + throw Error('Storage is currently in the process of saving..'); + } + saving = true; + + let iStream = converter.convertToInputStream(data); + let oStream = FileUtils.openSafeFileOutputStream(file); + + NetUtil.asyncCopy( + iStream, + oStream, + function(aResult) { + FileUtils.closeSafeFileOutputStream(oStream); + saving = false; + + if (!components.isSuccessCode(aResult)) { + reject(); + } + else { + resolve({ + data: data, + charset: charset + }); + } + } + ); + } + + return promise; +} +exports.set = set; + +function isSaving() { + return saving; +} +exports.isSaving = isSaving; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/awesomebar.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/awesomebar.js @@ -0,0 +1,205 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const {Cc, Ci, Cu, Cm, components} = require('chrome'); +Cu.import("resource://gre/modules/AddonManager.jsm", this); +Cu.import("resource://gre/modules/Services.jsm", this); +Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); + +var {unload} = require("../addon/unload"); +var {listen} = require("../xul/listen"); +var {watchWindows} = require("window-watcher"); +var {clearTimeout, setTimeout} = require("timer"); + +let handlers = []; + +// public api for adding a keyword and search handler +// TODO: validate, yo +exports.AwesomeBarSuggestion = function AwesomeBarSuggestion(options) { + var i = handlers.push(options) - 1; + var destroyed = false; + + return { + destroy: function() { + if (destroyed) return; + destroyed = true; + handlers[i] = null; + } + }; +}; + +// Bool check if a given string matches a given handler +function handlerMatch(query, handler) !!(handler && handler.matches.test(query)); + +// Get first registered handler that matches a given string +function getMatchingHandler(query) handlers.filter(function(handler) handlerMatch(query, handler)).shift() + +// Add functionality to search from the location bar and hook up autocomplete +function addAddressBarSearch(window) { + let {change} = makeWindowHelpers(window); + let {BrowserUI, gBrowser, gURLBar} = window; + + // Check the input to see if the add-on icon should be shown + // Called when the location bar fires the input event + function onLocationBarInput() { + if (skipCheck()) + return; + + let icon = ""; + let handler = getMatchingHandler(urlbar.value); + if (handler && handler.icon) + icon = handler.icon; + setIcon(icon); + } + + // Implement these functions depending on the platform + let setIcon, skipCheck, urlbar; + + // mobile + if (gBrowser == null) { + setIcon = function(url) BrowserUI._updateIcon(url); + skipCheck = function() false; + urlbar = BrowserUI._edit; + + // Check the input on various events + listen(window, BrowserUI._edit, "input", onLocationBarInput); + + // Convert inputs to twitter urls + change(window.Browser, "getShortcutOrURI", function(orig) { + return function(uri, data) { + return orig.call(this, uri, data); + }; + }); + } + // desktop + else { + setIcon = function(url) window.PageProxySetIcon(url); + skipCheck = function() gURLBar.getAttribute("pageproxystate") == "valid" && + !gURLBar.hasAttribute("focused"); + urlbar = gURLBar; + + // Check the input on various events + listen(window, gURLBar, "input", onLocationBarInput); + listen(window, gBrowser.tabContainer, "TabSelect", onLocationBarInput); + + // Convert inputs to twitter urls + change(gURLBar, "_canonizeURL", function(orig) { + return function(event) { + return orig.call(this, event); + }; + }); + } + + // Provide a way to set the autocomplete search engines and initialize + function setSearch(engines) { + urlbar.setAttribute("autocompletesearch", engines); + urlbar.mSearchNames = null; + urlbar.initSearchNames(); + }; + + // Add in the twitter search and remove on cleanup + let origSearch = urlbar.getAttribute("autocompletesearch"); + setSearch(require('self').id + " " + origSearch); + unload(function() setSearch(origSearch)); +} + +// Add an autocomplete search engine to provide location bar suggestions +function addAutocomplete() { + const contract = "@mozilla.org/autocomplete/search;1?name=" + require('self').id; + const desc = "Jetpack Autocomplete"; + const uuid = components.ID("504A8466-8D3D-11E0-A57E-D2F94824019B"); + + // Keep a timer to send a delayed no match + let timer; + function clearTimer() { + if (timer != null) + clearTimeout(timer); + timer = null; + } + + // call back in one second + function setTimer(callback) { + timer = setTimeout(callback, 1000); + } + + // Implement the autocomplete search that handles twitter queries + let search = { + createInstance: function(outer, iid) search.QueryInterface(iid), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch]), + + // Handle searches from the location bar + startSearch: function(query, param, previous, listener) { + + // Always clear the timer on a new search + clearTimer(); + + function suggest(o, done) { + listener.onSearchResult(search, { + getCommentAt: function() o.title, + getImageAt: function() o.favicon, + getLabelAt: function() o.label || o.url, + getValueAt: function() o.url, + getStyleAt: function() "favicon", + get matchCount() 1, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult]), + removeValueAt: function() {}, + searchResult: Ci.nsIAutoCompleteResult.RESULT_SUCCESS, + get searchString() query, + }); + } + + // TODO: if no search yet, but matched keyword, show example text + + // if there's a query string and a match + if (query.length) { + let handler = getMatchingHandler(query); + if (handler) { + if (query) { + handler.onSearch(query, suggest); + } + } + } + // Send a delayed NOMATCH so the autocomplete doesn't close early + else { + setTimer(function() { + listener.onSearchResult(search, { + searchResult: Ci.nsIAutoCompleteResult.RESULT_NOMATCH, + }); + }); + } + }, + + // Nothing to cancel other than a delayed search as results are synchronous + stopSearch: function() { + clearTimer(); + }, + }; + + // Register this autocomplete search service and clean up when necessary + const registrar = Ci.nsIComponentRegistrar; + Cm.QueryInterface(registrar).registerFactory(uuid, desc, contract, search); + unload(function() { + Cm.QueryInterface(registrar).unregisterFactory(uuid, search); + }); +} + +// Add support to the browser +watchWindows(addAddressBarSearch); +addAutocomplete(); + +// Take a window and create various helper properties and functions +function makeWindowHelpers(window) { + // Replace a value with another value or a function of the original value + function change(obj, prop, val) { + let orig = obj[prop]; + obj[prop] = typeof val == "function" ? val(orig) : val; + unload(function() obj[prop] = orig, window); + } + + return { + change: change, + }; +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/findbar/suggestion.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/findbar/suggestion.js @@ -0,0 +1,77 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const winUtils = require('sdk/deprecated/window-utils'); +const { Class } = require('sdk/core/heritage'); +const { validateOptions } = require('sdk/deprecated/api-utils'); +const { isBrowser } = require('sdk/window/utils'); +const { unload } = require('../../addon/unload'); +const { listen } = require('../../xul/listen'); + +const findsuggestionNS = require('sdk/core/namespace').ns(); +const NS_XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; + +function FindSuggestionOptions(options) { + return validateOptions(options, { + word: { is: ['string'] }, + //onClick: { is: ['undefined', 'function'] } + }); +} + +const FindSuggestion = Class({ + initialize: function(options) { + options = findsuggestionNS(this).options = FindSuggestionOptions(options); + let unloaders = findsuggestionNS(this).unloaders = []; + + winUtils.WindowTracker({ + onTrack: function(window) { + if (!isBrowser(window)) return; + + let findBar = window.gFindBar; + let findContainer = findBar.getElement('findbar-container'); + + // Show these suggestions in the findbar + let ele = window.document.createElementNS(NS_XUL, 'label'); + ele.setAttribute('value', options.word); + ele.style.margin = '2px'; + ele.style.cursor = 'pointer'; + ele.style.fontWeight = 'bold'; + findContainer.appendChild(ele); + + ele.addEventListener('click', suggestionClick.bind({ + findBar: findBar + }), false); + + // Clear out the suggestions when removing the add-on + function clearSuggestion() { + findContainer.removeChild(ele); + } + + // save a destroyer + unloaders.push( + destroyer.bind(null, unload(clearSuggestion, window), clearSuggestion)); + } + }); + }, + destroy: function() findsuggestionNS(this).unloaders.forEach(function(x) x()) +}); +exports.FindSuggestion = FindSuggestion; + +function suggestionClick(event) { + let suggestion = event.target.value; + let findField = this.findBar._findField; + + if (findField.value === suggestion) { + this.findBar.onFindAgainCommand(false); + } + else { + findField.value = suggestion; + findBar._find(); + } +} +function destroyer(remover, clearSuggestion) { + clearSuggestion(); + remover(); +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/menuitems.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/menuitems.js @@ -0,0 +1,218 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const windowUtils = require("sdk/deprecated/window-utils"); +const { Class } = require("sdk/core/heritage"); +const { validateOptions } = require("sdk/deprecated/api-utils"); +const { on, emit, once, off } = require("sdk/event/core"); +const { isBrowser } = require("sdk/window/utils"); +const { EventTarget } = require('sdk/event/target'); +const menuitemNS = require("sdk/core/namespace").ns(); + +const { unload } = require('../addon/unload'); + +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +function MenuitemOptions(options) { + return validateOptions(options, { + id: { is: ['string'] }, + menuid: { is: ['undefined', 'string'] }, + insertbefore: { is: ['undefined', 'string', 'object', 'number'] }, + label: { is: ["string"] }, + include: { is: ['string', 'undefined'] }, + disabled: { is: ["undefined", "boolean"], map: function(v) !!v}, + accesskey: { is: ["undefined", "string"] }, + key: { is: ["undefined", "string"] }, + checked: { is: ['undefined', 'boolean'] }, + className: { is: ["undefined", "string"] }, + onCommand: { is: ['undefined', 'function'] }, + useChrome: { map: function(v) !!v } + }); +} + +let Menuitem = Class({ + extends: EventTarget, + initialize: function(options) { + options = menuitemNS(this).options = MenuitemOptions(options); + EventTarget.prototype.initialize.call(this, options); + + menuitemNS(this).destroyed = false; + menuitemNS(this).unloaders = []; + menuitemNS(this).menuitems = addMenuitems(this, options).menuitems; + }, + get id() menuitemNS(this).options.id, + get label() menuitemNS(this).options.label, + set label(val) updateProperty(this, 'label', val), + get checked() menuitemNS(this).options.checked, + set checked(val) updateProperty(this, 'checked', !!val), + get disabled() menuitemNS(this).options.disabled, + set disabled(val) updateProperty(this, 'disabled', !!val), + get key() menuitemNS(this).options.key, + set key(val) updateProperty(this, 'key', val), + clone: function (overwrites) { + let opts = Object.clone(menuitemNS(this).options); + for (let key in overwrites) { + opts[key] = ovrewrites[key]; + } + return Menuitem(opts); + }, + get menuid() menuitemNS(this).options.menuid, + set menuid(val) { + let options = menuitemNS(this).options; + options.menuid = val; + + forEachMI(function(menuitem, i, $) { + updateMenuitemParent(menuitem, options, $); + }); + }, + destroy: function() { + if (!menuitemNS(this).destroyed) { + menuitemNS(this).destroyed = true; + menuitemNS(this).unloaders.forEach(function(u) u()); + menuitemNS(this).unloaders = null; + menuitemNS(this).menuitems = null; + } + return true; + } +}); + +function addMenuitems(self, options) { + let menuitems = []; + + // setup window tracker + windowUtils.WindowTracker({ + onTrack: function (window) { + if (menuitemNS(self).destroyed) return; + if (options.include) { + if (options.include != window.location) return; + } + else if (!isBrowser(window)) { + return; + } + + // add the new menuitem to a menu + var menuitem = updateMenuitemAttributes( + window.document.createElementNS(NS_XUL, "menuitem"), options); + var menuitems_i = menuitems.push(menuitem) - 1; + + // add the menutiem to the ui + let added = updateMenuitemParent(menuitem, options, function(id) window.document.getElementById(id)); + + menuitem.addEventListener("command", function() { + if (!self.disabled) + emit(self, 'command', options.useChrome ? window : null); + }, true); + + // add unloader + let unloader = function unloader() { + menuitem.parentNode && menuitem.parentNode.removeChild(menuitem); + menuitems[menuitems_i] = null; + }; + + menuitemNS(self).unloaders.push(function() { + remover(); + unloader(); + }); + + let remover = unload(unloader, window); + } + + }); + + return { menuitems: menuitems }; +} + +function updateMenuitemParent(menuitem, options, $) { + // add the menutiem to the ui + if (Array.isArray(options.menuid)) { + let ids = options.menuid; + for (var len = ids.length, i = 0; i < len; i++) { + if (tryParent($(ids[i]), menuitem, options.insertbefore)) + return true; + } + } + else { + return tryParent($(options.menuid), menuitem, options.insertbefore); + } + + return false; +} + +function updateMenuitemAttributes(menuitem, options) { + menuitem.setAttribute("id", options.id); + menuitem.setAttribute("label", options.label); + + if (options.accesskey) + menuitem.setAttribute("accesskey", options.accesskey); + + if (options.key) + menuitem.setAttribute("key", options.key); + + menuitem.setAttribute("disabled", !!options.disabled); + + if (options.image) { + menuitem.classList.add("menuitem-iconic"); + menuitem.style.listStyleImage = "url('" + options.image + "')"; + } + + if (options.checked) + menuitem.setAttribute('checked', options.checked); + + if (options.className) + options.className.split(/\s+/).forEach(function(name) menuitem.classList.add(name)); + + return menuitem; +} + +function updateProperty(menuitem, key, val) { + menuitemNS(menuitem).options[key] = val; + + forEachMI(function(menuitem) { + menuitem.setAttribute(key, val); + }, menuitem); + return val; +} + +function forEachMI(callback, menuitem) { + menuitemNS(menuitem).menuitems.forEach(function(mi, i) { + if (!mi) return; + callback(mi, i, function(id) mi.ownerDocument.getElementById(id)); + }); +} + +function tryParent(parent, menuitem, before) { + if (parent) { + if (!before) { + parent.appendChild(menuitem); + return true; + } + + parent.insertBefore(menuitem, insertBefore(parent, before)); + return true; + } + + return false; +} + +function insertBefore(parent, insertBefore) { + if (typeof insertBefore == "number") { + switch (insertBefore) { + case MenuitemExport.FIRST_CHILD: + return parent.firstChild; + } + return null; + } + else if (typeof insertBefore == "string") { + return parent.querySelector("#" + insertBefore); + } + return insertBefore; +} + +function MenuitemExport(options) { + return Menuitem(options); +} +MenuitemExport.FIRST_CHILD = 1; + +exports.Menuitem = MenuitemExport; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/actions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/actions.js @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const method = require('method/core'); + +exports.show = method('show'); +exports.hide = method('hide'); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/contract.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/contract.js @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { contract } = require('sdk/util/contract'); +const { isValidURI } = require('sdk/url'); + +let string = { is: ['string'] }; + +exports.contract = contract({ + id: { + is: [ 'string' ], + ok: function (v) /^[a-z0-9-_]+$/i.test(v), + msg: 'The option "id" must be a valid alphanumeric id (hyphens and ' + + 'underscores are allowed).' + }, + title: { + is: [ 'string' ], + ok: function (v) v.length + }, + url: { + is: [ 'string' ], + ok: function(url) { + return isValidURI(url); + }, + map: function(v) v.toString(), + msg: 'The option "url" must be a valid URI.' + } +}); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/state.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/state.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const method = require('method/core'); + +exports.isShowing = method('isShowing'); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/sidebar/utils.js @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { getMostRecentBrowserWindow } = require('sdk/window/utils'); + +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +function create(window, details) { + let { document } = window; + + let menuitem = document.createElementNS(XUL_NS, 'menuitem'); + menuitem.setAttribute('id', details.id); + menuitem.setAttribute('label', details.title); + menuitem.setAttribute('checked', 'false'); + menuitem.setAttribute('sidebarurl', details.sidebarurl); + menuitem.setAttribute('type', 'checkbox'); + menuitem.setAttribute('group', 'sidebar'); + menuitem.setAttribute('autoCheck', 'false'); + + document.getElementById('viewSidebarMenu').appendChild(menuitem); + + return menuitem; +} +exports.create = create; + +function dispose(menuitem) { + menuitem.parentNode.removeChild(menuitem); +} +exports.dispose = dispose; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/toolbarbutton.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/toolbarbutton.js @@ -0,0 +1,179 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const winUtils = require("sdk/deprecated/window-utils"); +const { isBrowser } = require('sdk/window/utils'); +const { Class } = require('sdk/core/heritage'); +const TBB_NS = require('sdk/core/namespace').ns(); + +const { validate: validateOptions } = require('./validate'); +const { getToolbarButtons, toolbarbuttonExists } = require('./utils'); +const { unload } = require("../addon/unload"); +const { listen } = require("../xul/listen"); + +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +exports.ToolbarButton = Class({ + initialize: function(options) { + TBB_NS(this).unloaders = []; + + const self = this; + TBB_NS(this).destroyed = false; + TBB_NS(this).destroyFuncs = []; + let safeOptions = TBB_NS(this).options = validateOptions(options); + + winUtils.WindowTracker({ + onTrack: function (window) { + if (!isBrowser(window) || TBB_NS(self).destroyed) + return; + + let doc = window.document; + let $ = function(id) doc.getElementById(id); + + // create toolbar button + let tbb = doc.createElementNS(NS_XUL, "toolbarbutton"); + tbb.setAttribute("id", safeOptions.id); + tbb.setAttribute("type", "button"); + if (safeOptions.image) + tbb.setAttribute("image", safeOptions.image); + tbb.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional"); + tbb.setAttribute("label", safeOptions.label); + tbb.setAttribute('tooltiptext', safeOptions.tooltiptext); + tbb.addEventListener("command", function() { + if (safeOptions.onCommand) + safeOptions.onCommand({}); // TODO: provide something? + + if (safeOptions.panel) { + safeOptions.panel.show(tbb); + } + }, true); + + // add toolbarbutton to palette + ($("navigator-toolbox") || $("mail-toolbox")).palette.appendChild(tbb); + + // find a toolbar to insert the toolbarbutton into + if (TBB_NS(self).options.toolbarID) { + var tb = $(TBB_NS(self).options.toolbarID); + } + if (!tb) { + var tb = toolbarbuttonExists(doc, safeOptions.id); + } + + // found a toolbar to use? + if (tb) { + let b4; + + // find the toolbarbutton to insert before + if (TBB_NS(self).options.insertbefore) { + b4 = $(TBB_NS(self).options.insertbefore); + } + if (!b4) { + let currentset = tb.getAttribute("currentset").split(","); + let i = currentset.indexOf(safeOptions.id) + 1; + + // was the toolbarbutton id found in the curent set? + if (i > 0) { + let len = currentset.length; + // find a toolbarbutton to the right which actually exists + for (; i < len; i++) { + b4 = $(currentset[i]); + if (b4) break; + } + } + } + + tb.insertItem(safeOptions.id, b4, null, false); + } + + var saveTBNodeInfo = function(e) { + TBB_NS(self).options.toolbarID = tbb.parentNode.getAttribute("id") || ""; + TBB_NS(self).options.insertbefore = (tbb.nextSibling || "") + && tbb.nextSibling.getAttribute("id").replace(/^wrapper-/i, ""); + }; + + window.addEventListener("aftercustomization", saveTBNodeInfo, false); + + // add unloader to unload+'s queue + var unloadFunc = function() { + tbb.parentNode.removeChild(tbb); + window.removeEventListener("aftercustomization", saveTBNodeInfo, false); + }; + var index = TBB_NS(self).destroyFuncs.push(unloadFunc) - 1; + listen(window, window, "unload", function() { + TBB_NS(self).destroyFuncs[index] = null; + }, false); + TBB_NS(self).unloaders.push(unload(unloadFunc, window)); + } + }); + }, + destroy: function() { + if (TBB_NS(this).destroyed) return; + TBB_NS(this).destroyed = true; + + let options = TBB_NS(this).options; + + if (options.panel) + options.panel.destroy(); + + // run unload functions + TBB_NS(this).destroyFuncs.forEach(function(f) f && f()); + TBB_NS(this).destroyFuncs.length = 0; + + // remove unload functions from unload+'s queue + TBB_NS(this).unloaders.forEach(function(f) f()); + TBB_NS(this).unloaders.length = 0; + }, + moveTo: function(pos) { + if (TBB_NS(this).destroyed) return; + + let options = TBB_NS(this).options; + + // record the new position for future windows + TBB_NS(this).options.toolbarID = pos.toolbarID; + TBB_NS(this).options.insertbefore = pos.insertbefore; + + // change the current position for open windows + for each (var window in winUtils.windowIterator()) { + if (!isBrowser(window)) continue; + + let $ = function (id) window.document.getElementById(id); + + // if the move isn't being forced and it is already in the window, abort + if (!pos.forceMove && $(this.id)) continue; + + var tb = $(TBB_NS(this).options.toolbarID); + var b4 = $(TBB_NS(this).options.insertbefore); + + // TODO: if b4 dne, but insertbefore is in currentset, then find toolbar to right + + if (tb) tb.insertItem(this.id, b4, null, false); + }; + }, + get id() TBB_NS(this).options.id, + get label() TBB_NS(this).options.label, + set label(value) { + TBB_NS(this).options.label = value; + getToolbarButtons(function(tbb) { + tbb.label = value; + }, this.id); + return value; + }, + setIcon: function setIcon(options) { + let val = TBB_NS(this).options.image = options.image || options.url; + getToolbarButtons(function(tbb) { + tbb.image = val; + }, this.id); + return val; + }, + get image() TBB_NS(this).options.image, + set image(value) this.setIcon({image: value}), + get tooltiptext() TBB_NS(this).options.tooltiptext, + set tooltiptext(value) { + TBB_NS(this).options.tooltiptext = value; + getToolbarButtons(function(tbb) { + tbb.setAttribute('tooltiptext', value); + }, this.id); + } +}); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/utils.js @@ -0,0 +1,28 @@ +'use strict'; + +const winUtils = require("sdk/deprecated/window-utils"); +const { isBrowser } = require('sdk/window/utils'); + +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +function getToolbarButtons(callback, id) { + let buttons = []; + for each (var window in winUtils.windowIterator()) { + if (!isBrowser(window)) continue; + let tbb = window.document.getElementById(id); + if (tbb) buttons.push(tbb); + } + if (callback) buttons.forEach(callback); + return buttons; +} +exports.getToolbarButtons = getToolbarButtons; + +function toolbarbuttonExists(doc, id) { + var toolbars = doc.getElementsByTagNameNS(NS_XUL, "toolbar"); + for (var i = toolbars.length - 1; ~i; i--) { + if ((new RegExp("(?:^|,)" + id + "(?:,|$)")).test(toolbars[i].getAttribute("currentset"))) + return toolbars[i]; + } + return false; +} +exports.toolbarbuttonExists = toolbarbuttonExists; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/validate.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/validate.js @@ -0,0 +1,31 @@ +'use strict'; + +const { validateOptions } = require('sdk/deprecated/api-utils'); +const { Panel } = require('sdk/panel'); + + const RULES = { + image: { is: ["null", "undefined", "string"] }, + tooltiptext: { + is: ["null", "undefined", "string"], + defaultValue: '' + }, + id: { + is: ["string"], + ok: function (v) v.length > 0, + msg: 'BAD ID', + readonly: true + }, + label: { + is: ["string"], + ok: function (v) v.length > 0, + msg: 'BAD Label' + }, + panel: { + is: ["null", "undefined", "object"], + ok: function(v) !v || v instanceof Panel + }, + onCommand: { + is: ["null", "undefined", "function"], + } +}; +exports.validate = function(o) validateOptions(o, RULES); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/warning.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/warning.js @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const self = require('sdk/self'); +const tabs = require('sdk/tabs'); +const { Class } = require('sdk/core/heritage'); +const { on, emit, once, off } = require('sdk/event/core'); +const { EventTarget } = require('sdk/event/target'); + +const awNS = require('sdk/core/namespace').ns(); + +let AddonWarning = Class({ + extends: EventTarget, + initialize: function initialize(options) { + EventTarget.prototype.initialize.call(this, options); + awNS(this).options = options; + }, + open: function() { + let self = this; + let options = awNS(self).options; + + tabs.open({ + url: module.uri.replace(/lib\/addon-warning\.js/, 'data/warning.html'), + onReady: function(tab) { + let worker = tab.attach({ + contentScriptFile: module.uri.replace(/lib\/addon-warning\.js/, 'data/warning-mod.js') + }); + + worker.port.on('cancel', function(data) { + emit(self, 'cancel'); + }); + worker.port.on('accept', function(data) { + emit(self, 'accept'); + }); + + worker.port.emit('load', options); + } + }); + } +}); +exports.AddonWarning = AddonWarning; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/web-panel.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/ui/web-panel.js @@ -0,0 +1,289 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +module.metadata = { + 'stability': 'experimental', + 'engines': { + 'Firefox': '*' + } +}; + +const { Class } = require('sdk/core/heritage'); +const { merge } = require('sdk/util/object'); +const { Disposable } = require('sdk/core/disposable'); +const { off, emit, setListeners } = require('sdk/event/core'); +const { EventTarget } = require('sdk/event/target'); +const { URL } = require('sdk/url'); +const { add, remove, has, clear, iterator } = require('sdk/lang/weak-set'); +const { WindowTracker } = require('sdk/deprecated/window-utils'); +const { isBrowser, getMostRecentBrowserWindow, windows } = require('sdk/window/utils'); +const { ns } = require('sdk/core/namespace'); +const { remove: removeFromArray } = require('sdk/util/array'); +const { Worker: WorkerTrait } = require('sdk/content/worker'); + +const { create, dispose } = require('./sidebar/utils'); +const { show, hide } = require('./sidebar/actions'); +const { isShowing } = require('./sidebar/state'); +const { contract } = require('./sidebar/contract'); + +const Worker = WorkerTrait.resolve({ + _injectInDocument: '__injectInDocument' +}).compose({ + get _injectInDocument() false +}); + +const sidebarNS = ns(); + +const WEB_PANEL_BROWSER_ID = 'web-panels-browser'; + +let sidebars = {}; +let models = new WeakMap(); +let views = new WeakMap(); + +function viewsFor(sidebar) views.get(sidebar); +function modelFor(sidebar) models.get(sidebar); + +const WebPanel = Class({ + implements: [ Disposable ], + extends: EventTarget, + setup: function(options) { + let self = this; + + const windowNS = ns(); + + let model = merge({}, contract(options)); + + models.set(this, model); + + setListeners(this, options); + + let bars = []; + sidebarNS(self).tracker = WindowTracker({ + onTrack: function(window) { + if (!isBrowser(window)) + return; + + let sidebar = window.document.getElementById('sidebar'); + let sidebarBox = window.document.getElementById('sidebar-box'); + + let bar = create(window, { + id: makeID(model.id), + title: model.title, + sidebarurl: model.url + }); + bars.push(bar); + windowNS(window).bar = bar; + + bar.addEventListener('command', function() { + if (isSidebarShowing(window, self)) { + hideSidebar(window, self); + return; + } + + showSidebar(window, self); + }, false); + + function onSidebarLoad() { + // check if the sidebar is ready + let isReady = sidebar.docShell && sidebar.contentDocument; + if (!isReady) + return; + + // check if it is a web panel + let panelBrowser = sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID); + if (!panelBrowser) { + bar.removeAttribute('checked'); + return; + } + + let sbTitle = window.document.getElementById('sidebar-title'); + function onWebPanelSidebarLoad() { + if (panelBrowser.contentWindow.location != model.url || + sbTitle.value != model.title) { + return; + } + + let worker = windowNS(window).worker = Worker({ + window: panelBrowser.contentWindow + }); + + function onWebPanelSidebarUnload() { + panelBrowser.removeEventListener('unload', onWebPanelSidebarUnload, true); + + windowNS(window).onWebPanelSidebarLoad = null; + + // uncheck the associated menuitem + bar.setAttribute('checked', 'false'); + + emit(self, 'hide', null); + emit(self, 'detach', worker); + } + windowNS(window).onWebPanelSidebarUnload = onWebPanelSidebarUnload; + panelBrowser.contentWindow.addEventListener('unload', onWebPanelSidebarUnload, false); + + // check the associated menuitem + bar.setAttribute('checked', 'true'); + + emit(self, 'show', null); + emit(self, 'attach', worker); + } + windowNS(window).onWebPanelSidebarLoad = onWebPanelSidebarLoad; + panelBrowser.addEventListener('DOMWindowCreated', onWebPanelSidebarLoad, true); + } + windowNS(window).onSidebarLoad = onSidebarLoad; + sidebar.addEventListener('load', onSidebarLoad, true); + }, + onUntrack: function(window) { + if (!isBrowser(window)) + return; + + let { bar } = windowNS(window); + if (bar) { + removeFromArray(viewsFor(self), bar); + dispose(bar); + } + + let sidebar = window.document.getElementById('sidebar'); + if (!sidebar) + return; + + if (windowNS(window).onSidebarLoad) { + sidebar.removeEventListener('load', windowNS(window).onSidebarLoad, true) + windowNS(window).onSidebarLoad = null; + } + + if (windowNS(window).onWebPanelSidebarLoad) { + let webPanel = sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID); + webPanel && webPanel.removeEventListener('DOMWindowCreated', windowNS(window).onWebPanelSidebarLoad, true); + windowNS(window).onWebPanelSidebarLoad = null; + } + + if (windowNS(window).onWebPanelSidebarUnload) { + windowNS(window).onWebPanelSidebarUnload(); + } + } + }); + + views.set(this, bars); + + add(sidebars, this); + }, + get id() modelFor(this).id, + get title() modelFor(this).title, + get url() modelFor(this).url, + show: function() show(this), + hide: function() hide(this), + dispose: function() { + off(this); + + let wins = windows('navigator:browser', { includePrivate: true }); + for each (let win in wins) { + hideSidebar(win, this); + } + + remove(sidebars, this); + + // stop tracking windows + sidebarNS(this).tracker.unload(); + sidebarNS(this).tracker = null; + + views.delete(this); + } +}); +exports.WebPanel = WebPanel; + +function showSidebar(window, sidebar) { + let model = modelFor(sidebar); + //let window = window || getMostRecentBrowserWindow(); + + window.openWebPanel(model.title, model.url); + + let menuitem = window.document.getElementById(makeID(model.id)); + menuitem.setAttribute('checked', true); +} +show.define(WebPanel, showSidebar.bind(null, null)); + +function hideSidebar(window, sidebar) { + //window = window || getMostRecentBrowserWindow(); + + if (!isSidebarShowing(window, sidebar)) + return; + + // return window.toggleSidebar(); + + // Below was taken from http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#4775 + // the code for window.todggleSideBar().. + let { document } = window; + //let sidebar = document.getElementById('sidebar'); + let sidebarTitle = document.getElementById('sidebar-title'); + let sidebarBox = document.getElementById('sidebar-box'); + let sidebarSplitter = document.getElementById('sidebar-splitter'); + let commandID = sidebarBox.getAttribute('sidebarcommand'); + let sidebarBroadcaster = document.getElementById(commandID); + + sidebarBox.hidden = true; + sidebarSplitter.hidden = true; + + sidebar.setAttribute('src', 'about:blank'); + //sidebar.docShell.createAboutBlankContentViewer(null); + + sidebarBroadcaster.removeAttribute('checked'); + sidebarBox.setAttribute('sidebarcommand', ''); + sidebarTitle.value = ''; + sidebarBox.hidden = true; + sidebarSplitter.hidden = true; + + // TODO: perhaps this isn't necessary if the window is not most recent? + window.gBrowser.selectedBrowser.focus(); +} +hide.define(WebPanel, hideSidebar.bind(null, null)); + +function isSidebarShowing(window, sidebar) { + let win = window || getMostRecentBrowserWindow(); + + // make sure there is a window + if (!win) { + return false; + } + + // make sure there is a sidebar for the window + let sb = win.document.getElementById('sidebar'); + let sidebarTitle = win.document.getElementById('sidebar-title'); + if (!(sb && sidebarTitle)) { + return false; + } + + // checks if the sidebar box is hidden + let sbb = win.document.getElementById('sidebar-box'); + if (!sbb || sbb.hidden) { + return false; + } + + // checks if the sidebar is loading + if (win.gWebPanelURI == modelFor(sidebar).url) { + return false; + } + + if (sidebarTitle.value == modelFor(sidebar).title) { + // checks if the sidebar loaded already + let ele = sb.contentDocument && sb.contentDocument.getElementById(WEB_PANEL_BROWSER_ID); + + if (ele.getAttribute('cachedurl') == modelFor(sidebar).url) { + return true; + } + + if (ele && ele.contentWindow && ele.contentWindow.location == modelFor(sidebar).url) { + return true; + } + } + + // default + return false; +} +isShowing.define(WebPanel, isSidebarShowing.bind(null, null)); + +function makeID(id) { + return 'pathfinder-sidebar-' + id; +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userscript.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userscript.js @@ -0,0 +1,116 @@ +'use strict'; + +var file = require("sdk/io/file"); +var url = require("sdk/url"); + +var convert2RegExp = require("./scriptish/convert-2-regexp").convert2RegExp; +var userscriptParser = require("./scriptish/userscript-header-parser").parse; +var manager = require("./scriptish/userscript-manager"); + +const JSVersions = ['1.6', '1.7', '1.8'/*, '1.8.1'*/]; + +var UserScript = exports.UserScript = function UserScript(aURL) { + var script = new Script(aURL); + manager.register(script); + + return { + destory: function() { + manager.unregister(script); + }, + get enabled() script.enabled, + set enabled(aVal) script.enabled = !!aVal + }; +} + +function Script(aURL) { + this._url = url.URL(aURL); + this._filepath = url.toFilename(aURL); + this._source = file.read(this._filepath); + var header = userscriptParser(this._source); + + this._name = (header.name && header.name[0]) || Script.parseScriptName(aURL); + this._namespace = (header.namespace && header.namespace[0]) || this.url.host; + this._description = (header.description && header.description[0]) || ""; + this.enabled = true; + this._includes = (header.include || []).map(convert2RegExp); + this._excludes = (header.exclude || []).map(convert2RegExp); + this._requires = (header.require || []); + this._resources = (header.resource || []); + if (header.jsversion) { + for (var i = header.jsversion.length - 1; ~i; i--) { + let val = header.jsversion[i]; + if (~JSVersions.indexOf(val)) { + this.jsversion = val; + break; + } + } + } +} + +Script.prototype = { + get prefPrefix () { + return ["greasemonkey.scriptvals.", + this._namespace, + "/", + this._name, + "."].join(""); + }, + + // TODO: actually implement this! + matchesDomain: function() { + return true; + }, + + matchesURL: function(url) { + var test = function(pattern) { + return pattern.test(url); + } + + return this.enabled + && this._includes.some(test) + && !this._excludes.some(test); + }, + + _changed: function(event, data) { + if(this._config) { + this._config._changed(this, event, data); + } + }, + + get name() { return this._name; }, + get namespace() { return this._namespace; }, + get description() { return this._description; }, + + get enabled() { return this._enabled; }, + set enabled(enabled) { + this._enabled = enabled; + this._changed("edit-enabled", enabled); + }, + + get includes() { return this._includes.concat(); }, + get excludes() { return this._excludes.concat(); }, + addInclude: function(url) { + this._includes.push(url); + this._changed("edit-include-add", url); + }, + removeIncludeAt: function(index) { + this._includes.splice(index, 1); + this._changed("edit-include-remove", index); + }, + addExclude: function(url) { + this._excludes.push(url); + this._changed("edit-exclude-add", url); + }, + removeExcludeAt: function(index) { + this._excludes.splice(index, 1); + this._changed("edit-exclude-remove", index); + }, + + get requires() { return this._requires.concat(); }, + get resources() { return this._resources.concat(); }, + get unwrap() { return this._unwrap; } +}; + + +Script.parseScriptName = function(aURL) (( + /\/([^\/]+)\.user(?:-\d+)?\.js(?:[\?#].*)?$/.test(aURL || "")) ? RegExp.$1 : ""); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userstyles.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/userstyles.js @@ -0,0 +1,72 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci } = require("chrome"); +const { unload } = require('./addon/unload'); + +const sss = Cc["@mozilla.org/content/style-sheet-service;1"] + .getService(Ci.nsIStyleSheetService); + +function getURI(aURL) Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService).newURI(aURL, null, null); + +function setOptions(url, options) { + let newOptions = {}; + options = options || {}; + + newOptions.uri = getURI(url); + newOptions.type = (options.type || 'user').toLowerCase(); + newOptions.type = (newOptions.type == 'agent') ? sss.AGENT_SHEET : sss.USER_SHEET; + + return newOptions; +}; + +// capture the unload callbacks for removing the unload function from +// the queue as they are no longer needed when a URL is unregistered manually +var unloaders = {}; + +function removeUnload(url) { + if (typeof unloaders[url] === "function") { + unloaders[url].call(null); + delete unloaders[url]; + } +} + +/** + * Load various packaged styles for the add-on and undo on unload + * + * @usage load(aURL): Load specified style + * @param [string] aURL: Style file to load + * @param [object] options: + */ +const loadSS = exports.load = function loadSS(url, options) { + let { uri, type } = setOptions(url, options); + + // load the stylesheet + sss.loadAndRegisterSheet(uri, type); + + // remove the unloader for this URL if it exists + removeUnload(url); + + // unload the stylesheet on unload + unloaders[url] = unload(unregisterSS.bind(null, url, options)); +}; + +const registeredSS = exports.registered = function registeredSS(url, options) { + let { uri, type } = setOptions(url, options); + + // check that the stylesheet is registered + return !!sss.sheetRegistered(uri, type); +}; + +const unregisterSS = exports.unload = function unregisterSS(url, options) { + let { uri, type } = setOptions(url, options); + + // remove the unloader our load function setup if it exists + removeUnload(url); + + // unregister the stylesheet + sss.unregisterSheet(uri, type); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/utils/addonmanager.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/utils/addonmanager.js @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const {Cc, Ci, Cu} = require("chrome"); + +Cu.import("resource://gre/modules/AddonManager.jsm", this); + +exports.AddonManager = AddonManager; +exports.AddonManagerPrivate = AddonManagerPrivate; + +exports.AddonType = AddonManagerPrivate.AddonType; +exports.AddonAuthor = + AddonManagerPrivate.AddonAuthor || function AddonAuthor(name, url) { + this.name = name; + this.url = url; + this.toString = function() this.name +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/browser.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/browser.js @@ -0,0 +1,180 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { WindowTracker } = require("sdk/deprecated/window-utils"); +const { isBrowser, windows } = require('sdk/window/utils'); +const { validateOptions } = require("sdk/deprecated/api-utils"); +const { Class } = require("sdk/core/heritage"); +const { ns } = require("sdk/core/namespace"); +const { ensure } = require('sdk/system/unload'); + +const { xulNS } = require('./namespace'); + +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; +const VALID_POSITIONS = ['top']; + +// Converts anything that isn't false, null or undefined into a string +function stringOrNull(val) val ? String(val) : val; + +const XUL_SKELETON = Class({ + setup: function setup(attributes) { + const internals = xulNS(this); + internals.attributes = attributes; + ensure(this, 'destroy'); + }, + appendChild: function appendChild(node) { + const ID = this.getAttribute('id'); + + // keep note to update parent in future windows + xulNS(node).parentID = ID; + xulNS(node).insertBeforeID = null; + + // update parent on current windows + windows().forEach(function(window) { + let parent = window.document.getElementById(ID); + let { element } = xulNS(node).windowsNS(window); + parent.appendChild(element); + }); + }, + insertBefore: function(node, beforeNode) { + const ID = this.getAttribute('id'); + const B4_ID = (typeof beforeNode == 'string') ? beforeNode : beforeNode.getAttribute('id'); + + // keep note to update parent in future windows + xulNS(node).parentID = ID; + xulNS(node).insertBeforeID = B4_ID; + + // update parent on current windows + windows().forEach(function(window) { + let parent = window.document.getElementById(ID); + let before = window.document.getElementById(B4_ID); + let { element } = xulNS(node).windowsNS(window); + + parent.insertBefore(element, before); + }); + }, + addEventListener: function addEventListener(type, listener, useCapture) { + internals.eles.forEach(function(ele) { + ele.addEventListener(type, listener, useCapture); + }); + }, + removeEventListener: function removeEventListener(type, listener, useCapture) { + internals.eles.forEach(function(ele) { + ele.removeEventListener(type, listener, useCapture); + }); + }, + getAttribute: function getAttribute(attr) { + return xulNS(this).attributes[attr]; + }, + setAttribute: function setAttribute(attr, value) { + const internals = xulNS(this); + internals.eles.forEach(function(ele) { + ele.setAttribute(attr, value); + }); + internals.attributes[attr] = value; + }, + destroy: function() { + const internals = xulNS(this); + internals.attributes = null; + } +}); + +const XUL = Class({ + implements: [ XUL_SKELETON ], + initialize: function(nodeName, attributes) { + const self = this; + const internals = xulNS(this); + internals.windowsNS = ns(); + internals.eles = []; + internals.attributes = attributes; + + XUL_SKELETON.prototype.setup.call(this, attributes); + + // Set Window Tracker + internals.windowtracker = WindowTracker({ + onTrack: function(window) { + if (!isBrowser(window)) return; + let ele = window.document.createElementNS(NS_XUL, nodeName); + + Object.keys(attributes).forEach(function(key) { + ele.setAttribute(key, attributes[key]); + }) + + internals.eles.push(ele); + internals.windowsNS(window).element = ele; + + // update parent? + if (internals.parentID) { + let parent = window.document.getElementById(internals.parentID); + if (internals.insertBeforeID) { + let before = window.document.getElementById(internals.insertBeforeID); + parent.insertBefore(ele, before); + } + else { + parent.appendChild(ele); + } + } + }, + onUntrack: function(window) { + if (!isBrowser(window)) return; + let { element } = internals.windowsNS(window); + element.parentNode.removeChild(element); + internals.windowsNS(window).element = null; + } + }); + }, + destroy: function() { + XUL_SKELETON.prototype.destroy.call(this); + const internals = xulNS(this); + internals.windowtracker.unload(); + internals.windowtracker = null; + internals.windowsNS = null; + } +}); +exports.XUL = XUL; + +const XUL_GETTER = Class({ + implements: [ XUL_SKELETON ], + initialize: function(attributes) { + const self = this; + const internals = xulNS(this); + internals.windowsNS = ns(); + internals.eles = []; + internals.attributes = attributes; + + XUL_SKELETON.prototype.setup.call(this, attributes); + + // Set Window Tracker + internals.windowtracker = WindowTracker({ + onTrack: function(window) { + if (!isBrowser(window)) return; + let ele = window.document.getElementById(attributes.id); + internals.eles.push(ele); + internals.windowsNS(window).element = ele; + + // update parent? + if (internals.parentID) { + let parent = window.document.getElementById(internals.parentID); + parent.appendChild(ele); + } + } + }); + }, + destroy: function() { + const internals = xulNS(this); + + XUL_SKELETON.prototype.destroy.call(this); + + internals.windowtracker.unload(); + internals.windowtracker = null; + internals.windowsNS = null; + } +}); +exports.XUL_GETTER = XUL_GETTER; + +function getXULById(id) { + return XUL_GETTER({ id: id }); +} +exports.getXULById = getXULById; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/key.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/key.js @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +exports.XulKey = function XulKey(options) { + var delegate = { + onTrack: function (window) { + if ("chrome://browser/content/browser.xul" != window.location) return; + + let doc = window.document; + function $(id) doc.getElementById(id); + function xul(type) doc.createElementNS(NS_XUL, type); + + var onCmd = function() { + options.onCommand && options.onCommand(); + }; + + var keyset = xul("keyset"); + + // add hotkey + var key = xul("key"); + key.setAttribute("id", options.id); + key.setAttribute("key", options.key); + if (options.modifiers) + key.setAttribute("modifiers", options.modifiers); + key.setAttribute("oncommand", "void(0);"); + key.addEventListener("command", onCmd, true); + ($("mainKeyset") || $("mailKeys")).parentNode.appendChild(keyset).appendChild(key); + + // add unloader + require("unload+").unload(function() { + key.removeEventListener("command", onCmd, true); // must do for some reason.. + keyset.parentNode.removeChild(keyset); + }, window); + }, + onUntrack: function (window) {} + }; + var winUtils = require("window-utils"); + var tracker = new winUtils.WindowTracker(delegate); +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/listen.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/listen.js @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { unload } = require('../addon/unload'); + +/** + * Helper that adds event listeners and remembers to remove on unload + */ +function listen(window, node, event, func, capture) { + // Default to use capture + if (capture == null) + capture = true; + + node.addEventListener(event, func, capture); + function undoListen() { + node.removeEventListener(event, func, capture); + } + + // Undo the listener on unload and provide a way to undo everything + let undoUnload = unload(undoListen, window); + return function() { + undoListen(); + undoUnload(); + }; +} +exports.listen = listen; + diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/namespace.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/xul/namespace.js @@ -0,0 +1,3 @@ +'use strict'; +const { ns } = require('sdk/core/namespace'); +exports.xulNS = ns(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/zip/utils.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/lib/zip/utils.js @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Cc, Ci, Cu } = require("chrome"); + +exports.getZipReader = function(aFile) { + var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"] + .createInstance(Ci.nsIZipReader); + zipReader.open(aFile); + return zipReader; +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/package.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/package.json @@ -0,0 +1,60 @@ +{ + "_args": [ + [ + "pathfinder@git+https://github.com/OverByThere/addon-pathfinder.git", + "/home/nik/src/librejs/node_modules/menuitem" + ] + ], + "_from": "git+https://github.com/OverByThere/addon-pathfinder.git", + "_id": "pathfinder@1.0.1", + "_inCache": true, + "_location": "/pathfinder", + "_phantomChildren": {}, + "_requested": { + "hosted": { + "directUrl": "https://raw.githubusercontent.com/OverByThere/addon-pathfinder/master/package.json", + "gitUrl": "git://github.com/OverByThere/addon-pathfinder.git", + "httpsUrl": "git+https://github.com/OverByThere/addon-pathfinder.git", + "shortcut": "github:OverByThere/addon-pathfinder", + "ssh": "git@github.com:OverByThere/addon-pathfinder.git", + "sshUrl": "git+ssh://git@github.com/OverByThere/addon-pathfinder.git", + "type": "github" + }, + "name": "pathfinder", + "raw": "pathfinder@git+https://github.com/OverByThere/addon-pathfinder.git", + "rawSpec": "git+https://github.com/OverByThere/addon-pathfinder.git", + "scope": null, + "spec": "git+https://github.com/OverByThere/addon-pathfinder.git", + "type": "hosted" + }, + "_requiredBy": [ + "/menuitem" + ], + "_resolved": "git+https://github.com/OverByThere/addon-pathfinder.git#bad1110fc9427bafd6d7fc1a1d4594cf8086ab94", + "_shasum": "e8e99972c3ac7a562fb84e8331b9df88ca2a9098", + "_shrinkwrap": null, + "_spec": "pathfinder@git+https://github.com/OverByThere/addon-pathfinder.git", + "_where": "/home/nik/src/librejs/node_modules/menuitem", + "author": { + "name": "Erik Vold" + }, + "bugs": { + "url": "https://github.com/OverByThere/menuitem/issues" + }, + "dependencies": {}, + "description": "The Add-on Pathfinder is the collection of Jetpack modules made to be used with the [Add-on SDK](https://github.com/mozilla/addon-sdk).", + "devDependencies": {}, + "gitHead": "bad1110fc9427bafd6d7fc1a1d4594cf8086ab94", + "homepage": "https://github.com/OverByThere/menuitem#readme", + "installable": true, + "license": "MPL 2.0", + "name": "pathfinder", + "optionalDependencies": {}, + "readme": "# Add-on Pathfinder\n\nThe Add-on Pathfinder is the collection of Jetpack modules made to be used with the\n[Add-on SDK](https://github.com/mozilla/addon-sdk).\n\n## Highlights\n\n* Toolbar buttons\n* Menuitems\n* GCLI\n* Downloads\n* About/Resource Schemes\n* UserStyles\n* UserScripts\n* XUL Help\n* ZIP Utilities\n* Content policies\n* Content Permissions\n* Awesomebar\n* Modifying Request Headers\n* Redirects\n* Much much more!...\n", + "readmeFilename": "README.md", + "repository": { + "type": "git", + "url": "git+https://github.com/OverByThere/menuitem.git" + }, + "version": "1.0.1" +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/black.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/black.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/index.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/index.html @@ -0,0 +1,4 @@ +<html> + <title></title> + <body></body> +</html> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-folder.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-folder.js @@ -0,0 +1,90 @@ +'use strict'; + +const JETPACK_DIR_BASENAME = "jetpack"; + +const FOLDER = require('pathfinder/addon/folder'); + +const { Loader } = require('sdk/test/loader'); +const { Cc, Ci } = require('chrome'); +const file = require('sdk/io/file'); +const jpSelf = require('sdk/self'); + +let storeFile = Cc['@mozilla.org/file/directory_service;1'] + .getService(Ci.nsIProperties) + .get('ProfD', Ci.nsIFile); +storeFile.append(JETPACK_DIR_BASENAME); +storeFile.append(jpSelf.id); +storeFile.append('addon-folder'); + +const ADDON_FOLDER_PATH = storeFile.path; + +exports.testFolderCreated = function(assert) { + let loader = Loader(module); + assert.ok(file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + ' was created'); + FOLDER.destroy(); + assert.ok(!file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + ' was destroyed'); + loader.require('pathfinder/addon/folder'); + assert.ok(file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + ' was created'); + loader.unload(); + assert.ok(file.exists(ADDON_FOLDER_PATH), ADDON_FOLDER_PATH + 'exists after unload'); +} + +exports.testFileLifecycle = function(assert, done) { + let filename = 'test.json'; + let fileStream = FOLDER.write(filename); + try { + fileStream.writeAsync('{}', function(err) { + assert.equal(FOLDER.exists(filename), true, 'the file was created'); + + if (err) + assert.fail(err); + else + assert.equal(FOLDER.read(filename), '{}', 'the file was written correctly'); + + let entries = FOLDER.list(); + assert.ok(entries.length > 0, 'there is more than one entry'); + for each (let entry in entries) { + assert.equal(entry, filename, filename + ' is the only entry listed'); + } + + let testFile = Cc['@mozilla.org/file/directory_service;1'] + .getService(Ci.nsIProperties) + .get('ProfD', Ci.nsIFile); + testFile.append(JETPACK_DIR_BASENAME); + testFile.append(jpSelf.id); + testFile.append('addon-folder'); + testFile.append(filename); + + assert.ok(testFile.exists(), 'the test file does exist.') + + FOLDER.remove(filename); + + assert.equal(FOLDER.exists(filename), false, 'the file was removed'); + + done(); + }); + } + catch(e) { + assert.fail(e); + fileStream.close(); + done(); + } +} + +exports.testBackPath = function(assert, done) { + let filename = '../../test.json'; + let fileStream = { close: function(){} }; + try { + fileStream = FOLDER.write(filename); + assert.fail(filename + ' should not be useable'); + } + catch(e) { + assert.pass(e); + } + + fileStream.close(); + done(); +} + + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-warning.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-addon-warning.js @@ -0,0 +1,3 @@ +'use strict'; + +const warning = require('pathfinder/ui/warning'); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-connection-request.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-connection-request.js @@ -0,0 +1,57 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Ci } = require('chrome'); +const tabs = require('sdk/tabs'); +const { data } = require('sdk/self'); +const { Loader } = require('sdk/test/loader'); +const httpd = require('sdk/test/httpd'); + +const { RequestRule } = require('pathfinder/connections'); + +exports.testNewHeader = function(assert, done) { + let rule = RequestRule({ + headers: { + 'X-TEST-HEADER': 'TEST' + } + }); + + let serverPort = 8058; + let url = 'http://localhost:' + serverPort + '/test.txt'; + let server = httpd.startServerAsync(serverPort); + const contents = "testNewHeader"; + let requestCount = 0; + + server.registerPathHandler("/test.txt", function handle(request, response) { + requestCount++; + + if (requestCount == 1) { + try { + assert.equal(request.getHeader('X-TEST-HEADER'), 'TEST', 'the new test header value is correct'); + } + catch (e) { + assert.fail(e); + } + rule.destroy(); + } + response.write(contents); + }); + + tabs.open({ + url: url, + onReady: function(tab) { + if (requestCount == 1) { + tab.reload(); + } + else { + server.stop(function() { + done(); + }); + } + } + }) +} + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-permissions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-permissions.js @@ -0,0 +1,35 @@ +'use strict'; + +const { permissions } = require('pathfinder/content/permissions'); + +exports.testAddRemovePermission = function(assert) { + permissions.add({ + url: 'http://erikvold.com/', + permission: 'deny', + type: 'images' + }); + + let found = false; + for each (let permission in permissions.permissions) { + if (permission.host == 'erikvold.com') { + found = true; + assert.equal(permission.permission, 'deny'); + assert.equal(permission.type, 'images'); + } + } + assert.ok(found, 'erikvold.com permission was found'); + + permissions.remove({ + url: 'http://erikvold.com/', + type: 'images' + }); + + for each (let permission in permissions.permissions) { + if (permission.host == 'erikvold.com') { + assert.fail('there should not be a permission for erikvold.com'); + } + } + assert.pass('permission was removed!'); +}; + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-policy.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-content-policy.js @@ -0,0 +1,155 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Loader } = require('sdk/test/loader'); +const tabs = require('sdk/tabs'); +const timers = require('sdk/timers'); + +const cp = require('pathfinder/content/policy'); + +exports.testConstants = function(assert) { + assert.ok(cp.REJECT != undefined, 'REJECT constant exists'); + assert.ok(cp.ACCEPT != undefined, 'ACCEPT constant exists'); + assert.ok(cp.ContentPolicy != undefined, 'ContentPolicy constant exists'); +}; + +exports.testContentPolicyDestroy = function(assert, done) { + const loader = Loader(module); + const httpd = loader.require('sdk/test/httpd'); + const { ContentPolicy } = loader.require('pathfinder/content/policy') + const { startServerAsync } = httpd; + const { setTimeout } = timers; + + let tabsCount = tabs.length; + let tab1; + + let serverPort = 8056; + let server = httpd.startServerAsync(serverPort); + const contents = '<!DOCTYPE html><html><head></head><body>testContentPolicyDestroy</body></html>'; + // test.html + let testPageRequests = 0; + server.registerPathHandler('/test.html', function handle(request, response) { + testPageRequests++; + response.write(contents); + }); + + let url = 'http://localhost:' + serverPort + '/test.html'; + let policy = ContentPolicy({ + shouldLoad: function({ location }) { + if (location != url) + return true; + + setTimeout(function() { + policy.destroy(); + + tabs.open({ + url: url, + inBackground: true, + onReady: function (tab2) { + assert.equal(tab2.url, url, url); + tab2.close(function() tab1.close()); + } + }); + assert.pass('tab2 opening..'); + }, 0); + return false; + } + }); + assert.pass('Content policy is setup'); + + setTimeout(function() { + tabs.open({ + url: url, + inBackground: true, + onOpen: function (tab) { + tab1 = tab; + assert.equal(tab1.url, 'about:blank', 'tab1 opened - about:blank'); + }, + onReady: function() { + assert.fail('tab1 loaded..'); + }, + onClose: function() { + assert.equal(testPageRequests, 1, 'test page was only requested once'); + //assert.equal(tabsCount, tabs.length, 'all test tabs are closed'); + loader.unload(); + done(); + } + }); + + assert.pass('tab1 opening..'); + }, 500); +}; + +exports.testContentPolicyUnload = function(assert, done) { + const loader = Loader(module); + const { ContentPolicy } = loader.require('pathfinder/content/policy'); + const { setTimeout } = loader.require('sdk/timers'); + + let tabsCount = tabs.length; + let tab1; + let otherTabs = []; + let calls = 0; + let expectedCalls = 1; + let url = 'data:text/html;charset=utf-8,testContentPolicyUnload'; + let policy = ContentPolicy({ + contract: '@erikvold.com/content-policy.TEST;unload', + shouldLoad: function({ location }) { + if (location != url) + return true; + + calls++; + setTimeout(function() { + loader.unload(); + + assert.pass('tab2 opening..'); + tabs.open({ + url: url, + inBackground: true, + onOpen: function(tab) { + otherTabs.push(tab); + }, + onReady: function (tab2) { + assert.equal(tab2.url, url, url); + expectedCalls = otherTabs.length; + + // close tabs + (function ender() { + if (otherTabs.length <= 0) + return tab1.close(); + otherTabs.pop().close(); + ender(otherTabs); + })() + } + }); + assert.pass('tab2 open called.'); + }, 0); + + return false; + } + }); + assert.pass('Content policy is setup'); + + setTimeout(function() { + assert.pass('tab1 opening..'); + tabs.open({ + url: url, + inBackground: true, + onOpen: function (tab) { + tab1 = tab; + assert.equal(tab1.url, 'about:blank', 'tab1 opened - about:blank'); + }, + onReady: function() { + assert.fail('tab1 loaded..'); + }, + onClose: function() { + assert.equal(calls, expectedCalls, 'content policy only rejected expected number of times'); + //assert.equal(tabsCount, tabs.length, 'all test tabs are closed'); + done(); + } + }); + }, 500); +}; + +require('test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-download.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-download.js @@ -0,0 +1,58 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Ci, Cc, Cu } = require('chrome'); +const { pathFor } = require("sdk/system"); +const { Loader } = require("sdk/test/loader"); +const { Request } = require('sdk/request'); +const options = require("@test/options"); + +const { Download } = require('pathfinder/download'); + +const { Services } = require('pathfinder/chrome/services'); + +exports.testDownload = function(assert, done) { + const loader = Loader(module); + const httpd = loader.require('sdk/test/httpd'); + + let serverPort = 8057; + let server = httpd.startServerAsync(serverPort); + const contents = "testDownload"; + + server.registerPathHandler("/test.txt", function handle(request, response) { + response.write(contents); + }); + + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); + file.append("test.txt"); + + assert.ok(!file.exists(), 'Download does not exist yet'); + + let download = Download({ + url: "http://localhost:" + serverPort + "/test.txt", + destination: file.path, + onComplete: function() { + assert.ok(file.exists(), 'Download was successful'); + + Request({ + url: Services.io.newFileURI(file).spec, + overrideMimeType: "text/plain; charset=latin1", + onComplete: function ({ text }) { + assert.equal(text, contents, 'the file content is correct'); + file.remove(false); + assert.ok(!file.exists(), 'File was removed'); + + server.stop(function() { + loader.unload(); + done(); + }); + } + }).get(); + } + }); + assert.ok(!!download, 'Download started'); +} + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-find-suggestion.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-find-suggestion.js @@ -0,0 +1,3 @@ +'use strict'; + +require('pathfinder/ui/findbar/suggestion'); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-listen.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-listen.js @@ -0,0 +1,152 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Loader } = require('sdk/test/loader'); +const { getMostRecentBrowserWindow } = require('sdk/window/utils'); +const { open, close, promise: windowPromise } = require('sdk/window/helpers'); +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +const { listen: gListen } = require('pathfinder/xul/listen'); + +// from https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent +function simulateClick(ele) { + let window = ele.ownerDocument.defaultView; + let { document } = window; + var evt = document.createEvent("MouseEvents"); + evt.initMouseEvent("click", true, true, window, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + ele.dispatchEvent(evt); +} + +function makeEle(window) { + window = window || getMostRecentBrowserWindow(); + let ele = window.document.createElementNS(NS_XUL, 'toolbar'); + return { + window: window, + document: window.document, + ele: ele + } +} + +exports.testSuccessiveListenersCaptureTrue = function(assert, done) { + const loader = Loader(module); + const { listen } = loader.require('pathfinder/xul/listen'); + let { window, document, ele } = makeEle(); + let aHappened = false; + + listen(window, ele, 'click', function() { + aHappened = true; + }, true); + listen(window, ele, 'click', function() { + assert.ok(aHappened, 'the first listener attached was the first called.') + loader.unload(); + done(); + }, true); + + simulateClick(ele); +} + +exports.testSuccessiveListeners = function(assert, done) { + const loader = Loader(module); + const { listen } = loader.require('pathfinder/xul/listen'); + let { window, document, ele } = makeEle(); + let aHappened = false; + + listen(window, ele, 'click', function() { + aHappened = true; + }, false); + listen(window, ele, 'click', function() { + assert.ok(aHappened, 'the first listener attached was the first called.') + loader.unload(); + done(); + }, false); + + simulateClick(ele); +} + +exports.testSuccessiveListenersAcrossLoaders = function(assert, done) { + const loader = Loader(module); + const { listen } = loader.require('pathfinder/xul/listen'); + let { window, document, ele } = makeEle(); + let aHappened = false; + + listen(window, ele, 'click', function() { + aHappened = true; + }, false); + let remover = gListen(window, ele, 'click', function() { + assert.ok(aHappened, 'the first listener attached was the first called.'); + remover(); + loader.unload(); + done(); + }, false); + + simulateClick(ele); +} + +exports.testRemover = function(assert, done) { + const loader = Loader(module); + const { listen } = loader.require('pathfinder/xul/listen'); + let { window, document, ele } = makeEle(); + let aHappened = false; + + let remover1 = listen(window, ele, 'click', function() { + aHappened = true; + }, false); + let remover = gListen(window, ele, 'click', function() { + assert.ok(!aHappened, 'the first listener attached was removed'); + remover(); + loader.unload(); + done(); + }, false); + + remover1(); + simulateClick(ele); +} + +exports.testWindowUnloadEvent = function(assert, done) { + let eHappened = false; + let { window, ele: ele1 } = makeEle(); + let remover2, remover1 = gListen(window, ele1, 'click', function() { + assert.ok(!eHappened, 'listeners are removed when parent window unloads'); + remover1(); + remover2(); + done(); + }); + + open().then(function(window) { + let { document, ele: ele2 } = makeEle(window); + + remover2 = gListen(window, ele2, 'click', function() { + eHappened = true; + }); + + windowPromise(window, 'unload').then(function() { + simulateClick(ele2); + simulateClick(ele1); + }); + close(window); + }); +} + +exports.testListenWorksOnUnload = function(assert, done) { + const loader = Loader(module); + const { listen } = loader.require('pathfinder/xul/listen'); + let { window, document, ele } = makeEle(); + + listen(window, ele, 'click', function() { + assert.fail('should not be here'); + }, false); + + let remover = gListen(window, ele, 'click', function() { + remover(); + assert.pass('ending listen unload test'); + done(); + }, false); + + loader.unload(); + simulateClick(ele); +} + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-menuitems.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-menuitems.js @@ -0,0 +1,169 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict' + +const windowUtils = require('sdk/deprecated/window-utils'); +const menuitems = require('pathfinder/ui/menuitems'); + +let window = windowUtils.activeBrowserWindow; +let document = window.document; +function $(id) document.getElementById(id); + +function createMI(options, test) { + test.equal(!$(options.id), true); + var mi = new menuitems.Menuitem(options); + return mi; +} + +exports.testMIDoesNotExist = function(assert) { + var options = { + id: "test-mi-dne", + label: "test" + }; + createMI(options, assert); + assert.equal(!!$(options.id), false, 'menuitem does not exists'); +}; + +exports.testMIDoesExist = function(assert) { + var options = { + id: "test-mi-exists", + label: "test", + menuid: 'menu_FilePopup' + }; + let mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.id, options.id, 'menuitem id is ok'); + assert.equal(menuitem.getAttribute('label'), options.label, 'menuitem label is ok'); + assert.equal(menuitem.parentNode.id, options.menuid, 'in the file menu'); + assert.equal(menuitem.getAttribute('disabled'), 'false', 'menuitem not disabled'); + assert.equal(menuitem.getAttribute('accesskey'), '', 'menuitem accesskey is ok'); + assert.equal(menuitem.getAttribute('class'), '', 'menuitem class is ok'); + assert.equal(menuitem.nextSibling, undefined, 'menuitem is last'); + assert.equal(menuitem.hasAttribute("checked"), false, 'menuitem not checked'); + mi.destroy(); + assert.ok(!$(options.id), 'menuitem is gone'); + assert.equal(menuitem.parentNode, null, 'menuitem has no parent'); +}; + +exports.testMIOnClick = function(assert, done) { + let options = { + id: "test-mi-onclick", + label: "test", + menuid: 'menu_FilePopup', + onCommand: function() { + mi.destroy(); + assert.pass('onCommand worked!'); + done(); + } + }; + + let e = document.createEvent("UIEvents"); + e.initUIEvent("command", true, true, window, 1); + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + menuitem.dispatchEvent(e); +}; + +exports.testMIDisabled = function(assert, done) { + let commandIsOK = false; + let count = 0; + let options = { + id: "test-mi-disabled", + label: "test", + disabled: true, + menuid: 'menu_FilePopup', + onCommand: function() { + count++; + if (!commandIsOK) { + assert.fail('onCommand was called, that is not ok'); + return; + } + + mi.destroy(); + assert.equal(count, 1, 'onCommand was called the correct number of times!'); + done(); + } + }; + + let e = document.createEvent("UIEvents"); + e.initUIEvent("command", true, true, window, 1); + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.getAttribute('disabled'), 'true', 'menuitem not disabled'); + menuitem.dispatchEvent(e); + mi.disabled = false; + assert.equal(menuitem.getAttribute('disabled'), 'false', 'menuitem not disabled'); + commandIsOK = true; + menuitem.dispatchEvent(e); +}; + +exports.testMIChecked = function(assert) { + let options = { + id: "test-mi-checked", + label: "test", + disabled: true, + menuid: 'menu_FilePopup', + checked: true + }; + + let mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.getAttribute("checked"), "true", 'menuitem checked'); + mi.checked = false; + assert.equal(menuitem.getAttribute("checked"), "false", 'menuitem checked'); + mi.destroy(); +}; + +exports.testMIClass = function(assert) { + let options = { + id: "test-mi-class", + label: "pizazz", + className: "pizazz", + menuid: 'menu_FilePopup', + }; + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.getAttribute('class'), 'pizazz', 'menuitem not disabled'); + mi.destroy(); +}; + +exports.testInsertBeforeExists = function(assert) { + let options = { + id: 'test-mi-insertbefore', + label: 'insertbefore', + insertbefore:'menu_FileQuitItem', + menuid: 'menu_FilePopup', + }; + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.nextSibling, $('menu_FileQuitItem'), 'menuitem not disabled'); + mi.destroy(); +}; + +exports.testInsertBeforeDoesNotExist = function(assert) { + let options = { + id: 'test-mi-insertbefore', + label: 'insertbefore', + insertbefore:'menu_ZZZDNE', + menuid: 'menu_FilePopup', + }; + + var mi = createMI(options, assert); + let menuitem = $(options.id); + assert.equal(!!menuitem, true, 'menuitem exists'); + assert.equal(menuitem.nextSibling, null, 'menuitem not disabled'); + mi.destroy(); +}; + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-panic.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-panic.js @@ -0,0 +1,103 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const panic = require('pathfinder/panic'); +const prefs = require('sdk/preferences/service'); +const { Loader } = require('sdk/test/loader'); + +const PREF_END_NAME = 'security.addon.panic_end'; + +// TEST: the inPanic variable and panic events +exports.testPanicInPanic = function(assert, done) { + assert.equal(panic.inPanic, false, "not in a panic"); + panic.once('start', function() { + assert.pass('"start" event was fired'); + assert.equal(panic.inPanic, true, "in a panic"); + + panic.once('end', function() { + assert.pass('"end" event was fired'); + assert.equal(panic.inPanic, false, "not in a panic"); + + done(); + }); + }); + + panic.panic(); +}; + +// TEST: on and off methods +exports.testPanicOnOff = function(assert, done) { + let count = 0; + + panic.on('start', function panicOn() { + panic.off('start', panicOn); + count++; + + panic.once('start', function() { + if (count > 1) { + assert.fail('panic.on was called too many times'); + } + else { + assert.pass('panic.on was only called once'); + } + + panic.once('end', function() { + done(); + }); + }); + + panic.once('end', function() { + panic.panic(50); + }); + }); + + panic.panic(); +}; + +// TEST: panic emits in multiple instances +exports.testPanicFiresInMultipleInstances = function(assert, done) { + let count = 0; + + let loader = Loader(module); + let panic2 = loader.require('panic'); + + let testCounter = function() { + if (++count < 2) return; + assert.pass('panic was fired on multiple instances'); + + panic.once('end', function() { + loader.unload(); + done(); + }); + }; + panic.once('start', testCounter); + panic2.once('start', testCounter); + + panic.panic(); +}; + +exports.testEndTimestamp = function(assert, done) { + let ms = 0; + let min = Date.now() + ms; + let endTimestamp; + + panic.once('end', function() { + let now = Date.now(); + let max = (now + ms); + + assert.ok(min <= endTimestamp, endTimestamp + ' is gte ' + min); + assert.ok(min <= now, now + ' event is gte to ' + min); + assert.ok(max >= endTimestamp, 'timestamp is lte to max'); + assert.ok(max >= now, 'end event is lte to max'); + + done(); + }); + + panic.panic(ms); + + endTimestamp = prefs.get(PREF_END_NAME); +}; + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-redirect.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-redirect.js @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const tabs = require('sdk/tabs'); +const { data } = require('sdk/self'); +const { Loader } = require("sdk/test/loader"); + +const { Redirect } = require('pathfinder/redirect'); + +function getData(url) { + return 'data:text/javascript;charset=utf-8,' + encodeURIComponent(url); +} + +exports.testRedirect = function(assert, done) { + const loader = Loader(module); + const httpd = loader.require('sdk/test/httpd'); + const { startServerAsync } = httpd; + + let serverPort = 8058; + let server = httpd.startServerAsync(serverPort); + const contents = "testRedirect"; + + server.registerPathHandler("/test.txt", function handle(request, response) { + response.write(contents); + }); + + let details = { + from: 'http://localhost:' + serverPort + '/test.txt', + to: getData('exptected') + }; + let redirect = Redirect(JSON.parse(JSON.stringify(details))); + + tabs.open({ + url: details.from, + onReady: function(tab) { + assert.equal(tab.url, details.to, 'The final destination is correct!'); + redirect.destroy(); + + server.stop(function() { + loader.unload(); + tab.close(done); + }); + } + }); +} + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-about.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-about.js @@ -0,0 +1,43 @@ +'use strict'; + +const { Loader } = require('sdk/test/loader'); +const tabs = require('sdk/tabs') + +function openTabGetContent(url, callback) { + tabs.open({ + url: 'about:test', + inBackground: true, + onReady: function(tab) { + let worker = tab.attach({ + contentScript: 'self.port.emit("body", document.body.innerHTML)' + }) + worker.port.on('body', function(msg) { + tab.close(function() { + callback(msg); + }); + }); + } + }) +} + +exports.testAddAboutWhat = function(assert, done) { + const loader = Loader(module); + const { add } = loader.require('pathfinder/scheme/about'); + + add({ + what: 'test', + url: 'data:text/html;charset=utf-8,<body>test</body>' + }); + + openTabGetContent('about:test', function(msg) { + assert.equal(msg, 'test', 'about:test content is "test"'); + loader.unload(); + openTabGetContent('about:test', function(msg) { + assert.notEqual(msg, 'test', 'about:test content is "test"'); + done(); + }); + }); + +} + +require('test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-resource.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-scheme-resource.js @@ -0,0 +1,3 @@ +'use strict'; + +require('pathfinder/scheme/resource'); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-storage.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-storage.js @@ -0,0 +1,134 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Loader } = require('sdk/test/loader'); +const { before, after } = require('sdk/test/utils'); + +const { get, set } = require('pathfinder/storage'); + +exports.testGetNothing = function(assert, done) { + get().then(function({ data }) { + assert.equal(data, '', 'the data is blank!'); + done(); + }); +}; + +exports.testSetThenGet = function(assert, done) { + const randomData = Math.random() + ''; + + // SET TO A RANDOM VALUE + set({ data: randomData }).then(function({ data }) { + assert.pass('setting was successful'); + assert.equal(data, randomData, 'the data returned from set is correct [' + randomData + ']'); + }, function(e) { + assert.fail('setting was unsuccessful'); + assert.fail(e); + }).then(function() get()).then(function({ data }) { + assert.pass('getting was successful'); + assert.equal(data, randomData, 'the data returned from get is correct [' + randomData + ']'); + }, function(e) { + assert.fail('getting was unsuccessful'); + assert.fail(e); + }) + // SET AGAIN + .then(function() set({ data: 'test' })).then(function({ data }) { + assert.pass('setting was successful'); + assert.equal(data, 'test', 'the data returned from set is correct [test]'); + }, function(e) { + assert.fail('setting was unsuccessful'); + assert.fail(e); + }).then(function() get()).then(function({ data }) { + assert.pass('getting was successful'); + assert.equal(data, 'test', 'the data returned from get is correct [test]'); + }, function(e) { + assert.fail('getting was unsuccessful'); + assert.fail(e); + }). + // SET TO BLANK + then(function() set({ data: '' })).then(function({ data }) { + assert.pass('setting was successful'); + assert.equal(data, '', 'the data returned from set is correct'); + }, function(e) { + assert.fail('setting was unsuccessful'); + assert.fail(e); + }).then(function() get()).then(function({ data }) { + assert.pass('getting was successful'); + assert.equal(data, '', 'the data returned from get is correct'); + }, function(e) { + assert.fail('getting was unsuccessful'); + assert.fail(e); + }). + // SET TO BLANK AGAIN + then(function() set({ data: '' })).then(function({ data }) { + assert.pass('setting was successful'); + assert.equal(data, '', 'the data returned from set is correct'); + }, function(e) { + assert.fail('setting was unsuccessful'); + assert.fail(e); + }).then(function() get()).then(function({ data }) { + assert.pass('getting was successful'); + assert.equal(data, '', 'the data returned from get is correct'); + }, function(e) { + assert.fail('getting was unsuccessful'); + assert.fail(e); + }).then(done, assert.fail); +}; + +exports.testSettingJSON = function(assert, done) { + const json = JSON.stringify({ + num: 1, + str: 'string', + bool: true, + obj: { x: 'x' }, + ary: [ 1, 2, 3 ] + }); + + set({ data: json }).then(function({ data }) { + assert.pass('setting was successful'); + assert.equal(data, json, 'the data returned from set is correct json'); + }, function(e) { + assert.fail('setting was unsuccessful'); + assert.fail(e); + }).then(function() get()).then(function({ data }) { + assert.pass('getting was successful'); + assert.equal(data, json, 'the data returned from get is correct json'); + }, function(e) { + assert.fail('getting was unsuccessful'); + assert.fail(e); + }). + // SET TO BLANK AGAIN + then(function() set({ data: '' })).then(function({ data }) { + assert.pass('setting was successful'); + assert.equal(data, '', 'the data returned from set is correct'); + }, function(e) { + assert.fail('setting was unsuccessful'); + assert.fail(e); + }).then(function() get()).then(function({ data }) { + assert.pass('getting was successful'); + assert.equal(data, '', 'the data returned from get is correct'); + }, function(e) { + assert.fail('getting was unsuccessful'); + assert.fail(e); + }).then(done, assert.fail); +}; + +before(exports, function(name, assert, done) { + let loader = Loader(module); + loader.require('pathfinder/storage'); + let file = loader.sandbox('pathfinder/storage').getStorageFile(); + assert.pass(file.exists(), false, 'the storage file DNE'); + loader.unload(); + done(); +}); +after(exports, function(name, assert, done) { + let loader = Loader(module); + loader.require('pathfinder/storage'); + let file = loader.sandbox('pathfinder/storage').getStorageFile(); + assert.pass(file.exists(), false, 'the storage file DNE'); + loader.unload(); + done(); +}); + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-toolbarbutton.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-toolbarbutton.js @@ -0,0 +1,165 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const windows = require("sdk/windows").browserWindows; +const toolbarbutton = require("pathfinder/ui/toolbarbutton"); +//const { Loader } = require('sdk/test/loader'); +const winUtils = require('sdk/window/utils'); + +const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +const TEST_ICON_URL = module.uri.replace(/[^\.\\\/]*\.js$/, "test.png"); +const TEST_ICON_BLACK_URL = module.uri.replace(/[^\.\\\/]*\.js$/, "black.png"); + +function $(id) winUtils.getMostRecentBrowserWindow().document.getElementById(id); + +function createToolbarButton(options, test) { + test.assertEqual(!$(options.id), true); + + var tbb = toolbarbutton.ToolbarButton(options); + test.assertEqual(!$(options.id), true); + + tbb.moveTo(options); + if (options.toolbarID) + test.assertEqual(!$(options.id), false); + + return tbb; +} + +function buttonExists(button, options, test) { + test.assertEqual(!button, false, 'test button'); + test.assertEqual(button.parentNode, $(options.toolbarID), 'test parent'); + test.assertEqual(button.id, options.id, 'test id'); + if (options.label) + test.assertEqual(button.label, options.label, 'test label'); + if (options.image) + test.assertEqual(button.image, options.image); + else + test.assertEqual(button.image, ""); +} + +exports.testTBBExists = function(test) { + var options = { + id: "test-tbb", + label: "test", + toolbarID: "nav-bar", + forceMove: true + }; + + var tbb = createToolbarButton(options, test); + buttonExists($(options.id), options, test); + tbb.destroy(); + test.assertEqual(!$(options.id), true); + var tbb = createToolbarButton(options, test); + tbb.destroy(); +}; + +exports.testTBBDoesNotExist = function(test) { + var options = { + id: "test-tbb2", + label: "test" + }; + var tbb = createToolbarButton(options, test); + var tbbEle = $(options.id); + test.assertEqual(!tbbEle, true, 'toolbar button dne'); + tbb.destroy(); +}; + +exports.testTBBLabelChange = function(test) { + test.waitUntilDone(); + + var options = { + id: "test-tbb3", + label: "test", + toolbarID: "nav-bar", + forceMove: true + }; + + let tbb = createToolbarButton(options, test); + buttonExists($(options.id), options, test); + tbb.label = 'test change'; + test.assertEqual($(options.id).label, 'test change', 'the label is changed'); + test.assertEqual(tbb.label, 'test change', 'the label is changed'); + + tbb.destroy(); + test.done(); +}; + +exports.testTBBPropertyChange = function(test) { + test.waitUntilDone(); + + var options = { + id: "test-tbb4", + label: "test", + toolbarID: "nav-bar", + forceMove: true, + image: TEST_ICON_URL, + tooltiptext: 'a' + }; + + let tbb = createToolbarButton(options, test); + buttonExists($(options.id), options, test); + test.assertEqual($(options.id).image, TEST_ICON_URL, 'the image is correct'); + test.assertEqual(tbb.image, TEST_ICON_URL, 'the image is correct'); + test.assertEqual(tbb.tooltiptext, 'a', 'the tooltiptext is correct'); + tbb.setIcon({url: TEST_ICON_BLACK_URL}); + test.assertEqual($(options.id).image, TEST_ICON_BLACK_URL, 'the image is changed'); + test.assertEqual(tbb.image, TEST_ICON_BLACK_URL, 'the image is changed'); + tbb.tooltiptext = 'b'; + test.assertEqual($(options.id).getAttribute('tooltiptext'), 'b', 'the tooltiptext is changed'); + test.assertEqual(tbb.tooltiptext, 'b', 'the tooltiptext is changed'); + + tbb.destroy(); + test.done(); +}; + +exports.testTBBIteratorWithNonBrowserWindow = function(test) { + test.waitUntilDone(); + + let scratchpad = winUtils.getMostRecentBrowserWindow().Scratchpad.openScratchpad(); + let options = { + id: "test-tbb5", + label: "TEST", + toolbarID: "nav-bar", + image: TEST_ICON_URL + }; + windows.open({ + onOpen: function(window) { + let tbb = createToolbarButton(options, test); + test.assertEqual(windows.length, 2); + + scratchpad.close(); + tbb.destroy(); + window.close(function() test.done()); + } + }) +}; + +exports.testTBBIterator2 = function(test) { + test.waitUntilDone(); + + let window1 = winUtils.getMostRecentBrowserWindow(); + let options = { + id: "test-tbb6", + label: "TEST", + toolbarID: "nav-bar", + image: TEST_ICON_URL + }; + let button = window1.document.createElementNS(NS_XUL, "toolbarbutton"); + button.setAttribute('id', options.id); + window1.document.getElementById(options.toolbarID).appendChild(button); + test.assert(!!$(options.id)); + + windows.open({ + onOpen: function(window) { + let tbb = createToolbarButton(options, test); + test.assertEqual(windows.length, 2); + + tbb.destroy(); + button.parentNode.removeChild(button); + window.close(function() test.done()); + } + }) +}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-unload+.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-unload+.js @@ -0,0 +1,150 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +var timer = require("sdk/timers"); +var { Cc,Ci } = require("chrome"); +const windowUtils = require("sdk/deprecated/window-utils"); +const { Loader } = require('sdk/test/loader'); + +function makeEmptyWindow() { + var xulNs = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + var blankXul = ('<?xml version="1.0"?>' + + '<?xml-stylesheet href="chrome://global/skin/" ' + + ' type="text/css"?>' + + '<window xmlns="' + xulNs + '">' + + '</window>'); + var url = "data:application/vnd.mozilla.xul+xml," + escape(blankXul); + var features = ["chrome", "width=10", "height=10"]; + + var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Ci.nsIWindowWatcher); + return ww.openWindow(null, url, null, features.join(","), null); +} + +exports.testUnloading = function(assert) { + var loader = Loader(module); + var {unload} = loader.require("pathfinder/addon/unload"); + var unloadCalled = 0; + + function unloader() { + unloadCalled++; + } + unload(unloader); + + function unloader2() unloadCalled++; + var removeUnloader2 = unload(unloader2); + + function unloader3() unloadCalled++; + unload(unloader3); + + // remove unloader2 + removeUnloader2(); + + loader.unload(); + + assert.equal(unloadCalled, 2, "Unloader functions are called on unload."); +}; + +exports.testUnloadingWindow = function(assert, done) { + var loader = Loader(module); + var {unload} = loader.require("pathfinder/addon/unload"); + var unloadCalled = 0; + var finished = false; + var myWindow; + + var delegate = { + onTrack: function(window) { + if (window == myWindow) { + assert.pass("onTrack() called with our test window"); + + let unloader = function unloader() { + unloadCalled++; + } + unload(unloader, window); + unload(unloader); + + timer.setTimeout(function() { + window.close(); + + assert.equal(unloadCalled, 1, "unloader was still called."); + + if (window.closed) { + assert.pass("window closed"); + } + else { + assert.fail("window is not closed!"); + } + + timer.setTimeout(function() { + assert.equal(unloadCalled, 1, "unloader was called."); + + unload(function() { + assert.equal(unloadCalled, 2, "two unloaders called."); + + if (finished) { + assert.pass("finished"); + done(); + } + else { + assert.fail("not finished!"); + } + }); + + loader.unload(); + }, 1); + }, 1); + } + }, + onUntrack: function(window) { + if (window == myWindow) { + assert.pass("onUntrack() called with our test window"); + + if (!finished) { + finished = true; + myWindow = null; + wt.unload(); + } + else { + assert.fail("finishTest() called multiple times."); + } + } + } + }; + + var wt = new windowUtils.WindowTracker(delegate); + myWindow = makeEmptyWindow(); +}; + +exports.testUnloaderExecutionOnWindowClose = function(assert, done) { + var loader = Loader(module); + var {unload} = loader.require("pathfinder/addon/unload"); + var unloadCalled = 0; + var finished = false; + var myWindow; + var unloaderRan = false; + + var delegate = { + onTrack: function(window) { + if (window != myWindow) return; + + unload(function() unloaderRan = true, window); + window.close(); + }, + onUntrack: function(window) { + if (window != myWindow) return; + + loader.require('sdk/timers').setTimeout(function() { + assert.ok(unloaderRan, 'test complete'); + loader.unload(); + done(); + }, 0); + } + }; + + var wt = new windowUtils.WindowTracker(delegate); + myWindow = makeEmptyWindow(); +}; + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userscripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userscripts.js @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + + + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.css b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.css diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-userstyles.js @@ -0,0 +1,116 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Loader } = require('sdk/test/loader'); + +const userstyles = require('userstyles'); + +const TEST_CSS_URL = module.uri.replace(/\.js$/, '.css'); +const TEST_FNF_URL = module.uri.replace(/\.js$/, '.x.css'); + +// TEST: userstyles.load +exports.testLoad = function(assert) { + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.'); + + userstyles.load(TEST_CSS_URL); + assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.'); + + userstyles.unload(TEST_CSS_URL); + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was unregistered.'); +}; + +// TEST: userstyles.load file not found +exports.testLoadFNF = function(assert) { + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is not registered.'); + + try { + userstyles.load(TEST_FNF_URL); + assert.fail('trying to load a file that does not exist should throw an error'); + } + catch(e) { + assert.pass('trying to load a file that does not exist throws an error'); + } + + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was not registered.'); +}; + +// TEST: userstyles.load for 'agent' type +exports.testLoadAgent = function(assert) { + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is not registered.'); + assert.equal(userstyles.registered(TEST_CSS_URL, {type: 'agent'}), false, 'css is not registered.'); + + userstyles.load(TEST_CSS_URL, {type: 'AgeNt'}); + assert.ok(userstyles.registered(TEST_CSS_URL, {type: 'AGENT'}), 'css was registered.'); + + try { + userstyles.unload(TEST_CSS_URL); + assert.fail('unregister did not throw an error'); + } + catch(e) { + assert.pass('unregister did throw an error'); + } + assert.equal(userstyles.registered(TEST_CSS_URL, {type: 'agent'}), true, 'css was not unregistered.'); + + userstyles.unload(TEST_CSS_URL, {type: 'agent'}); + assert.equal(userstyles.registered(TEST_CSS_URL, {type: 'agent'}), false, 'css was unregistered.'); +}; + +exports.testUnload = function(assert) { + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.'); + let loader = Loader(module); + + loader.require('userstyles').load(TEST_CSS_URL); + assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.'); + + loader.unload(); + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was unregistered.'); +} + +exports.testUnloadWithMultipleLoads = function(assert) { + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.'); + let loader = Loader(module); + + // first load + loader.require('userstyles').load(TEST_CSS_URL); + assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.'); + + // now unload + loader.require('userstyles').unload(TEST_CSS_URL); + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.'); + + // now load again + loader.require('userstyles').load(TEST_CSS_URL); + assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.'); + + // send addon unload message and see if we fail + loader.unload(); + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.'); +} + +exports.testUnloadWithMultipleLoaders = function(assert) { + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.'); + let loader = Loader(module); + + // first load + loader.require('userstyles').load(TEST_CSS_URL); + assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.'); + + // now unload + loader.require('userstyles').unload(TEST_CSS_URL); + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css is unregistered.'); + + // now load again + userstyles.load(TEST_CSS_URL); + assert.ok(userstyles.registered(TEST_CSS_URL), 'css was registered.'); + + // send addon unload message and see if we fail + loader.unload(); + assert.equal(userstyles.registered(TEST_CSS_URL), true, 'css is still registered.'); + + userstyles.unload(TEST_CSS_URL); + assert.equal(userstyles.registered(TEST_CSS_URL), false, 'css was unregistered.'); +} + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-web-panel.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test-web-panel.js @@ -0,0 +1,563 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +const { Loader } = require('sdk/test/loader'); +const { getMostRecentBrowserWindow } = require('sdk/window/utils'); +const { open, close, focus, promise: windowPromise } = require('sdk/window/helpers'); +const { setTimeout } = require('sdk/timers'); +const { isPrivate } = require('sdk/private-browsing'); +const { data } = require('sdk/self'); +const { fromIterator } = require('sdk/util/array'); +const { URL } = require('sdk/url'); + +const { WebPanel } = require('pathfinder/ui/web-panel'); +const { show, hide } = require('pathfinder/ui/sidebar/actions'); +const { isShowing } = require('pathfinder/ui/sidebar/state'); + +const BUILTIN_SIDEBAR_MENUITEMS = [ + 'menu_socialSidebar', + 'menu_historySidebar', + 'menu_bookmarksSidebar' +]; + +const WEB_PANEL_BROWSER_ID = 'web-panels-browser'; + +function isSidebarShowing(window) { + window = window || getMostRecentBrowserWindow(); + let sidebar = window.document.getElementById('sidebar-box'); + return !sidebar.hidden; +} + +function getSidebarMenuitems(window) { + window = window || getMostRecentBrowserWindow(); + return fromIterator(window.document.querySelectorAll('#viewSidebarMenu menuitem')); +} + +function getExtraSidebarMenuitems() { + let menuitems = getSidebarMenuitems(); + return menuitems.filter(function(mi) { + return BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) < 0; + }); +} + +function makeID(id) { + return 'pathfinder-sidebar-' + id; +} + +function simulateClick(ele) { + let window = ele.ownerDocument.defaultView; + let { document } = window; + var evt = document.createEvent("XULCommandEvent"); + evt.initCommandEvent("command", true, true, window, + 0, false, false, false, false, null); + ele.dispatchEvent(evt); +} + +exports.testSidebarBasicLifeCycle = function(assert, done) { + let testName = 'testSidebarBasicLifeCycle'; + let window = getMostRecentBrowserWindow(); + assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE'); + let sidebarXUL = window.document.getElementById('sidebar'); + assert.ok(sidebarXUL, 'sidebar xul element does exist'); + assert.ok(!getExtraSidebarMenuitems().length, 'there are no extra sidebar menuitems'); + + assert.equal(isSidebarShowing(window), false, 'sidebar is not showing 1'); + let sidebarDetails = { + id: testName, + title: 'test', + url: 'data:text/html;charset=utf-8,'+testName + }; + let sidebar = WebPanel(sidebarDetails); + + // test the sidebar attributes + for each(let key in Object.keys(sidebarDetails)) { + assert.equal(sidebarDetails[key], sidebar[key], 'the attributes match the input'); + } + + assert.pass('The Sidebar constructor worked'); + + let extraMenuitems = getExtraSidebarMenuitems(); + assert.equal(extraMenuitems.length, 1, 'there is one extra sidebar menuitems'); + + let ele = window.document.getElementById(makeID(testName)); + assert.equal(ele, extraMenuitems[0], 'the only extra menuitem is the one for our sidebar.') + assert.ok(ele, 'sidebar element was added'); + assert.ok(ele.getAttribute('checked'), 'false', 'the sidebar is not displayed'); + assert.equal(ele.getAttribute('label'), sidebar.title, 'the sidebar title is the menuitem label') + + assert.equal(isSidebarShowing(window), false, 'sidebar is not showing 2'); + sidebar.on('show', function() { + assert.pass('the show event was fired'); + assert.equal(isSidebarShowing(window), true, 'sidebar is not showing 3'); + assert.equal(isShowing(sidebar), true, 'the sidebar is showing'); + assert.equal(ele.getAttribute('checked'), 'true', 'the sidebar is displayed'); + + sidebar.once('hide', function() { + assert.pass('the hide event was fired'); + assert.equal(ele.getAttribute('checked'), 'false', 'the sidebar menuitem is not checked'); + assert.equal(isShowing(sidebar), false, 'the sidebar is not showing'); + assert.equal(isSidebarShowing(window), false, 'the sidebar elemnt is hidden'); + + sidebar.once('detach', function() { + sidebar.destroy(); + + let sidebarMI = getSidebarMenuitems(); + for each (let mi in sidebarMI) { + assert.ok(BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) >= 0, 'the menuitem is for a built-in sidebar') + assert.equal(mi.getAttribute('checked'), "false", 'no sidebar menuitem is checked'); + } + + assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE'); + assert.pass('calling destroy worked without error'); + + done(); + }); + }); + + sidebar.hide(); + assert.pass('hiding sidebar..'); + }); + + sidebar.show(); + assert.pass('showing sidebar..'); +} + +exports.testSideBarIsInNewWindows = function(assert, done) { + let testName = 'testSideBarOnNewWindow'; + let sidebar = WebPanel({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+testName + }); + + let startWindow = getMostRecentBrowserWindow(); + let ele = startWindow.document.getElementById(makeID(testName)); + assert.ok(ele, 'sidebar element was added'); + + open().then(function(window) { + let ele = window.document.getElementById(makeID(testName)); + assert.ok(ele, 'sidebar element was added'); + + sidebar.destroy(); + assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE'); + assert.ok(!startWindow.document.getElementById(makeID(testName)), 'sidebar id DNE'); + + close(window).then(done, assert.fail); + }) +} + +exports.testSideBarIsNotInNewPrivateWindows = function(assert, done) { + let testName = 'testSideBarOnNewWindow'; + let sidebar = WebPanel({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+testName + }); + + let startWindow = getMostRecentBrowserWindow(); + let ele = startWindow.document.getElementById(makeID(testName)); + assert.ok(ele, 'sidebar element was added'); + + open(null, { features: { private: true } }).then(function(window) { + let ele = window.document.getElementById(makeID(testName)); + assert.ok(isPrivate(window), 'the new window is private'); + assert.equal(ele, null, 'sidebar element was not added'); + + sidebar.destroy(); + assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE'); + assert.ok(!startWindow.document.getElementById(makeID(testName)), 'sidebar id DNE'); + + close(window).then(done, assert.fail); + }) +} + +exports.testSideBarIsShowingInNewWindows = function(assert, done) { + let testName = 'testSideBarIsShowingInNewWindows'; + let sidebar = WebPanel({ + id: testName, + title: testName, + url: URL('data:text/html;charset=utf-8,'+testName) + }); + + let startWindow = getMostRecentBrowserWindow(); + let ele = startWindow.document.getElementById(makeID(testName)); + assert.ok(ele, 'sidebar element was added'); + + let oldEle = ele; + sidebar.once('show', function() { + assert.pass('show event fired'); + + sidebar.once('attach', function() { + assert.pass('attach event fired'); + + sidebar.once('show', function() { + let window = getMostRecentBrowserWindow(); + assert.notEqual(startWindow, window, 'window is new'); + + let sb = window.document.getElementById('sidebar'); + if (sb && sb.docShell && sb.contentDocument && sb.contentDocument.getElementById('web-panels-browser')) { + end(); + } + else { + sb.addEventListener('DOMWindowCreated', end, false); + } + + function end() { + sb.removeEventListener('DOMWindowCreated', end, false); + let webPanelBrowser = sb.contentDocument.getElementById('web-panels-browser'); + + let ele = window.document.getElementById(makeID(testName)); + + assert.ok(ele, 'sidebar element was added 2'); + assert.equal(ele.getAttribute('checked'), 'true', 'the sidebar is checked'); + assert.notEqual(ele, oldEle, 'there are two different sidebars'); + + assert.equal(isShowing(sidebar), true, 'the sidebar is showing in new window'); + + webPanelBrowser.contentWindow.addEventListener('load', function onload() { + webPanelBrowser.contentWindow.addEventListener('load', onload, false); + + sidebar.destroy(); + + assert.equal(isShowing(sidebar), false, 'the sidebar is not showing'); + assert.ok(!isSidebarShowing(window), 'sidebar in most recent window is not showing'); + assert.ok(!isSidebarShowing(startWindow), 'sidebar in most start window is not showing'); + assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE'); + assert.ok(!startWindow.document.getElementById(makeID(testName)), 'sidebar id DNE'); + + setTimeout(function() { + close(window).then(done, assert.fail); + }); + }, false); + } + }); + + startWindow.OpenBrowserWindow(); + }); + }); + + show(sidebar); + assert.pass('showing the sidebar'); +} + +exports.testShowingOneSidebarAfterAnother = function(assert, done) { + let testName = 'testShowingOneSidebarAfterAnother'; + + let sidebar1 = WebPanel({ + id: testName + '1', + title: testName + '1', + url: 'data:text/html;charset=utf-8,'+ testName + 1 + }); + let sidebar2 = WebPanel({ + id: testName + '2', + title: testName + '2', + url: 'data:text/html;charset=utf-8,'+ testName + 2 + }); + + let window = getMostRecentBrowserWindow(); + let IDs = [ sidebar1.id, sidebar2.id ]; + + let extraMenuitems = getExtraSidebarMenuitems(window); + assert.equal(extraMenuitems.length, 2, 'there are two extra sidebar menuitems'); + + function testShowing(sb1, sb2, sbEle) { + assert.equal(isShowing(sidebar1), sb1); + assert.equal(isShowing(sidebar2), sb2); + assert.equal(isSidebarShowing(window), sbEle); + } + testShowing(false, false, false); + + sidebar1.once('show', function() { + testShowing(true, false, true); + for each (let mi in getExtraSidebarMenuitems(window)) { + let menuitemID = mi.getAttribute('id').replace(/^pathfinder-sidebar-/, ''); + assert.ok(IDs.indexOf(menuitemID) >= 0, 'the extra menuitem is for one of our test sidebars'); + assert.equal(mi.getAttribute('checked'), menuitemID == sidebar1.id ? 'true' : 'false', 'the test sidebar menuitem has the correct checked value'); + } + + sidebar2.once('show', function() { + testShowing(false, true, true); + for each (let mi in getExtraSidebarMenuitems(window)) { + let menuitemID = mi.getAttribute('id').replace(/^pathfinder-sidebar-/, ''); + assert.ok(IDs.indexOf(menuitemID) >= 0, 'the extra menuitem is for one of our test sidebars'); + assert.equal(mi.getAttribute('checked'), menuitemID == sidebar2.id ? 'true' : 'false', 'the test sidebar menuitem has the correct checked value'); + } + + sidebar1.destroy(); + sidebar2.destroy(); + + testShowing(false, false, false); + + done(); + }); + + show(sidebar2); + assert.pass('showing sidebar 2'); + }) + show(sidebar1); + assert.pass('showing sidebar 1'); +} + +exports.testSidebarUnload = function(assert, done) { + let loader = Loader(module); + + let testName = 'testSidebarUnload'; + let window = getMostRecentBrowserWindow(); + + assert.equal(isPrivate(window), false, 'the current window is not private'); + + let sidebar = loader.require('pathfinder/ui/web-panel').WebPanel({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+ testName, + onShow: function() { + assert.pass('onShow works for Sidebar'); + loader.unload(); + + let sidebarMI = getSidebarMenuitems(); + for each (let mi in sidebarMI) { + assert.ok(BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) >= 0, 'the menuitem is for a built-in sidebar') + assert.equal(mi.getAttribute('checked'), 'false', 'no sidebar menuitem is checked'); + } + assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE'); + assert.equal(isSidebarShowing(window), false, 'the sidebar is not showing'); + + done(); + } + }) + + sidebar.show(); + assert.pass('showing the sidebar'); +} + +exports.testRemoteContent = function(assert) { + let testName = 'testRemoteContent'; + try { + let sidebar = WebPanel({ + id: testName, + title: testName, + url: 'http://dne.xyz.mozilla.org' + }); + assert.ok('the web panel was created!'); + sidebar.destroy(); + } + catch(e) { + assert.fail('sidebar was not created..'); + } +} + +exports.testInvalidURL = function(assert) { + let testName = 'testInvalidURL'; + try { + let sidebar = WebPanel({ + id: testName, + title: testName, + url: 'http:mozilla.org' + }); + assert.pass('remote uris are fine'); + sidebar.destroy(); + } + catch(e) { + assert.ok(/The option "url" must be a valid URI./.test(e), 'invalid URIs are not acceptable'); + } +} + +exports.testInvalidURLType = function(assert) { + let testName = 'testInvalidURLType'; + try { + let sidebar = WebPanel({ + id: testName, + title: testName + }); + assert.fail('a bad sidebar was created..'); + sidebar.destroy(); + } + catch(e) { + assert.ok(/The option "url" must be a valid URI./.test(e), 'invalid URIs are not acceptable'); + } +} + +exports.testInvalidTitle = function(assert) { + let testName = 'testInvalidTitle'; + try { + let sidebar = WebPanel({ + id: testName, + title: '', + url: 'data:text/html;charset=utf-8,'+testName + }); + assert.fail('a bad sidebar was created..'); + sidebar.destroy(); + } + catch(e) { + assert.equal('The option "title" must be one of the following types: string', e.message, 'invalid titles are not acceptable'); + } +} + +exports.testInvalidID = function(assert) { + let testName = 'testInvalidTitle'; + try { + let sidebar = WebPanel({ + id: '!', + title: testName, + url: 'data:text/html;charset=utf-8,'+testName + }); + assert.fail('a bad sidebar was created..'); + sidebar.destroy(); + } + catch(e) { + assert.ok(/The option "id" must be a valid alphanumeric id/.test(e), 'invalid ids are not acceptable'); + } +} + +exports.testSidebarIsNotOpenInNewPrivateWindow = function(assert, done) { + let testName = 'testSidebarIsNotOpenInNewPrivateWindow'; + let window = getMostRecentBrowserWindow(); + + let sidebar = WebPanel({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+testName + }); + + sidebar.on('show', function() { + assert.equal(isPrivate(window), false, 'the new window is not private'); + assert.equal(isSidebarShowing(window), true, 'the sidebar is showing'); + assert.equal(isShowing(sidebar), true, 'the sidebar is showing'); + + let window2 = window.OpenBrowserWindow({private: true}); + windowPromise(window2, 'load').then(focus).then(function() { + // TODO: find better alt to setTimeout... + setTimeout(function() { + assert.equal(isPrivate(window2), true, 'the new window is private'); + assert.equal(isSidebarShowing(window), true, 'the sidebar is showing in old window still'); + assert.equal(isSidebarShowing(window2), false, 'the sidebar is not showing in the new private window'); + assert.equal(isShowing(sidebar), false, 'the sidebar is not showing'); + sidebar.destroy(); + close(window2).then(done); + }, 500) + }) + }); + + sidebar.show(); +} + +// TEST: edge case where web panel is destroyed while loading +exports.testDestroyEdgeCaseBug = function(assert, done) { + let testName = 'testDestroyEdgeCaseBug'; + let window = getMostRecentBrowserWindow(); + let sidebar = WebPanel({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+testName + }); + + // NOTE: purposely not listening to show event b/c the event happens + // between now and then. + sidebar.show(); + + assert.equal(isPrivate(window), false, 'the new window is not private'); + assert.equal(isSidebarShowing(window), true, 'the sidebar is showing'); + + //assert.equal(isShowing(sidebar), true, 'the sidebar is showing'); + + open(null, { features: { private: true } }).then(focus).then(function(window2) { + assert.equal(isPrivate(window2), true, 'the new window is private'); + assert.equal(isSidebarShowing(window2), false, 'the sidebar is not showing'); + assert.equal(isShowing(sidebar), false, 'the sidebar is not showing'); + + sidebar.destroy(); + assert.pass('destroying the sidebar'); + + close(window2).then(function() focus(window)).then(function(window) { + let loader = Loader(module); + + assert.equal(window, getMostRecentBrowserWindow(), 'window is current window'); + assert.equal(isPrivate(window), false, 'the current window is not private!'); + + let sidebar = loader.require('pathfinder/ui/web-panel').WebPanel({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+ testName, + onShow: function() { + assert.pass('onShow works for Sidebar'); + loader.unload(); + + let sidebarMI = getSidebarMenuitems(); + for each (let mi in sidebarMI) { + assert.ok(BUILTIN_SIDEBAR_MENUITEMS.indexOf(mi.getAttribute('id')) >= 0, 'the menuitem is for a built-in sidebar') + assert.equal(mi.getAttribute('checked'), 'false', 'no sidebar menuitem is checked'); + } + assert.ok(!window.document.getElementById(makeID(testName)), 'sidebar id DNE'); + assert.equal(isSidebarShowing(window), false, 'the sidebar is not showing'); + + done(); + } + }) + + assert.pass('showing the sidebar1'); + sidebar.show(); + assert.pass('showing the sidebar2'); + + }); + }); +} + +exports.testClickingACheckedMenuitem = function(assert, done) { + let testName = 'testClickingACheckedMenuitem'; + let window = getMostRecentBrowserWindow(); + let sidebar = WebPanel({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+testName, + onShow: function() { + sidebar.once('hide', function() { + assert.pass('clicking the menuitem after the sidebar has shown hides it.'); + sidebar.destroy(); + done(); + }); + let menuitem = window.document.getElementById(makeID(sidebar.id)); + simulateClick(menuitem); + } + }); + + sidebar.show(); +} + +exports.testAddonGlobalDNE = function(assert, done) { + let testName = 'testAddonGlobal'; + let url = 'data:text/html;charset=utf-8,'+encodeURIComponent('<script>window.addEventListener("message", function() window.postMessage({ addon: !!window.addon }, "*"), false)</script>'); + let sidebar = WebPanel({ + id: testName, + title: testName, + url: url + }); + + sidebar.on('attach', function(worker) { + assert.pass('sidebar was attached'); + assert.ok(!!worker, 'attach event has worker'); + + let sidebarXUL = getMostRecentBrowserWindow().document.getElementById('sidebar'); + let window = sidebarXUL.contentDocument.getElementById(WEB_PANEL_BROWSER_ID).contentWindow; + + window.addEventListener('load', function() { + let count = 0; + window.addEventListener('message', function({ data: msg }) { + if (++count != 2) return; + + assert.equal(msg.addon, false, 'the addon global DNE'); + + sidebar.destroy(); + + done(); + }, false); + window.postMessage('', '*'); + }, false); + + }); + + show(sidebar); +} + +require('sdk/test').run(exports); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/node_modules/pathfinder/test/test.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/options.xul b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/options.xul @@ -1,8 +0,0 @@ -<?xml version="1.0" ?> -<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - <setting data-jetpack-id="jid1-KtlZuoiikVfFew@jetpack" pref="extensions.jid1-KtlZuoiikVfFew@jetpack.whitelist" pref-name="whitelist" title="Whitelist domain, separated by comma, omit protocol, e.g.: gnu.org, wildcard is *" type="string"/> - <setting data-jetpack-id="jid1-KtlZuoiikVfFew@jetpack" pref="extensions.jid1-KtlZuoiikVfFew@jetpack.complaint_tab" pref-name="complaint_tab" title="Display complaint tab on sites where nonfree nontrivial JavaScript is detected" type="bool"/> - <setting data-jetpack-id="jid1-KtlZuoiikVfFew@jetpack" pref="extensions.jid1-KtlZuoiikVfFew@jetpack.display_notifications" pref-name="display_notifications" title="Display notifications of the JavaScript code being analyzed by LibreJS." type="bool"/> - <setting data-jetpack-id="jid1-KtlZuoiikVfFew@jetpack" pref="extensions.jid1-KtlZuoiikVfFew@jetpack.complaint_email_subject" pref-name="complaint_email_subject" title="Complaint email subject" type="string">Initial subject line used in complaint emails</setting> - <setting data-jetpack-id="jid1-KtlZuoiikVfFew@jetpack" pref="extensions.jid1-KtlZuoiikVfFew@jetpack.complaint_email_body" pref-name="complaint_email_body" title="Complaint email body" type="string">Initial body text used in complaint emails</setting> -</vbox> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/package.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/package.json @@ -0,0 +1,66 @@ +{ + "name": "librejs", + "license": "GPL-3.0+", + "author": "Loic J. Duros", + "homepage": "https://gnu.org/software/librejs/", + "repository": "http://git.savannah.gnu.org/cgit/librejs.git/", + "version": "6.0.10", + "title": "GNU LibreJS", + "id": "jid1-KtlZuoiikVfFew@jetpack", + "description": "GNU LibreJS is an add-on for Mozilla-based browsers (IceCat, Firefox, Abrowser, Iceweasel)\n that prevents the execution of nonfree nontrivial JavaScript as described in \"The Javascript Trap\": http://www.gnu.org/philosophy/javascript-trap.html", + "main": "lib/main.js", + "icon": "data/widget/images/librejs-64.png", + "dependencies": { + "menuitem": "0.0.5", + "notification-box": "0.1.1" + }, + "permissions": { + "private-browsing": true, + "unsafe-content-script": true + }, + "preferences": [ + { + "name": "whitelist", + "title": "Whitelist domain, separated by comma, omit protocol, e.g.: gnu.org, wildcard is *", + "type": "string", + "value": "" + }, + { + "name": "complaint_tab", + "title": "Display complaint tab on sites where nonfree nontrivial JavaScript is detected", + "type": "bool", + "value": true + }, + { + "name": "display_notifications", + "title": "Display notifications of the JavaScript code being analyzed by LibreJS.", + "type": "bool", + "value": false + }, + { + "name": "complaint_email_subject", + "title": "Complaint email subject", + "description": "Initial subject line used in complaint emails", + "type": "string", + "value": "Please make your JavaScript free" + }, + { + "name": "complaint_email_body", + "title": "Complaint email body", + "description": "Initial body text used in complaint emails", + "type": "string", + "value": "I could not use your site because it requires running JavaScript code which is not free software. Since a nonfree program disrespects the user's freedom, I decided not to run it. \\n\\nSee http://gnu.org/philosophy/javascript-trap.html for more information, and please make your JavaScript code free." + } + ], + "scripts": { + "pretest": "jshint lib data", + "test": "jpm test -v" + }, + "jscsConfig": { + "preset": "google", + "validateIndentation": 4 + }, + "jshintConfig": { + "moz": true + } +} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/content/display-panel.html b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/display_panel/content/display-panel.html @@ -1,72 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>Display JS Monitoring Panel</title> -<link rel="stylesheet" type="text/css" href="./panel-styles.css"/> - -<!-- /** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2014 Loic J. Duros - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ ---> -</head> - -<body> - <div class="title-area"> - <div> - <a class="libre" - id="ljs-settings" - href="javascript:void" - title="LibreJS Whitelist Settings"> - <h1 class="libre">LibreJS</h1> - </a> - </div> - <div> - <a target="_blank" href="https://www.gnu.org/software/librejs/" - id="librejs-web-link" - >gnu.org/software/librejs</a> - </div> - <div> - <strong>LibreJS 6.0.10.20150620</strong> - </div> - </div> - - <div id="info"> - <div id="dryrun"> - <h2 class="dryrun-js"></h2> - <ul class="dryrun-js"></ul> - </div> - - <div id="accepted"> - <h2 class="accepted-js"></h2> - <ul class="accepted-js"></ul> - </div> - - <div id="blocked"> - <h2 class="blocked-js"></h2> - <ul class="blocked-js"> - </div> - - <div id="librejs-web-labels-pages"> - <h2></h2> - <ul></ul> - </div> - </div> -</body> -</html> diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/magnet-links.txt b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/licenses/magnet-links.txt @@ -1,28 +0,0 @@ - -magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt -magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt -magnet:?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt -magnet:?xt=urn:btih:89a97c535628232f2f3888c2b7b8ffd4c078cec0&dn=Boost-1.0.txt -magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt -magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt -magnet:?xt=urn:btih:e8823381a12cbaec8042d8f5928ed9ca427ae6ed&dn=clear-bsd.txt -magnet:?xt=urn:btih:84143bc45939fc8fa42921d619a95462c2031c5c&dn=cpal-1.0.txt -magnet:?xt=urn:btih:4c6a2ad0018cd461e9b0fc44e1b340d2c1828b22&dn=epl-1.0.txt -magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt -magnet:?xt=urn:btih:0c9737ee7c3f64a549ae792605960b900d0bab7f&dn=freebsd.txt -magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt -magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt -magnet:?xt=urn:btih:035da57b2e51467406d7f737ce130844ceb555e1&dn=illinois-NCSA.txt -magnet:?xt=urn:btih:34b1392ce6108db166bd9ee4a37e655c67891e5b&dn=imlib2.txt -magnet:?xt=urn:btih:3254dcf4f9d9dadad8dfb4951177854d5d0e2491&dn=IntelACPI.txt -magnet:?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt -magnet:?xt=urn:btih:fcd495f3ca5fb96b147041401bcf213eec0a6439&dn=lgpl-2.0.txt -magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt -magnet:?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt -magnet:?xt=urn:btih:2f25cfbac271643d1e41a754034e8daedeb8a281&dn=magnet-links.txt -magnet:?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt -magnet:?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt -magnet:?xt=urn:btih:5866afca5f37889c0c1fdd108f4922d4fcdb5e3d&dn=unlicense.txt -magnet:?xt=urn:btih:723febf9f6185544f57f0660a41489c7d6b4931b&dn=wtfpl.txt -magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt -magnet:?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/script_libraries/script-libraries.json b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/script_libraries/script-libraries.json @@ -1,1567 +0,0 @@ -{ - "9d6f8bdcadd59eba977e9e31066bf393c9fdf8a4": { - "filename": "http://code.jquery.com/jquery-1.0.4.js", - "result": "[freelib]" - }, - "31555f340a206de7622fb760718ef4a1b296ed44": { - "filename": "http://code.jquery.com/jquery-1.1.js", - "result": "[freelib]" - }, - "88c03b5c437ac3551661ecfbe6e1de155c3099c4": { - "filename": "http://code.jquery.com/jquery-1.0.pack.js", - "result": "[freelib]" - }, - "08341cd159e29f561ca0ec16c99bf4b85e43d30f": { - "filename": "http://code.jquery.com/jquery-1.0.1.pack.js", - "result": "[freelib]" - }, - "84b1514a01def3bc0b52f6fa03d0d9fa349bef72": { - "filename": "http://code.jquery.com/jquery-1.0.2.pack.js", - "result": "[freelib]" - }, - "d3b30b0fead39e4c40fb0c91408e74439020a279": { - "filename": "http://code.jquery.com/jquery-1.0.2.js", - "result": "[freelib]" - }, - "fa05290dadfb7d2659a55c50b77595e23f999a74": { - "filename": "http://code.jquery.com/jquery-1.0.1.js", - "result": "[freelib]" - }, - "4a2c9fd552e1ca9ad66feaaad365990b1e664a8f": { - "filename": "http://code.jquery.com/jquery-1.0.4.pack.js", - "result": "[freelib]" - }, - "ddb4126bf4713cb4e0f2310401e58cb9e3f98997": { - "filename": "http://code.jquery.com/jquery-1.0.3.pack.js", - "result": "[freelib]" - }, - "4c12e01d990bd2b1075812d9f28e3ffa50ca59df": { - "filename": "http://code.jquery.com/jquery-1.0.3.js", - "result": "[freelib]" - }, - "16306f8187df578589821e6eb6b807ac4d467d1f": { - "filename": "http://code.jquery.com/jquery-1.1.pack.js", - "result": "[freelib]" - }, - "24dd74d65d2e02aae973af97ebbb31b9820a5bbb": { - "filename": "http://code.jquery.com/jquery-1.1.1.pack.js", - "result": "[freelib]" - }, - "24fdaa88685c8b2dadcc94559ceef318fdcd115b": { - "filename": "http://code.jquery.com/jquery-1.1.1.js", - "result": "[freelib]" - }, - "07c089df7b7a5da16f434870087d6b0e1c45d3b5": { - "filename": "http://code.jquery.com/jquery-1.1.2.pack.js", - "result": "[freelib]" - }, - "788bb58005b75a004cd7abbd26f942eea0391f47": { - "filename": "http://code.jquery.com/jquery-1.1.2.js", - "result": "[freelib]" - }, - "a7e07121debf460f86aa77073676c1e936478c22": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.3.js", - "result": "[freelib]" - }, - "d0d4200eedc83fe692dd65aeab5a548bfe840d06": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.3.1.pack.js", - "result": "[freelib]" - }, - "e1c9252b3e60673e4fa1bb1648cb18cd33139535": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.3.1.js", - "result": "[freelib]" - }, - "0c80055d513ce3103bb70ca956be005f63e32922": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.4.pack.js", - "result": "[freelib]" - }, - "5af7abb29b3b091080db17e53ef6ddcfa555dbe6": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.1.4.js", - "result": "[freelib]" - }, - "e0c497fc264d7706da23235266ed52acf2c7b89a": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.min.js", - "result": "[freelib]" - }, - "3aca6488dfb65cf0e600a7a70376ca1354b7377c": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.js", - "result": "[freelib]" - }, - "0cafb88edcaebad82c207cdf124de1889364c9f3": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.1.min.js", - "result": "[freelib]" - }, - "384cbfe95d92a30d7c86ac07ea5de56f79c15f6a": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.1.js", - "result": "[freelib]" - }, - "2710cce192fcc4dc676d9572cd852f104ea59387": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.2.pack.js", - "result": "[freelib]" - }, - "6869cb783670d6a4923aaccfe4331015961ed8d6": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.4.pack.js", - "result": "[freelib]" - }, - "55c7f265deba4afc1335071fafbbf7fda8f02bbe": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.6.js", - "result": "[freelib]" - }, - "f3abd53f3725675e3e049c414749e16df11951ba": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.js", - "result": "[freelib]" - }, - "7b9e8594368d30387059e5fdef9d662095dbbf7a": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.min.js", - "result": "[freelib]" - }, - "6be187a67b639b65dc8427eb8e790e42bbe4d7dd": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.1.js", - "result": "[freelib]" - }, - "fed603a4db640b82de54b246de4be7a1cffa8780": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js", - "result": "[freelib]" - }, - "f0b95e99225f314fbe37ccf6b74ce2f916c517de": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.2.js", - "result": "[freelib]" - }, - "3dc9f7c2642efff4482e68c9d9df874bf98f5bcb": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js", - "result": "[freelib]" - }, - "ea6cc893792569fdbb344181034eb668261f2b24": { - "filename": "http://code.jquery.com/jquery-1.5.1.js", - "result": "[freelib]" - }, - "fe7b4d1b72fc22fc397f3df3f1fd891c78f8fc96": { - "filename": "http://code.jquery.com/jquery-1.5.2.min.js", - "result": "[freelib]" - }, - "b509dd44ba3f9c72cf8bba6fcb5f06fae15cabf6": { - "filename": "http://code.jquery.com/jquery-1.5.2.js", - "result": "[freelib]" - }, - "22c1eefcce5be20a3e0966f5bcdf88ed81e9f5e7": { - "filename": "http://code.jquery.com/jquery-1.6.1.js", - "result": "[freelib]" - }, - "7fa300666dadade0d006e4c496bf1c85f4b0ab0c": { - "filename": "http://code.jquery.com/jquery-1.6.2.min.js", - "result": "[freelib]" - }, - "eeee9d4604e71f2e01b818fc1439f7b5baf1be7a": { - "filename": "http://code.jquery.com/jquery-1.6.2.js", - "result": "[freelib]" - }, - "aee58a81bea80c20176c61ff03caaf0aa273f9a1": { - "filename": "http://code.jquery.com/jquery-1.6.3.min.js", - "result": "[freelib]" - }, - "61a11f601d70a331de6444c11e72eab2ffd86427": { - "filename": "http://code.jquery.com/jquery-1.6.4.min.js", - "result": "[freelib]" - }, - "3e5c6d7c6e09965d36df8c1e3d9dca6462c41ec1": { - "filename": "http://code.jquery.com/jquery-1.6.3.js", - "result": "[freelib]" - }, - "921e7702ac9e4c4a4bca052b7bc83b0304440ee3": { - "filename": "http://code.jquery.com/jquery-1.6.4.js", - "result": "[freelib]" - }, - "13184e03cd6a0fc0020cf5ad4eee3d8cb3fadac1": { - "filename": "http://code.jquery.com/jquery-1.7.min.js", - "result": "[freelib]" - }, - "7f389928e5f9d3cb2ae273ae1a6913741d18f0a6": { - "filename": "http://code.jquery.com/jquery-1.7.js", - "result": "[freelib]" - }, - "b47730ffaec4272a8a01756af2ef13ecea1c4e92": { - "filename": "http://code.jquery.com/jquery-1.7.1.js", - "result": "[freelib]" - }, - "0b6da89c21e1dd2093fb26366dd90ffeea635c6a": { - "filename": "http://code.jquery.com/jquery-1.7.1.min.js", - "result": "[freelib]" - }, - "7c64f79dbeeebaa7accd13bf68302c7adb195d7d": { - "filename": "http://code.jquery.com/jquery-1.7.2.min.js", - "result": "[freelib]" - }, - "0d7896e2bb23f88e26e52b22a075350b354df447": { - "filename": "http://code.jquery.com/jquery-1.7.2.js", - "result": "[freelib]" - }, - "0eaabd478dd9538ac53334276b8ff784180140a6": { - "filename": "http://code.jquery.com/jquery-1.8.0.js", - "result": "[freelib]" - }, - "b567b6dd8cb0cb5c1183e55d2f2d1466f32edb39": { - "filename": "http://code.jquery.com/jquery-1.8.2.min.js", - "result": "[freelib]" - }, - "229d5537173d1f006b744b014a28f64912988c61": { - "filename": "http://code.jquery.com/jquery-1.8.2.js", - "result": "[freelib]" - }, - "8b6babff47b8a9793f37036fd1b1a3ad41d38423": { - "filename": "http://code.jquery.com/jquery-1.8.3.min.js", - "result": "[freelib]" - }, - "49a6d1346f3d5a167331a8a5de4f34b5fcc1f6d0": { - "filename": "http://code.jquery.com/jquery-1.8.3.js", - "result": "[freelib]" - }, - "002da8cbe90fcf32fbdebb72386125079e3805ee": { - "filename": "http://code.jquery.com/jquery-1.9.0.min.js", - "result": "[freelib]" - }, - "bfc05b695dfa4f23e11d04b84993585da7a764bf": { - "filename": "http://code.jquery.com/jquery-1.9.0.js", - "result": "[freelib]" - }, - "6c6f10e003ad0c7f462802c0e6422971577c3532": { - "filename": "http://code.jquery.com/jquery-1.8.1.min.js", - "result": "[freelib]" - }, - "45efe8797f5a875878fec7fdaaa90d99532dbf16": { - "filename": "http://code.jquery.com/jquery-1.8.1.js", - "result": "[freelib]" - }, - "ebc4e804054a68c177e9c67cc58e7960d3a8706f": { - "filename": "http://code.jquery.com/jquery-1.8.0.min.js", - "result": "[freelib]" - }, - "ae49e56999d82802727455f0ba83b63acd90a22b": { - "filename": "http://code.jquery.com/jquery-1.9.1.min.js", - "result": "[freelib]" - }, - "9257afd2d46c3a189ec0d40a45722701d47e9ca5": { - "filename": "http://code.jquery.com/jquery-1.9.1.js", - "result": "[freelib]" - }, - "348ab13488f5ab45e048dfb39bb4bc8ed9d840c2": { - "filename": "http://code.jquery.com/jquery-1.10.0.js", - "result": "[freelib]" - }, - "19715ffee604b54e95a0e9db76f6de2b5125c29e": { - "filename": "http://code.jquery.com/jquery-1.10.0.min.js", - "result": "[freelib]" - }, - "b39b6f7d8c5f62a40960ded5c40cc288c10b438d": { - "filename": "http://code.jquery.com/jquery-1.10.1.js", - "result": "[freelib]" - }, - "161b78ec52f28657a835e4a5423f03782fd35806": { - "filename": "http://code.jquery.com/jquery-1.10.1.min.js", - "result": "[freelib]" - }, - "1d85f0f3464e5e49b0522744bf7314e176ac76d9": { - "filename": "http://code.jquery.com/jquery-1.10.2.js", - "result": "[freelib]" - }, - "0511abe9863c2ea7084efa7e24d1d86c5b3974f1": { - "filename": "http://code.jquery.com/jquery-1.10.2.min.js", - "result": "[freelib]" - }, - "6945741107601d402c70a13ce46eb72fd1168bc8": { - "filename": "http://code.jquery.com/jquery-1.11.0.js", - "result": "[freelib]" - }, - "b66ed708717bf0b4a005a4d0113af8843ef3b8ff": { - "filename": "http://code.jquery.com/jquery-1.11.0.min.js", - "result": "[freelib]" - }, - "73e5d044bd153dd912930e8be433059454ce19cd": { - "filename": "http://code.jquery.com/jquery-1.11.1.js", - "result": "[freelib]" - }, - "d6c1f41972de07b09bfa63d2e50f9ab41ec372bd": { - "filename": "http://code.jquery.com/jquery-1.11.1.min.js", - "result": "[freelib]" - }, - "8130544c215fe5d1ec081d83461bf4a711e74882": { - "filename": "http://code.jquery.com/jquery-1.11.2.min.js", - "result": "[freelib]" - }, - "5b57851b09022c5e5f3a5fd08152b2dc12671974": { - "filename": "http://code.jquery.com/jquery-1.11.2.js", - "result": "[freelib]" - }, - "276c87ff3e1e3155679c318938e74e5c1b76d809": { - "filename": "http://code.jquery.com/jquery-1.11.3.min.js", - "result": "[freelib]" - }, - "96c73f3774471cc8378c77a64ecf09b7f625d8b7": { - "filename": "http://code.jquery.com/jquery-1.11.3.js", - "result": "[freelib]" - }, - "41b4bfbaa96be6d1440db6e78004ade1c134e276": { - "filename": "http://code.jquery.com/jquery-2.1.3.min.js", - "result": "[freelib]" - }, - "1852661bd11a09ca9b9cb63d1aa6ff390fffaf4e": { - "filename": "http://code.jquery.com/jquery-2.1.3.js", - "result": "[freelib]" - }, - "43dc554608df885a59ddeece1598c6ace434d747": { - "filename": "http://code.jquery.com/jquery-2.1.4.min.js", - "result": "[freelib]" - }, - "0fed45ad7a48ace869bc725ca474ad86a1ef1562": { - "filename": "http://code.jquery.com/jquery-2.1.4.js", - "result": "[freelib]" - }, - "0be05c714a7e6cf28fe692629ece5b3769901dca": { - "filename": "http://code.jquery.com/jquery-2.0.0.min.js", - "result": "[freelib]" - }, - "79db35e3a94da9ce724c4d3c8ccc5d1864b23a95": { - "filename": "http://code.jquery.com/jquery-2.0.0.js", - "result": "[freelib]" - }, - "d193cc22196566fce6b7a54d483f8ca55b38a2f5": { - "filename": "http://code.jquery.com/jquery-2.0.1.js", - "result": "[freelib]" - }, - "2a35d61baf7dde4a800b08fd7b495a62a8a1e620": { - "filename": "http://code.jquery.com/jquery-2.0.1.min.js", - "result": "[freelib]" - }, - "37fc3e651159cf6b9353a3f6f3bfe6e5e63e0092": { - "filename": "http://code.jquery.com/jquery-2.0.2.js", - "result": "[freelib]" - }, - "1e0331b6dd11e6b511d2e3d75805f5ccdb3b83df": { - "filename": "http://code.jquery.com/jquery-2.0.2.min.js", - "result": "[freelib]" - }, - "ad73590c92b4c3f08d02a0751ba4e4aef658daa0": { - "filename": "http://code.jquery.com/jquery-2.0.3.js", - "result": "[freelib]" - }, - "fbf9c77d0c4e3c34a485980c1e5316b6212160c8": { - "filename": "http://code.jquery.com/jquery-2.0.3.min.js", - "result": "[freelib]" - }, - "0fe3e567e0776226ee98326ba8cae7680683c112": { - "filename": "http://code.jquery.com/jquery-2.1.0.js", - "result": "[freelib]" - }, - "98884258cbdb0d939fa2c5e74fc7ac9e56d8170f": { - "filename": "http://code.jquery.com/jquery-2.1.0.min.js", - "result": "[freelib]" - }, - "8d55aabf2b76486cc311fdc553a3613cad46aa3f": { - "filename": "http://code.jquery.com/jquery-2.1.1.js", - "result": "[freelib]" - }, - "afb90752e0a90c24b7f724faca86c5f3d15d1178": { - "filename": "http://code.jquery.com/jquery-2.1.1.min.js", - "result": "[freelib]" - }, - - "0b327b43256da9f57b78e3134aaecc2a4a5a3bad": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.js", - "result": "[freelib]" - }, - "01100f829bce3f074adcb6ae5309d9e769ef29fe": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js", - "result": "[freelib]" - }, - "5f99079e4564f94a1d5e45d22d6dc18acbb148da": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.js", - "result": "[freelib]" - }, - "a2035b74876c5212cfe3e4e35dfd070e74e8c3fd": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/jquery-ui.js", - "result": "[freelib]" - }, - "2a3fa481079f9e02043810cbeee6b5481abf51c0": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.20/jquery-ui.js", - "result": "[freelib]" - }, - "0881516b541abe68d79724c08c1a665872f8f2c2": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.js", - "result": "[freelib]" - }, - "85b15aef55b1eede971c7febd0c00ba04dc16edf": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.js", - "result": "[freelib]" - }, - "d9b48fef067caa58d4e1dec54801c22fe0ea7449": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js", - "result": "[freelib]" - }, - "990dbb08231ef9c9c59653051f5ac7c1e2185d46": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.js", - "result": "[freelib]" - }, - "2e140b943f459e383f569227b3e5569f0dbc6f34": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.js", - "result": "[freelib]" - }, - "53dd39212504739ac18790a4461b9a67c50f2728": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.js", - "result": "[freelib]" - }, - "5cd73db8238d48c08c88f12fe9e5b99b6fa644f7": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.js", - "result": "[freelib]" - }, - "0c3d725fac553c73368496769ff77c3045103704": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.js", - "result": "[freelib]" - }, - "e5de581f09ac990adae2b4aede35264f1dc5cd72": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.js", - "result": "[freelib]" - }, - "e1e87320b2d14e36a9bba1b637b5247645df7185": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.19/jquery-ui.js", - "result": "[freelib]" - }, - "8b71e136c6275d0eeed2b55b9e718a54ce343015": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.js", - "result": "[freelib]" - }, - "c71ddb1b3843c24e909a31595b7e873d7e6da45d": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.js", - "result": "[freelib]" - }, - "d5203dbbb97db1a68ca5a3adf265f17cdaea738d": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.js", - "result": "[freelib]" - }, - "1b96be82b697e835b903c6c22799c8e4e55e285c": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.js", - "result": "[freelib]" - }, - "2804fac51308f459c3eb9c3d20e7ee009a8ba31c": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.js", - "result": "[freelib]" - }, - "5d61b19cbee2f8047f518a58ceff7fdaeeb24921": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js", - "result": "[freelib]" - }, - "7f7859e006f0644a43a7294b50b39e7e9159b3a2": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.js", - "result": "[freelib]" - }, - "842cb8f83614f6de98f70fa7de2f866eecae7ab4": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.js", - "result": "[freelib]" - }, - "90fab357529f510e5134ad0dcdad3f654894d4fc": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.3/jquery-ui.js", - "result": "[freelib]" - }, - "960e36796c42dadf66fafb63bba6087c7d6e1d85": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.js", - "result": "[freelib]" - }, - "1f102103bea71c5e173a916137c563dc62a97cdb": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.js", - "result": "[freelib]" - }, - "61c88c8898ae6bd653737a9dae52209a98998def": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.js", - "result": "[freelib]" - }, - "b87f7150da2b0811ed143443af4038e3e2d41eda": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.js", - "result": "[freelib]" - }, - "9927afbb31df93a76977a676a933b7e3696d61ba": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js", - "result": "[freelib]" - }, - "7b6f5c747c19ad6fbe28957e4318559b45d89111": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/jquery-ui.min.js", - "result": "[freelib]" - }, - "429282063ca7f3bae9797d70a6f09f2e3e05458a": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js", - "result": "[freelib]" - }, - "e398b87b98ae72cbee9f7d3044189ea638f3f80c": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/jquery-ui.min.js", - "result": "[freelib]" - }, - "e9b5baec45507c35477aac5d19afbca8cad92426": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js", - "result": "[freelib]" - }, - "431b7ebb5e36d5af5e7890b782789ac983e28d00": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.19/jquery-ui.min.js", - "result": "[freelib]" - }, - "680f1bd5b4021dbac8b82d68a818d3a94f097ffd": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js", - "result": "[freelib]" - }, - "fc4c1a4691f3819ecd16eaefa68f96f764538f1e": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.min.js", - "result": "[freelib]" - }, - "1d97dd4111b504abc8f6dee45daf6f358aa40140": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.js", - "result": "[freelib]" - }, - "aff393e11d2122a6026df1e2f75d46de4ead89ff": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.js", - "result": "[freelib]" - }, - "d81b246f0f221f4d9a6eb74a8994c4041d2b7215": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.6.0/jquery-ui.js", - "result": "[freelib]" - }, - "8e8b0dccbacc70dc6406023be9e35dfa4f3a944e": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js", - "result": "[freelib]" - }, - "67070ff953d6b0f886083edba723f6d66fa6cbca": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.min.js", - "result": "[freelib]" - }, - "6952564ff6404bd93cb523f1634b451ac1cc8fec": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js", - "result": "[freelib]" - }, - "b48e01c35c1e6ad622386b9a3161bd1bf02723c8": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js", - "result": "[freelib]" - }, - "34d32c47711aa10bdeb196c55d489962296a64c4": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js", - "result": "[freelib]" - }, - "33f5808531e82f2f6e8859da3a765c4d8a0073d2": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js", - "result": "[freelib]" - }, - "973e1554af7d9240e059e38165f2e7b5fc7aa0a5": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js", - "result": "[freelib]" - }, - "ae74362cdb2fadb2eee6c962f47f1e33af51c79d": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.20/jquery-ui.min.js", - "result": "[freelib]" - }, - "31d0cb90f7b82088df6c4e00b5765f9dccc48329": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.js", - "result": "[freelib]" - }, - "a192b2ef3371febba192179ff86e3da3f633160d": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js", - "result": "[freelib]" - }, - "db895a7ed5c8b42e27de2b3ef3199d038a259fdb": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.min.js", - "result": "[freelib]" - }, - "06adc576409427237ce3c269bb9a568d3cd53c9b": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js", - "result": "[freelib]" - }, - "8fdfbe7ccaf0bdcde4c0b34738c0cd73b4587a45": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js", - "result": "[freelib]" - }, - "02d2e4a524b0da52c3cb236619ad065fec44d69a": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.min.js", - "result": "[freelib]" - }, - "42936431058c6c4663e64e2c07931b9159083c31": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js", - "result": "[freelib]" - }, - "bbf7ce8f5ce8d8f9d207f8973328527ac0093b17": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js", - "result": "[freelib]" - }, - "09fdd3d9aebc9086b27b45b3fb051ebded272b39": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js", - "result": "[freelib]" - }, - "e002b335c75b5edefcd251962f61f53a2ab8e0f2": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.min.js", - "result": "[freelib]" - }, - "b5f2733aac4e257929a5f1ff93410ee0bda311b6": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.3/jquery-ui.min.js", - "result": "[freelib]" - }, - "f978dcb9ea6ecfbc7f8a2f9948bacd679c0cd1b4": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js", - "result": "[freelib]" - }, - "f78ae3cdaf4a6a21dfb2565491f5d295462d8be3": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js", - "result": "[freelib]" - }, - "5ed6bdacae842fc530dbc83aabb9a466c7f2b5a1": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.6.0/jquery-ui.min.js", - "result": "[freelib]" - }, - "fe810f47883364fbc4dc2c61e03a3aca0f74fed7": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js", - "result": "[freelib]" - }, - "da851ac384c279992d1855d59257f8d98c603063": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.min.js", - "result": "[freelib]" - }, - "5b59bc1a7087c3a83abd5b9ff559a88428ceab0a": { - "filename": "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.min.js", - "result": "[freelib]" - }, - - "0a2054143eddc76447bacf3da455ffc1c726e304": { - "filename": "http://yui.yahooapis.com/3.6.0/build/yui-base/yui-base.js", - "result": "[freelib]" - }, - "5f47da5d3c8902e763ef6ae02e9307a63a95ae5a": { - "filename": "http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader-min.js", - "result": "[freelib]" - }, - "52ebc252c54e6cdaa9e349e1fea37a2950f6af96": { - "filename": "http://yui.yahooapis.com/2.7.0/build/yuiloader/yuiloader-min.js", - "result": "[freelib]" - }, - "e77f9c1022bb48425d63cbaf309d7718ff5d3fbd": { - "filename": "http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader-min.js", - "result": "[freelib]" - }, - "8f1cfeefecc782f53f411de1bf64c77b48b8ba56": { - "filename": "http://yui.yahooapis.com/2.8.1/build/yuiloader/yuiloader-min.js", - "result": "[freelib]" - }, - "aa113da84ddbad46a8002ea22393a238eccf9ee4": { - "filename": "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader-min.js", - "result": "[freelib]" - }, - "a4fadcd6f68d7823a9fd9d1f6089025041a3212a": { - "filename": "http://yui.yahooapis.com/2.8.2/build/yuiloader/yuiloader-min.js", - "result": "[freelib]" - }, - "c398b7eab95bfe84816f60311eaf91194f3bfec8": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/aes.js", - "result": "[freelib]" - }, - "a7eba31001379f751d1a54b988ccdb500d873ec1": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/enc-base64.js", - "result": "[freelib]" - }, - "9bdf0dfad487422fd36693d4119b59175f0112ee": { - "filename": "http://yui.yahooapis.com/2.8.1/build/yuiloader/yuiloader.js", - "result": "[freelib]" - }, - "d9f710afddaba467707c0d6e7b187a8beae1e1f2": { - "filename": "http://yui.yahooapis.com/2.8.2/build/yuiloader/yuiloader.js", - "result": "[freelib]" - }, - "5f8d372d7b385588f61dd53c588608f47a3c3b60": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/enc-utf16.js", - "result": "[freelib]" - }, - "4dc6c77a03258ee7fbe5e877a1ed97311bc45652": { - "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject_src.js", - "result": "[freelib]" - }, - "5847ed101f55d51c53538a7078971e7de8fb6762": { - "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", - "result": "[freelib]" - }, - "fe91b37266d1cdb4b4f51297f69326e271704f35": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "493afa22594fdff6e6fc4f21f99c626533c35b06": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "9fa29ea8f3ec6714b3b6236eb2ce6e1ce905c560": { - "filename": "http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader.js", - "result": "[freelib]" - }, - "1523029ce227a35976407408c5d08039c8fe4f0e": { - "filename": "http://yui.yahooapis.com/2.7.0/build/yuiloader/yuiloader.js", - "result": "[freelib]" - }, - "9514b1927292acf4c670fae6492e9ce2e263472f": { - "filename": "http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader.js", - "result": "[freelib]" - }, - "6b911b0dc178423b946b0299851d9661004c21ef": { - "filename": "http://code.jquery.com/jquery-1.4.1.js", - "result": "[freelib]" - }, - "65cbff4e9d95d47a6f31d96ab4ea361c1f538a7b": { - "filename": "http://code.jquery.com/jquery-1.4.2.min.js", - "result": "[freelib]" - }, - "f02e1f7f1bb966d5fcf16b03daa79ee077a993f8": { - "filename": "http://code.jquery.com/jquery-1.4.js", - "result": "[freelib]" - }, - "b9c72aa78de3c124248f30234c64bf6f3b1a7cb5": { - "filename": "http://code.jquery.com/jquery-1.1.3.pack.js", - "result": "[freelib]" - }, - "bff995d3a845903f281b0b51fea421059459a808": { - "filename": "http://code.jquery.com/jquery-1.4.1.min.js", - "result": "[freelib]" - }, - "b5efe44645f5358e3d785091af3440f80afa85e3": { - "filename": "http://code.jquery.com/jquery-1.4.min.js", - "result": "[freelib]" - }, - "0e9545b59077541c44f521769243a8b717d83aae": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.5/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "e80905e4a45e31075b89189f5ba4913fc0451fdf": { - "filename": "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader.js", - "result": "[freelib]" - }, - "80494ad8eb98e317ffec3671b00944cdc30cee02": { - "filename": "http://yui.yahooapis.com/3.4.0/build/yui-base/yui-base-min.js", - "result": "[freelib]" - }, - "83d1b489e30275a03f568f7e3fa6537d695e0197": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.pack.js", - "result": "[freelib]" - }, - "e956e4de8f223992e2d1362d78c5b5bb33e27497": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "3c737636f4789a45b73f5365cd4cfc8c0922f458": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/hmac.js", - "result": "[freelib]" - }, - "42a8029d12e24767778fc1c6d978b4696b445524": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-cfb.js", - "result": "[freelib]" - }, - "14682f01c5c15f8656cb01425487ad675676df8e": { - "filename": "http://yui.yahooapis.com/3.5.1/build/yui-base/yui-base-min.js", - "result": "[freelib]" - }, - "e1ae2c72f8c5e1b6c423c015349a476f8a908b22": { - "filename": "http://yui.yahooapis.com/3.4.1/build/yui-base/yui-base-min.js", - "result": "[freelib]" - }, - "ca0aea084a63d0a56e1bbf17fde5061f631b391f": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.1.pack.js", - "result": "[freelib]" - }, - "265a86a9d9df5dfdbad77e06c85605bec4beb32a": { - "filename": "http://code.jquery.com/jquery-1.4.2.js", - "result": "[freelib]" - }, - "a2358d630d1a5dad24b679d52e9777b7349910b2": { - "filename": "http://yui.yahooapis.com/3.5.0/build/yui-base/yui-base-min.js", - "result": "[freelib]" - }, - "65fe3b80fae349ecb3acd6541ef651d1ff4961f6": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "66851ab2133e27b97c4f3048416b947aa7ed82c5": { - "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js", - "result": "[freelib]" - }, - "08f37f8169e620c6ecd87635c18fc2b22e3e850e": { - "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js", - "result": "[freelib]" - }, - "28780fdb8fc54bf7d80b1f223abca4f77cd89e85": { - "filename": "https://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject_src.js", - "result": "[freelib]" - }, - "00a5e26ff9ed4b84fc93c764225684c33588a41e": { - "filename": "http://yui.yahooapis.com/3.6.0/build/yui-base/yui-base-min.js", - "result": "[freelib]" - }, - "fe56013bb04c602e676feb34bb49add4da2e0225": { - "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js", - "result": "[freelib]" - }, - "6c445baf655cccb16ee2788714827ab186ed94bf": { - "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.2/scriptaculous.js", - "result": "[freelib]" - }, - "74974f9dc0810ea359367589cb273dd5174d80df": { - "filename": "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.1/scriptaculous.js", - "result": "[freelib]" - }, - "c7e9c7f2fb17e0d2ca2391e33007bf3547fec465": { - "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js", - "result": "[freelib]" - }, - "d97ecac3f1b3ccf1f0f68434e8406f87f5acc907": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.2.min.js", - "result": "[freelib]" - }, - "97be02d1785b7bb4f41ae116a6a9bef74cb018d6": { - "filename": "http://code.jquery.com/jquery-1.4.3.min.js", - "result": "[freelib]" - }, - "6a7a7d88fa4e7369003de24164f5961852731e0e": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-ctr.js", - "result": "[freelib]" - }, - "d65a39fc4b09df061a30172f080019ef9d800ca4": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-ecb.js", - "result": "[freelib]" - }, - "427300f82762288c5af967dbf642fbec58c201ea": { - "filename": "http://code.jquery.com/jquery-1.4.4.js", - "result": "[freelib]" - }, - "94ec4a3bcd6b30353584026c0e109e79fb21b6ad": { - "filename": "http://code.jquery.com/jquery-1.5.min.js", - "result": "[freelib]" - }, - "71adcc2cae87e412e521e4a7276efeaee2347927": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.2.js", - "result": "[freelib]" - }, - "677c1ad6d84705c818d63a43298ee3a12959c1b3": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.3.pack.js", - "result": "[freelib]" - }, - "3d542e33a9f3eb3cb45e06fe93d08dd4b7490496": { - "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js", - "result": "[freelib]" - }, - "e70997dd3dbadadebf375908515617059d0c597e": { - "filename": "http://yui.yahooapis.com/3.4.1/build/yui-base/yui-base.js", - "result": "[freelib]" - }, - "b3db6906c1c0641b7a3098e547e0a8039accd80a": { - "filename": "http://yui.yahooapis.com/3.5.0/build/yui-base/yui-base.js", - "result": "[freelib]" - }, - "cc66556593e147584f19b41b697405f828f7562e": { - "filename": "http://code.jquery.com/jquery-1.5.js", - "result": "[freelib]" - }, - "c147a1a86a2c33e60f160b8861501f43f4638c8d": { - "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js", - "result": "[freelib]" - }, - "d45787e64e233eb17f3f1492b12a682f294f866a": { - "filename": "http://code.jquery.com/jquery-1.5.1.min.js", - "result": "[freelib]" - }, - "278d68b8e9edad4895836e272fbc8f78ec4f2f3e": { - "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js", - "result": "[freelib]" - }, - "b98bb654c88a9b7da659fe8dad95a5c7376bb166": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/md5.js", - "result": "[freelib]" - }, - "6463e558dd79d51a2e8464806824c7bbc18c77fd": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.3.min.js", - "result": "[freelib]" - }, - "5cc87d3fcd5cb3c5913c08bad17ff80f4d0d7f46": { - "filename": "http://yui.yahooapis.com/3.4.0/build/yui-base/yui-base.js", - "result": "[freelib]" - }, - "333b6d92a99eac873b1de2045c670fbdb61970ab": { - "filename": "http://yui.yahooapis.com/3.5.1/build/yui-base/yui-base.js", - "result": "[freelib]" - }, - "522f0852b91775306ca47138c1d6ceeb87677880": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/mode-ofb.js", - "result": "[freelib]" - }, - "4407f7b9602539e80f1569ae734696fd92deeff0": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-ansix923.js", - "result": "[freelib]" - }, - "c82ea9768b18696832408b6cc729e2e121def691": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.3.js", - "result": "[freelib]" - }, - "0d2bc9db63acd9cc238a4925e79f9a3079490970": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.4.min.js", - "result": "[freelib]" - }, - "5900300a75ed7917eaa6f75077afe9ef49e66986": { - "filename": "https://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js", - "result": "[freelib]" - }, - "2cc787ebd4d29f2e24646f76f9c525336949783e": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools.js", - "result": "[freelib]" - }, - "a965003ea3313be11a02743f4807411c9eb71f04": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-iso10126.js", - "result": "[freelib]" - }, - "3bb92e84642c03cf0fe49174d0e1c420d46d2e18": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.4.js", - "result": "[freelib]" - }, - "325edd57857f7a3160cfe2512dff5526d7e647db": { - "filename": "http://code.jquery.com/jquery-1.6.min.js", - "result": "[freelib]" - }, - "034970f98cb529c779c8f961b2b7c09ecb499240": { - "filename": "http://code.jquery.com/jquery-1.6.js", - "result": "[freelib]" - }, - "341a7a52109c3abfb23d5a5b4f363fd8d6a52f6c": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-iso97971.js", - "result": "[freelib]" - }, - "c654cdaa3ca1184d9b18d0c31f8369a04c63f7f5": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-nopadding.js", - "result": "[freelib]" - }, - "20860bad9c83c3890be57052f009b9d97848c9ec": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.5.min.js", - "result": "[freelib]" - }, - "6111fcf6c2277eba8821ca365dbbea472a3206e7": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.4/mootools.js", - "result": "[freelib]" - }, - "9025fe9334566eb919ddca85a8f949b01c7d837d": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.5.pack.js", - "result": "[freelib]" - }, - "0e9a07ee104153a459cdbcb9fa28293b4bbb429f": { - "filename": "http://code.jquery.com/jquery-1.6.1.min.js", - "result": "[freelib]" - }, - "e55462193a857ffe36e42bfcbecfebf1ca33d0b8": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools.js", - "result": "[freelib]" - }, - "7df0e9aae795337db012b3efd0b9ee9cc7719b56": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools.js", - "result": "[freelib]" - }, - "8963108fa84c2033a1052d47079d7f75a7e5b60e": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.5.js", - "result": "[freelib]" - }, - "aa7020d6c8d5475ae588640954caa9e4cdd7eca0": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pad-zeropadding.js", - "result": "[freelib]" - }, - "1be9c3684054001f53fa7ff6d85ec3cb573a9cd2": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js", - "result": "[freelib]" - }, - "e0f3225498158bc63af7bfba636b091ea4ee5fcd": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/pbkdf2.js", - "result": "[freelib]" - }, - "c415b533f7edda8b9de417cc0517904f86e9fe1f": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/rabbit.js", - "result": "[freelib]" - }, - "c10dbe0c2b23444d0794f3376398702d84f41583": { - "filename": "http://jqueryjs.googlecode.com/files/jquery-1.2.6.pack.js", - "result": "[freelib]" - }, - "f4d4125bcd5151aad69dd849a11fc1ca589cc64b": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools.js", - "result": "[freelib]" - }, - "4ee6675ca57dda3255aa669d8ec4d35760eb47c3": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.0/mootools.js", - "result": "[freelib]" - }, - "0c89448016629bb2ea758f4e98529c2e166a122d": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.1/mootools.js", - "result": "[freelib]" - }, - "b4096385cad3144e81c255aa6e4b7dabb30bc19f": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/rc4.js", - "result": "[freelib]" - }, - "037f4fadbc2020ccb4935384b8ae5af62bdd0145": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha1.js", - "result": "[freelib]" - }, - "bc018ec49a5c7757577bb63e5d5f8a99be0e3954": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.2/mootools.js", - "result": "[freelib]" - }, - "aa5c283b9e094eeacdd080b44951406abbc9e58c": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha224.js", - "result": "[freelib]" - }, - "6dc7644a54d5cc254a1f6d7cb7154128b2b6570a": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.3/mootools.js", - "result": "[freelib]" - }, - "c0c37b7d3119f29d3759fdaf7eb8bc4670ea9e7f": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.1/mootools.js", - "result": "[freelib]" - }, - "b38f741b43f6ddcce3f1b47274d1683cca9f07a8": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha256.js", - "result": "[freelib]" - }, - "e29701dd85d792bddbf52d1e1fc3d1ada41b6192": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha384.js", - "result": "[freelib]" - }, - "cc019ac09f68258ee3442fe7cc440adf78a3cef2": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "e88bb2c302b41a4cc5b97604354a48d068e3e1eb": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/sha512.js", - "result": "[freelib]" - }, - "fc39ed8ca4a58668124471e509506443de4467f2": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.4/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "b1a271458ae47d0b47c9e0996956091a93dec16f": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.1/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "86f0df8662b511142dfc4e0ce9c81d805c8d7a7e": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.0/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "e0bfed3ffc741a9f4e59e6004a1dec9c71241a59": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/x64-core.js", - "result": "[freelib]" - }, - "fc21f8084ad4040ddbf620ba79acd3998fb3dc7b": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "1e8f9e1614db771782bc9e871fb712b06610b9f4": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.2/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "c7e2076a3af9997731499bc1f7dc3941b522c1eb": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.4.3/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "dd7783b4c8d4ecaad4091d1d32df2f97d7b10ddc": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.2/mootools.js", - "result": "[freelib]" - }, - "55bba460dcbb70562536ddd5c8734b311f38c42d": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools.js", - "result": "[freelib]" - }, - "3c1ddf62af20a1f5c5de7a3af180b32528dc47db": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.2/mootools.js", - "result": "[freelib]" - }, - "c43a38fce1aa745d59b1a6f7ab7def81f28701a4": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.3/mootools.js", - "result": "[freelib]" - }, - "e5335c2a82f26e49b1324edc21e452de040d5cdc": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools.js", - "result": "[freelib]" - }, - "ccf015fcd45618c6b116977c96539d93ee10b542": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/tripledes.js", - "result": "[freelib]" - }, - "3d9fc65389ce7de16f87909039aa2e728c693b3d": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.5/mootools.js", - "result": "[freelib]" - }, - "5f970c3c8ca26a94c14a1ae1e7321621cf4eae0c": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.2/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "03a65e56fc95caea1b85a591c984e9b6c080726d": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.1.1/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "669d164e3bff6156b21084cf035979d62433df75": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.2/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "f3e20ad41082a93dbd09202590717da71aebd316": { - "filename": "https://ajax.googleapis.com/ajax/libs/mootools/1.2.3/mootools-yui-compressed.js", - "result": "[freelib]" - }, - "8dda5f159c9bedee9f4a6b7a7a6028a554977994": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "15c3f73c75bb3ab87040fe55240f9dd5ea69b6bf": { - "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core-debug.js", - "result": "[freelib]" - }, - "5c83aac1a3409dc1ec3a228e4c765292eb4434d4": { - "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.0.0/ext-core-debug.js", - "result": "[freelib]" - }, - "7dc1b4f3e358c58030c4676c990eff60a0fc838f": { - "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core.js", - "result": "[freelib]" - }, - "d19d40a20252730e9fd9af1c7867c0f5417ebe32": { - "filename": "https://ajax.googleapis.com/ajax/libs/ext-core/3.0.0/ext-core.js", - "result": "[freelib]" - }, - "e1db767afb82018ab6a695fe52334f2f5d81a0e3": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "a90b5f6afb6c78b30c3539392d49e45fd9dfe3d9": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5.1/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "0a0a820f2bc4f2dac8dcfde2282411275e2dc697": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "b6d2c0b655b327407966b52303449dedce084ded": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "4cc838a3be933fda21bbbfc8f52b01e14a1e70a5": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "2ef4341a4ca0b9a0fc1aea422d85b5d9771fde87": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.0/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "df435b881e8364ddfbd44d5f786b10c75f964175": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "19214655c4152b79f204e222a481d1e18da84972": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "f444ee6b041735ee6109dd2fe3c3a7755fa949f7": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.0/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "c7f5b42b2306a79f67988ee073ac98c2a1d5782f": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.3/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "d8afec39893c1a99139212feb40888847f8a5253": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "a6edefef305d9164212fa140426629c7d8a58c93": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.1.1/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "a3e5c42f93722ad28cda811f8635bddf213819ed": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "741b8eeb65774256a8a76ea1af91f976357fcd81": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5.1/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "911a35988b8540414cfbc990fbc112eb124fd968": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "c753cf372377ef0b5a18204cd86df8d4792fa8f5": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "8b95d59f6b28b072ceb4228a6db107b934500a02": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.4.0/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "8c135fc57355fe5d5a18f3dbe5736bc772bb20a7": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "70b1fe9dd4ebec0b5d417647e549bca8f9200020": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "8980e43d4750c63eb57cfff5f0723f118d243c67": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.3.0/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "d2fc56e1b9f2014fb7710d186a355a57e3acd283": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.3/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "2bab42610adee25cdc0d3a4ba96b94f1e9ccd115": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "6bb906d86dd239add79d0779a9fcdf9740aa7e3b": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.1.1/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "3d96f61e48510cbe595081ef8b2d5c8479f95d3e": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "1e4cb0dcb97df9a15433477f9f8a666914eedc3c": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.0/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "47732fb5e03d251aff1a7c0b550a3af74c7ceea5": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.3/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "85399dd9527026afc66a6fb43ad5c0d4ea97f83e": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "147eab514dfe1d88506a5e158b782cb5c504c056": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.xd.js.uncompressed.js", - "result": "[freelib]" - }, - "229e4025f71b0b94d98505f56c5cfd7cd41d06aa": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.3/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "135ade1e60da3e3b79fd73c3a6a005a250e2a7f7": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "135188b624daae8f4b015b0b8b75875a6132aa3d": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "fac80a6188865418344d4b6c5d4955ee7e7362c2": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.0/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "311d8f38b12a09f16f5a19e1dfb6575b5ce0f83c": { - "filename": "https://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.xd.js", - "result": "[freelib]" - }, - "ca2868985811d45cfbad118a297869707572e0bb": { - "filename": "https://raw.github.com/voldsoftware/toolbarbutton-jplib/stable/lib/toolbarbutton.js", - "result": "[freelib]" - }, - "32d542564913a016f1cea340ba8ac164c160004d": { - "filename": "http://yui.yahooapis.com/3.3.0/build/yui-base/yui-base.js", - "result": "[freelib]" - }, - "012cc186912c473552a341b2eaffb71240688ccd": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/cipher-core.js", - "result": "[freelib]" - }, - "d1c9d4d91c1c3c76f601778cb5e0489e0f80a10d": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/evpkdf.js", - "result": "[freelib]" - }, - "794503310ed31a11f233e1acdddc10f2ce91748e": { - "filename": "http://crypto-js.googlecode.com/svn/tags/3.0.2/src/core.js", - "result": "[freelib]" - }, - "5717e22c3b2c7caf870fc0772a64344962b59ee6": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.6/underscore.js", - "result": "[freelib]" - }, - "7e0294019938a772f4ddd7799501496074e0f0fb": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.7/underscore.js", - "result": "[freelib]" - }, - "28e41c3ce9232633468013342c49fd62a4f5f6bd": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.2/underscore.js", - "result": "[freelib]" - }, - "8d84b347dfe4f5b75f7b5f670326ca5c8041b7a9": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.3/underscore.js", - "result": "[freelib]" - }, - "9564fa7a6a001e4e56b0244ccda03eef3940813e": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.3/underscore.js", - "result": "[freelib]" - }, - "058cbd179f032f667823545519aa2d10b0b69508": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.2/underscore.js", - "result": "[freelib]" - }, - "868141351efa758d031779c776e608e3a049d823": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.4/underscore.js", - "result": "[freelib]" - }, - "2fee700150a7de876acc21403f77e57dae2f5618": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.5/underscore.js", - "result": "[freelib]" - }, - "40946800c5c8bee189ca3e7f8017661f9456e490": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.0/underscore.js", - "result": "[freelib]" - }, - "b842a8ca5e996e001e648fc8c73316cd55e496ed": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.4/underscore.js", - "result": "[freelib]" - }, - "f2fa9179d764f6a688dc0c99b1b5283f1b680249": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.1/underscore.js", - "result": "[freelib]" - }, - "c1dff1c5dbb68af6e22bd401afd28aab970a8aff": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.3/underscore.js", - "result": "[freelib]" - }, - "5846c870e0f1daca152db22277915adb6520ffa3": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.0/underscore.js", - "result": "[freelib]" - }, - "cdacc2b0045fa1b920b64664b88b155d0c0df169": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.2/underscore.js", - "result": "[freelib]" - }, - "baa693e82387a328abccf9694c6d2db571ac8aca": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.3/underscore-min.js", - "result": "[freelib]" - }, - "e67cf6a985999c7ef5595772e4ffefeacd0c6ac3": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.1/underscore.js", - "result": "[freelib]" - }, - "0a15952061f6fb7a5493281f6ff8eb916a417e2f": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.1/underscore-min.js", - "result": "[freelib]" - }, - "bd9624f882f7d3d29292ddc7f484987b3e991cb5": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.0/underscore.js", - "result": "[freelib]" - }, - "ede1d022640f26eaa6109da9e924670f6ed14cce": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.2/underscore-min.js", - "result": "[freelib]" - }, - "63f6a94752e5fde78627529763e67ecd4ef78f12": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.4/underscore-min.js", - "result": "[freelib]" - }, - "1185da1043863517c6aa0a4e0a3bc433dfb98313": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.2/underscore-min.js", - "result": "[freelib]" - }, - "86752ba2e4f3855a8a5e45d5f07567ea70a9cc98": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.0/underscore-min.js", - "result": "[freelib]" - }, - "cfbc3fa20d685d100308e123c3310dc9600ef0fd": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.3/underscore-min.js", - "result": "[freelib]" - }, - "083bbcd739b7b1336f13c72603e1704b164c02bd": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.1/underscore-min.js", - "result": "[freelib]" - }, - "f665459959c5167c0905974a62ffe923f2c19813": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.5/underscore-min.js", - "result": "[freelib]" - }, - "2de2ecea5ba12e7235ffb44d6892cc77fe6f4abe": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.4/underscore-min.js", - "result": "[freelib]" - }, - "81afb4cd3755671fea5e74d7118d7d460c475308": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.7/underscore-min.js", - "result": "[freelib]" - }, - "9e389ede8ed7f782c5ecf2f87c3afa3b1e309bff": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.3/underscore-min.js", - "result": "[freelib]" - }, - "703d6a61f31ddb45252c55813556a92e8cc2ee22": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.6/underscore-min.js", - "result": "[freelib]" - }, - "7d6e352b0d26655ba851863561b5d912cc24caa7": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.0/underscore-min.js", - "result": "[freelib]" - }, - "5de53da57fc8b7ab6c77d597c22875d747352fef": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.1/underscore-min.js", - "result": "[freelib]" - }, - "bcdd63e18a8a7cf728253f738556ad3b88d74649": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.2/underscore-min.js", - "result": "[freelib]" - }, - "ee68308411c690cd51cc8a43fe6ae60d3d1678af": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.4/underscore-min.js", - "result": "[freelib]" - }, - "49a747d3284b1d04f3eb823a4188f7725004f823": { - "filename": "https://raw.github.com/documentcloud/underscore/1.1.0/underscore-min.js", - "result": "[freelib]" - }, - "97f93241957893ebd7febc5b5bac9a7bd1d94a0f": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.3/underscore-min.js", - "result": "[freelib]" - }, - "710c3a99f0bd456c2fd6dcbcbd1e500e0646ec19": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.1/underscore-min.js", - "result": "[freelib]" - }, - "7361e8afa72bd0098e2520584786474c9c4a5064": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.2/underscore-min.js", - "result": "[freelib]" - }, - "ad0775c89a87111019840dc7bbf902d832e4ccdf": { - "filename": "https://raw.github.com/documentcloud/underscore/1.0.0/underscore-min.js", - "result": "[freelib]" - }, - "34454bfed864addf8ec4aacdd9adf872f8360ed3": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.1/underscore.js", - "result": "[freelib]" - }, - "07916c0b7274275f916fe288d01b254545b17d9a": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.4/underscore.js", - "result": "[freelib]" - }, - "133de2283d03193cb06f62f92c494afe098460a5": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.0/underscore.js", - "result": "[freelib]" - }, - "4c977634c87efbd2b7113993d36dad603b8dcf2f": { - "filename": "https://raw.github.com/documentcloud/underscore/1.2.1/underscore.js", - "result": "[freelib]" - }, - "3fa74bb289537fcdee796b26968e47d53d38f903": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.2/underscore.js", - "result": "[freelib]" - }, - "772b2587aa2fa345fb760eff9ebe5acd97937243": { - "filename": "https://raw.github.com/documentcloud/underscore/1.3.3/underscore.js", - "result": "[freelib]" - }, - "562c6c44b39809ec07c047f4ed6c591f3ae7c034": { - "filename": "https://raw.github.com/documentcloud/underscore/1.4.0/underscore.js", - "result": "[freelib]" - }, - "063a7d75792dff2b46eee81cc12de63def672911": { - "filename": "https://raw.github.com/documentcloud/underscore/1.4.1/underscore.js", - "result": "[freelib]" - }, - "47479149fe12fc56685a9de90c5a9903390cb451": { - "filename": "https://raw.github.com/documentcloud/underscore/1.4.2/underscore.js", - "result": "[freelib]" - }, - "d53fbd7308ae3d7eeb4a536c2cbfe739648850b4": { - "filename": "https://raw.github.com/documentcloud/underscore/1.4.3/underscore.js", - "result": "[freelib]" - }, - "6d9ee62759cb911ec03b21078c9f92f0f2afa25c": { - "filename": "https://raw.github.com/documentcloud/underscore/1.4.4/underscore.js", - "result": "[freelib]" - }, - "5d42ed92480d3a88efa270449f38c6d88d653af5": { - "filename": "https://raw.github.com/documentcloud/underscore/1.5.0/underscore.js", - "result": "[freelib]" - }, - "9ee15c1f1a84a258ba5f48de72da3538c8b7c375": { - "filename": "https://raw.github.com/documentcloud/underscore/1.5.1/underscore.js", - "result": "[freelib]" - }, - "c9ae7b502c521d2f53b9065ef4fc7d7cc97dce4c": { - "filename": "https://raw.github.com/documentcloud/underscore/1.5.2/underscore.js", - "result": "[freelib]" - }, - "fe1b87838b7328273812380d26837f58348103b0": { - "filename": "https://raw.github.com/documentcloud/underscore/1.6.0/underscore.js", - "result": "[freelib]" - }, - "92d29762b3d85d123d593f14b113d4fb6385598f": { - "filename": "https://raw.github.com/documentcloud/underscore/1.7.0/underscore.js", - "result": "[freelib]" - }, - "fb26909af4ad2a6c240b9aa4b35bb983cf4b20e4": { - "filename": "https://raw.github.com/documentcloud/underscore/1.7.0/underscore-min.js", - "result": "[freelib]" - }, - - "63a001665725b35d2bc4a6212385a746584c1a3b": { - "filename": "http://cdn.jsdelivr.net/jquery.fancytree/2.6.0/jquery.fancytree-all.min.js", - "result": "[freelib]" - }, - "d6469e3aa15a6107ad5783a96e3c8fa3f5ce21ca": { - "filename": "http://cdn.jsdelivr.net/jquery.fancytree/2.5.0/jquery.fancytree-all.min.js", - "result": "[freelib]" - }, - "2de56a2ec01b0aa170754bd6ed7485576f16f165": { - "filename": "http://cdn.jsdelivr.net/jquery.fancytree/2.4.1/jquery.fancytree-all.min.js", - "result": "[freelib]" - }, - - "5ada7c103fc1deabc925cc1fdbbb6e451c21fc70": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js", - "result": "[freelib]" - }, - "afa7af2bc7cbe37eeccb9b65577744c08219c5a9": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.js", - "result": "[freelib]" - }, - "b3f2ef9f985e7906c9360756b73cd64bf7733647": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js", - "result": "[freelib]" - }, - "f8752e9ae24daec0a0baffd7819122f8c6fd9103": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.js", - "result": "[freelib]" - }, - "253711c6d825de55a8360552573be950da180614": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js", - "result": "[freelib]" - }, - "542cfd539f0cad650342c8cab8baf1cdbcd5fea6": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.js", - "result": "[freelib]" - }, - "6c264e0e0026ab5ece49350c6a8812398e696cbb": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js", - "result": "[freelib]" - }, - "bbf55e20f1ebb6368522799f29db39830a08ef93": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js", - "result": "[freelib]" - }, - "5814e91bb6276f4de8b7951c965f2f190a03978d": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js", - "result": "[freelib]" - }, - "fd607f85d598503b24d7799722db29fec4de1ef6": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.js", - "result": "[freelib]" - }, - "c6a8a0f02ee0ecd975226ae4b38e9660750d1f93": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js", - "result": "[freelib]" - }, - "539e456bb40d9e98244060186f5f131b1a7f4b33": { - "filename": "http://netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.js", - "result": "[freelib]" - }, - - "128273a9c66a32d7d59a6f290deb6cc4a2b2ee5a": { - "filename": "http://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.7.1/js/lightbox.min.js", - "result": "[freelib]" - }, - "250d7c160f17c13e89cee0e1dcd1debb2e940ed2": { - "filename": "http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js", - "result": "[freelib]" - } -} diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/widget/images/librejs-32.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/widget/images/librejs-32.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/widget/images/librejs-64.png b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/data/widget/images/librejs-64.png Binary files differ. diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/addon_management/install_uninstall.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/addon_management/install_uninstall.js @@ -1,67 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * The following module is intended to perform tasks when the - * add-on is enabled and disabled. - */ - -const {Cc, Ci, Cu, Cm, Cr} = require("chrome"); - -const httpObserver = require("http_observer/http_request_observer"); -var narcissusWorker = require("parser/narcissus_worker") - .narcissusWorker; -const caching = require("http_observer/caching"); - -const prompt = Cc["@mozilla.org/embedcomp/prompt-service;1"]. - getService(Ci.nsIPromptService); - - -const tabs = require('sdk/tabs'); - -/** - * Stop the httpObserver when the add-on is disabled or removed. - */ -exports.onUnload = function(reason) { - if (reason == "disable" || - reason == "shutdown" || - reason == "upgrade" || - reason == "downgrade") { - require("settings/storage").librejsStorage.writeCacheToDB(); - // remove all http notifications - httpObserver.removeHttpObserver(); - // remove worker. - narcissusWorker.stopWorker(); - } - -}; - -exports.onLoad = function () { - try { - var clearCache = prompt.dialog(null, "LibreJS installation", "If you have tabs and windows opened prior to installing LibreJS, you will have to refresh them for their JavaScript to be analyzed and blocked. Press OK to clear the browser cache."); - if (clearCache) { - caching.clearAllCache(); - } - } catch (e) { - console.debug(e); - } -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/addon_management/prefchange.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/addon_management/prefchange.js @@ -1,126 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var whitelist = []; - -var prefSet = require("sdk/simple-prefs"); -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); - -var prompt = Cc['@mozilla.org/embedcomp/prompt-service;1']. - getService(Ci.nsIPromptService); -var scriptsCached = require("script_entries/scripts_cache").scriptsCached; - -var setWhitelist = function () { - whitelist = []; - - var str; - var whitelistString; - if (typeof prefSet.prefs.whitelist === 'undefined') { - whitelistString = ''; - } else { - whitelistString = prefSet.prefs.whitelist.split(','); - } - - for (var i = 0; i < whitelistString.length; i++) { - // remove space, trailing slash, escape any nonalpha except *, - // replace * with .* - str = whitelistString[i] - .replace(" ", "").replace(/\/$/, "") - .replace(/[^a-z0-9\*]/ig, "\\$&").replace("*", ".*"); - - if (str !== '') { - whitelist.push( - new RegExp('^https?:\/\/(www\\.)?' + str + '/', 'i')); - } - } -}; - -exports.getWhitelist = function () { - return whitelist; -}; - -exports.init = function () { - setWhitelist(); -}; - -prefSet.on("whitelist", setWhitelist); - -/*var setDryRun = function () { - var dryRun = prefSet.prefs.dryrun; - if (dryRun === true) { - prompt.alert(null, "LibreJS Dry Run Mode", "Is Dry Run Mode really what you want? LibreJS will still analyze JavaScript on a page, but it will not block any of it. As a result, ALL of the JavaScript on a page will run as is, whether it is free and trivial or not. You will not be warned again. Uncheck that box if you are unsure."); - scriptsCached.resetCache(); - } else { - prompt.alert(null, "LibreJS Dry Run Mode", "LibreJS Dry Run Mode is now disabled"); - } -};*/ - -//prefSet.on("dryrun", setDryRun); - -/*exports.isDryRun = function () { - // Returns true if dryRun mode is enabled. False otherwise. - //return prefSet.prefs.dryrun; - return false; -};*/ - -var setComplaintTab = function () { - var complaintTab = prefSet.prefs.complaint_tab; - if (complaintTab === true) { - prompt.alert(null, "Turning on complaint tab", "A complaint tab will be displayed on pages where nonfree nontrivial JavaScript is found and contact information is found as well."); - } else { - prompt.alert(null, "Turning off complaint tab", "No complaint tab will appear on pages, even when nonfree nontrivial JavaScript is found."); - } -}; -prefSet.on("complaint_tab", setComplaintTab); - -exports.isComplaintTab = function () { - /** - * Returns true if complaint tab mode is enabled. False otherwise. - */ - return prefSet.prefs.complaint_tab; -}; - -var setDisplayNotifications = function () { - var displayNotifications = prefSet.prefs.display_notifications; - if (displayNotifications === true) { - prompt.alert(null, "Turning on notifications", "Notifications with code snippets will now appear while LibreJS is analyzing JavaScript on a page."); - } else { - prompt.alert(null, "Turning off notifications", "Notifications of code being analyzed will not be displayed."); - } -}; - -prefSet.on("display_notifications", setDisplayNotifications); - -exports.isDisplayNotifications = function () { - /** - * Returns true if complaint tab mode is enabled. False otherwise. - */ - return prefSet.prefs.display_notifications; -}; - -exports.complaintEmailSubject = function() { - return prefSet.prefs.complaint_email_subject; -}; - -exports.complaintEmailBody = function() { - return prefSet.prefs.complaint_email_body; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler.js @@ -1,573 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * - * dom_handler.js - * - * After the HTML DOM has been parsed, domHandler finds all the scripts - * on a page (including inline, on-page, and external files), and triggers the - * JavaScript analysis for each of them. - * - */ - -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); - -var scriptProperties = - require("html_script_finder/dom_handler/script_properties"); - -const scriptTypes = scriptProperties.scriptTypes; -const statusTypes = scriptProperties.statusTypes; -const reasons = scriptProperties.reasons; - -var urlHandler = require("url_handler/url_handler"); - -var WebLabelFinder = - require("html_script_finder/web_labels/js_web_labels").WebLabelFinder; - -// object model for script entries. -var scriptObject = require("html_script_finder/dom_handler/script_object"); - -var privacyChecker = require("js_checker/privacy_checker").privacyCheck; -var jsChecker = require("js_checker/js_checker"); -const types = require("js_checker/constant_types"); - -var checkTypes = types.checkTypes; - -var stripCDATAOpen = /<\!\[CDATA\[/gi; -var stripCDATAClose = /]]>/g; - -var isDryRun = require("addon_management/prefchange").isDryRun; -var allowedRef = require('http_observer/allowed_referrers').allowedReferrers; -var attributeHelpers = require("html_script_finder/dom_handler/attributes"); - -// javascript:* -var jsInAttrRe = attributeHelpers.jsInAttrRe; - -// the list of all available event attributes -var intrinsicEvents = attributeHelpers.intrinsicEvents; - -var domGatherer = - require("html_script_finder/dom_handler/dom_gatherer").domGatherer; -var domChecker = - require("html_script_finder/dom_handler/dom_checker").domChecker; - -/** - * The DomHandler object takes a whole document, - * finds script elements within that DOM, analyzes them - * using the js_checker module and finally returns a cleaned - * DOM depending on the result. - */ -var DomHandler = function() { - // external object with methods used - // in DomHandler - this.domGatherer = null; - - // external object with methods used - // in DomHandler - this.domChecker = null; - - this.dom = null; - this.pageURL = null; - - // fragment found in url. - this.fragment = null; - - // array containing all scripts on a page. - this.domScripts = []; - - // array containing all scripts on a page, - // data related to them, such as parse tree, ... - this.inlineScripts = []; - - this.externalScripts = []; - - // all scripts. - this.scripts = []; - - // keeps track of the number of scripts. - this.numScripts = 0; - - // store the reference to the callback method - // presumably from htmlParser. - this.callback = function() {}; - - // boolean set to true if external scripts are loaded - // from the html page. - this.loadsHtmlExternalScripts = false; - - this.jsCheckString = null; - - /* object containing boolean property set to false if trivialness - is not allowed anymore (if another script defines ajax requests, - ...) */ - this.allowTrivial = null; - - // boolean set to true if inline JavaScript - // is found to be free. - this.inlineJsFree = null; - - // boolean set to true when at least one script - // has been removed. - this.hasRemovedScripts = null; - - // boolean to check if scripts were removed - // prevents removeAllJs from running multiple times. - this.removedAllScripts = null; - - // will eventually contain an array of data - // for the js web labels licenses. - this.licenseList = []; - - // the response status for the page (200, 404, ...) - this.responseStatus = null; - - // number of scripts fully tested. - this.scriptsTested = 0; - - // number of external scripts to be tested. - this.numExternalScripts = null; - - // number of inline/inattribute scripts - this.numInlineScripts = null; -}; - -/** - * Initialize properties of the object - * - * @param {domObject} obj A reference of the DOM object being - * analyzed. - * - * @param {pageURL} string The formatted URL (with fragment - * removed) of the corresponding page for this DOM - * - * @param {fragment} the #fragment from the url if applicable. - * - * @param {callback} the callback function. - * - */ -DomHandler.prototype.init = function( - domObject, pageURL, fragment, responseStatus, callback -) { - // initialize object properties. - - console.debug('init', pageURL); - var that = this; - - this.reset(); - - // arguments passed. - this.dom = domObject; - this.pageURL = pageURL; - this.fragment = fragment; - this.responseStatus = responseStatus; - - console.debug('in dom handler, responseStatus is', this.responseStatus); - - // make callback function available - // for the entire object. - this.callback = function (dom) { - callback(dom); - that.destroy(); - }; -}; - -DomHandler.prototype.reset = function () { - - this.dom = null; - // arrays. - this.onEventElement = []; - this.scriptStatus = []; - this.inlineScripts = []; - this.externalScripts = []; - this.scripts = []; - - // booleans - this.allowTrivial = true; - this.inlineJsFree = false; - this.hasRemovedScripts = false; - this.removedAllScripts = false; - - // we start with 0, and will increment in - // dom_checker. - this.numExternalScripts = 0; - - this.numInlineScripts = 0; - - this.scriptsTested = 0; - -}; - -DomHandler.prototype.destroy = function () { - this.domGatherer = null; - this.domChecker = null; - /* destroy callback so that it can't be called multiple times. */ - this.callback = function() {}; - //this.reset(); -}; - -DomHandler.prototype.scriptHasBeenTested = function() { - this.scriptsTested++; - console.debug('incremented DomHandler.scriptsTested to', - this.scriptsTested); -}; - -/** - * scriptHasJsWebLabel - * - * Checks if a script was found earlier in a Js License Web Label - * table. See http://www.gnu.org/licenses/javascript-labels.html - * for more information. - * - */ -DomHandler.prototype.scriptHasJsWebLabel = function(script) { - if (this.licenseList) { - - var url = urlHandler.resolve(this.pageURL, script.src), - i = 0, - len = this.licenseList.length; - - console.debug('looking for web label'); - - for (; i < len; i++) { - if (this.licenseList[i].fileUrl === url && - this.licenseList[i].free === true - ) { - console.debug('found something true'); - console.debug( - this.licenseList[i].fileUrl, ' is found'); - return true; - } - } - } - return false; -}; - -/** - * processScripts. - * Starts by looking for a js web labels page - * then calls the complete function, which runs - * the rest of the check. - */ -DomHandler.prototype.processScripts = function () { - var that = this; - - // check for the existence of the - // js web labels first. - this.lookForJsWebLabels(function () { - - // gather and check all script elements on - // page. - console.debug("Calling checkAllScripts"); - that.checkAllScripts(); - - }); - -}; - -/** - * jsWebLabelsComplete - * - */ -DomHandler.prototype.checkAllScripts = function () { - try { - console.debug( - 'found in', this.pageURL, JSON.stringify(this.licenseList)); - console.debug('checkAllScripts triggered async'); - - // use domGatherer to gather scripts. - this.domGatherer.findScripts(); - this.domGatherer.gatherScriptsContent(); - this.domGatherer.gatherIntrinsicEvents(); - - console.debug('fragment is', this.fragment); - - if ( - this.fragment === undefined || - this.fragment === null || - this.fragment.indexOf('librejs=true') < 0 - ) { - try { - - // use domChecker to check scripts. - console.debug("Calling checkAllInlineScripts"); - this.domChecker.checkAllInlineScripts(); - } catch (x) { - console.debug('error in domChecker:', x, x.lineNumber); - this.removeAllJs(); - } - } else { - console.debug('This is a pageworker, removing all js'); - // this is the Page Worker to find contact link - // just remove all the JS since we don't need it. - console.debug('fragment found, remove js'); - this.removeAllJs(); - } - } catch (x) { - console.debug('error', x, x.lineNumber, x.fileName); - } -}; - -/** - * lookForJsWebLabels - * - * Checks if a link to a js web label table exists. - * If it does, return an array of objects with the data - * gathered (script name, path, license name, url, ...) - * - */ -DomHandler.prototype.lookForJsWebLabels = function (completed) { - var that = this; - console.debug("calling lookForJsWebLabels"); - if (this.fragment !== '#librejs=true') { - var webLabelFinder = new WebLabelFinder(); - webLabelFinder.init( - this.dom, - this.pageURL, - function (licenseList) { - // assign array returned to property. - that.licenseList = licenseList; - console.debug("calling completed"); - completed(); - }); - } else { - completed(); - } -}; - -DomHandler.prototype.checkScriptForJsWebLabels = function(script) { - var scriptEntry; - - if (this.hasSrc(script) && this.scriptHasJsWebLabel(script)) { - // This script is in the list of allowed scripts (through web labels) - scriptEntry = scriptObject.Script({ - 'type': scriptTypes.EXTERNAL, - 'status': statusTypes.ACCEPTED, - 'element': script, - 'url': urlHandler.resolve(this.pageURL, script.src) - }); - - scriptEntry.tagAsAccepted(this.pageURL, reasons.FREE); - return true; - } -}; - -/** - * hasSrc - * Check the given script has an src attribute. - * @param script obj The script element. - * @return a string with the value of the src attribute. - */ -DomHandler.prototype.hasSrc = function(script) { - if (script.src) { - return script.src; - } - return false; -}; - -/** - * Uses relationChecker to guess whether the script only uses - * predefined functions/variables or interacts with other scripts - * (this is still very experimental and needs improvement.) - * - */ -DomHandler.prototype.removeScriptIfDependent = function (script) { - var nonWindowProps = script.tree.relationChecker.nonWindowProperties; - - for (var entry in nonWindowProps) { - if (nonWindowProps[entry]) { - console.debug('script has non window properties.'); - this.removeGivenJs(script, reasons.TRIVIAL_NOT_ALLOWED); - return true; - } - } -}; - -/** - * removeGivenJs - * Remove a single script from the DOM. - * @param script Obj The script element to be removed from the - * DOM. - * - */ -DomHandler.prototype.removeGivenJs = function (script, reason, singleton, hash) { - var commentedOut; - var isAllowed = allowedRef.urlInAllowedReferrers(this.pageURL); - console.debug("removing given js hash", hash); - - if (script.status != statusTypes.REJECTED && - script.status != statusTypes.JSWEBLABEL - ) { - console.debug('removing a', script.type); - if (script.type === scriptTypes.ATTRIBUTE && - !isAllowed - ) { - this.removeGivenAttribute(script, reason); - return; - } - if (!isAllowed) { - // set invalid type if dry run off. - script.element.setAttribute('type', 'librejs/blocked'); - // add entry as removed. - console.debug('removeGivenJs hash is', hash); - script.tagAsRemoved(this.pageURL, reason, hash); - } else { - script.element.setAttribute( - 'data-librejs-dryrun', 'librejs/blocked'); - script.tagAsDryRun(this.pageURL, reason, hash); - } - - if (singleton === true) { - // flag singletons. - script.element.setAttribute('data-singleton', 'true'); - } - - // remove src if dry run off. - if (script.element.getAttribute('src') !== undefined) { - script.element.setAttribute( - 'data-librejs-blocked-src', - script.element.getAttribute('src') - ); - if (!isAllowed) { - script.element.removeAttribute('src'); - } - } - if (isAllowed) { - comment_str = 'LibreJS: Script should be blocked, but page is whitelisted.'; - script.status = statusTypes.ACCEPTED; - } else { - comment_str = 'LibreJS: script blocked.'; - script.status = statusTypes.REJECTED; - } - - commentedOut = this.dom.createComment(comment_str); - // add a comment for curious source readers. - script.element.parentNode.appendChild(commentedOut); - script.element.parentNode.insertBefore(commentedOut, script.element); - this.hasRemovedScripts = true; - } -}; - -DomHandler.prototype.removeGivenAttribute = function (script, reason) { - var i = 0, - le = script.jsAttributes.length; - - console.debug('removing given attribute', script, reason); - script.element.setAttribute('data-librejs-blocked-event', - JSON.stringify(script.jsAttributes)); - - script.tagAsRemoved(this.pageURL, reason, script.hash || script.tree.hash); - - // might need to be removed. - script.element.setAttribute('data-librejs-blocked-value', ''); - - if (!allowedRef.urlInAllowedReferrers(this.pageURL)) { - // only run if not in dry run mode. - for (; i < le; i++) { - console.debug('removing attribute', JSON.stringify(script.jsAttributes)); - script.element.removeAttribute(script.jsAttributes[i].attribute); - } - } else { - - } - this.hasRemovedScripts = true; -}; - -/** - * removeAllJs - * Loop through all scripts from top to bottom and add a type - * attribute 'librejs/blocked' to prevent their interpretation - * by the browser. - * - */ -DomHandler.prototype.removeAllJs = function (reason) { - // remove all js is useless from now on. - console.debug('removeAllJs'); - this.hasRemovedScripts = true; - - // removeAllJs needs not be run next time. - this.removedAllScripts = true; - - try { - this.removeAllArray(this.scripts, reason); - this.callback(this.dom); - } catch (x) { - console.debug( - 'in removeAllJs method: ', - x, - 'number of scripts is', - this.numScripts - ); - this.callback(this.dom); - } - -}; - -DomHandler.prototype.removeAllArray = function(scriptArray, reason) { - var script, i = 0, le; - console.debug('removeAllArray'); - try { - le = scriptArray.length; - // loop through all scripts. - - for (; i < le; i++) { - script = scriptArray[i]; - if (script.type === scriptTypes.INLINE || - script.type === scriptTypes.EXTERNAL - ) { - this.removeGivenJs(script, reason); - } - else if (script.type === scriptTypes.ATTRIBUTE) { - this.removeGivenAttribute(script, reason); - } - } - } catch (e) { - this.callback(""); - } - -}; - -exports.DomHandler = DomHandler; - -/** - * exports.domHandler - * Instantiates a DomHandler and checks the DOM - * @param dom obj The given dom for analysis. - * @param pageURL string the URL for the page. - * @param callback function callback when all the work has been performed. - */ -exports.domHandler = function( - dom, pageURL, fragment, responseStatus, callback) { - console.debug("Creating domHandler"); - var domHandler = new DomHandler(); - domHandler.init(dom, pageURL, fragment, responseStatus, callback); - - // use domGatherer methods. - domHandler.domGatherer = domGatherer(domHandler); - - // use domChecker methods. - domHandler.domChecker = domChecker(domHandler); - - // launch the whole process. - console.debug("Calling processScripts"); - domHandler.processScripts(); -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/attributes.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/attributes.js @@ -1,139 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -// object model for script entries. -var scriptObject = require("html_script_finder/dom_handler/script_object"); - -var scriptProperties = require("html_script_finder/dom_handler/script_properties"); - -const scriptTypes = scriptProperties.scriptTypes; - -const statusTypes = scriptProperties.statusTypes; - -var jsInAttrRe = /javascript:/ig; - -// the list of all available event attributes -var intrinsicEvents = [ - "onload", - "onunload", - "onclick", - "ondblclick", - "onmousedown", - "onmouseup", - "onmouseover", - "onmousemove", - "onmouseout", - "onfocus", - "onblur", - "onkeypress", - "onkeydown", - "onkeyup", - "onsubmit", - "onreset", - "onselect", - "onchange"]; - -exports.jsInAttrRe = jsInAttrRe; -exports.intrinsicEvents = intrinsicEvents; - - -/** - * findJSinAttribute - * - * Looks for attributes containing 'javascript:' - * - */ -exports.findJSinAttribute = function (elem, callback) { - var i = 0, attrLen = elem.attributes.length; - - var attribPairs = []; - - for (; i < attrLen; i++) { - - //looping through all attributes in elem to look for "javascript:" - attrib = elem.attributes[i]; - - if (attrib.value.match(jsInAttrRe)) { - str = attrib.value.replace(jsInAttrRe, ''); - attribPairs.push({attribute: attrib.name, value: str}); - } - - } - - if (attribPairs.length > 0) { - // contains in attribute javascript. - scriptEntry = scriptObject.Script({'type': scriptTypes.ATTRIBUTE, - 'status': statusTypes.UNCHECKED, - 'element': elem, - 'jsAttributes': attribPairs - }); - - // push back to DOMHandler - callback(scriptEntry); - - } else { - callback(false); - } - -}; - -/** - * findOnJSAttribute. - * - * Look for attributes in on* - * - */ -exports.findOnJSAttribute = function (elem, callback) { - - var i = 0, eventsLen = intrinsicEvents.length; - - var attribPairs = []; - - for (; i < eventsLen; i++) { - - // looping through all on* attributes - if (elem.hasAttribute(intrinsicEvents[i])) { - - attribPairs.push({ - attribute: intrinsicEvents[i], - value: elem.getAttribute(intrinsicEvents[i]) - }); - - } - - } - if (attribPairs.length > 0) { - - console.debug('found an attribute', scriptTypes.ATTRIBUTE); - scriptEntry = scriptObject.Script({'type': scriptTypes.ATTRIBUTE, - 'status': statusTypes.UNCHECKED, - 'element':elem, - 'jsAttributes': attribPairs - }); - // Push back to DOMHandler. - // push back to DOMHandler - callback(scriptEntry); - - } else { - callback(false); - } -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/dom_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/dom_checker.js @@ -1,480 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * dom_checker.js - * - * checks scripts for nonfree/nontrivial. - * - */ - -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); -var timer = require("sdk/timers"); - -var scriptProperties = require("html_script_finder/dom_handler/script_properties"); -const scriptTypes = scriptProperties.scriptTypes; -const statusTypes = scriptProperties.statusTypes; -const reasons = scriptProperties.reasons; - -// ensure xhr won't create an infinite loop -// with html content. -var urlTester = require("html_script_finder/url_seen_tester").urlSeenTester; -var urlHandler = require("url_handler/url_handler"); - -var privacyChecker = require("js_checker/privacy_checker").privacyCheck; -var jsChecker = require("js_checker/js_checker"); - -const types = require("js_checker/constant_types"); -var checkTypes = types.checkTypes; -var stripCDATAOpen = /<\!\[CDATA\[/gi; -var stripCDATAClose = /]]>/g; - -const getHash = require("script_entries/scripts_cache").scriptsCached.getHash; - -var DomChecker = function() { - // reference to domHandler instance - // using this object. - this.d = null; -}; - -/** - * init - * - * assign a reference domHandler object - * to access/updates its properties. - * - */ -DomChecker.prototype.init = function(domHandler) { - "use strict"; - - this.d = domHandler; -}; - -DomChecker.prototype.destroy = function() { - "use strict"; - - this.d = null; -}; - -/** - * checkAllInlineScripts - * - * Sends all the inline/onpage scripts as a whole for a check and - * removes all scripts if nonfree nontrivial is found. - * - */ -DomChecker.prototype.checkAllInlineScripts = function() { - "use strict"; - - try { - var i = 0, len, script; - - if (typeof this.d.inlineScripts !== 'undefined' && - this.d.inlineScripts.length > 0 - ) { - script = this.d.inlineScripts.shift(); - console.debug("checking script for page", - this.d.pageURL - /*, JSON.stringify(script)*/); - if (this.d.removedAllScripts) { - // all js has already been removed. - // stop check. - console.debug("removed all"); - return; - } - - if (this.d.inlineJsFree === true) { - // add entry as accepted. - try { - hash = getHash(script.text); - script.tagAsAccepted(this.d.pageURL, reasons.FREE, hash); - } catch (e) { - console.debug(e); - } - } - - // even if page is free we need to check for allow trivial. - if (script.type === scriptTypes.INLINE) { - console.debug("analyzing script", script); - this.analyzeJs(script, - script.text, - this.checkSingleInlineScript.bind(this)); - } else if (script.type === scriptTypes.ATTRIBUTE) { - console.debug("analyzing inline script", script); - this.analyzeJs(script, - this.concatAttributes(script), - this.checkSingleElementAttributes.bind(this)); - } - } else { - // no more inline scripts. Switch to external scripts. - this.readyForExternal(); - } - } catch (x) { - console.debug('checkAllInlineScripts error', - x, x.lineNumber, x.fileName); - this.readyForExternal(); - } -}; - -DomChecker.prototype.concatAttributes = function(script) { - "use strict"; - var i = 0, - le = script.jsAttributes.length, - text = ""; - - // we concatenate all js in multiple attributes. - // because it's too much of a hassle to keep track - // otherwise. - for (; i < le; i++) { - text += script.jsAttributes[i].value + '\n'; - } - - return text; -}; - -/** - * - * check a single element with attributes - */ -DomChecker.prototype.checkSingleElementAttributes = function( - script, loadedScript, checker) { - "use strict"; - var check, value, - i = 0, - le = script.jsAttributes.length, - text = ""; - - try { - check = checker.parseTree.freeTrivialCheck; - script.tree = checker; - script.result = check; - script.status = statusTypes.CHECKED; - } catch (e) { - console.debug('problem checking inline scripts', e, e.lineNumber); - this.d.removeGivenJs(script); - } - - this.processInlineCheckResult(script, check, checker); -}; - -DomChecker.prototype.processInlineCheckResult = function( - script, check, checker) { - "use strict"; - console.debug("check.reason is", check.reason, "and type", check.type); - var hash = checker.hash; - - if (this.d.inlineJsFree === true) { - console.debug('tagging', script.text, 'as accepted', "with reason", check.reason); - script.tagAsAccepted(this.d.pageURL, this.d.freeReason + " -- " + check.reason, hash); - } - - // process the result. - if (check.type === checkTypes.FREE) { - // this is free. - console.debug('tagging', script.text, 'as accepted with reason', check.reason); - this.d.inlineJsFree = true; - this.d.freeReason = check.reason; - // add entry as accepted. - script.tagAsAccepted(this.d.pageURL, check.reason, hash); - } else if (check.type === checkTypes.FREE_SINGLE_ITEM) { - // accept this script. - console.debug("free single item, ", check.reason); - script.tagAsAccepted(this.d.pageURL, check.reason, hash); - } else if (check.type === checkTypes.NONTRIVIAL) { - console.debug("nontrivial hash is", hash); - if (this.d.inlineJsFree) { - // inline is free. So accept. - console.debug('tagging', script.text, 'as accepted'); - script.tagAsAccepted( - this.d.pageURL, - this.d.freeReason + ' -- ' + check.reason, - hash); - } else { - console.debug('tagging', script.text, 'as removed'); - this.d.removeGivenJs(script, check.reason, false, hash); - } - } else if (!this.d.inlineJsFree && - this.d.loadsHtmlExternalScripts && - check.type === checkTypes.TRIVIAL_DEFINES_FUNCTION - ) { - // nontrivial, because defines function and loads - // external scripts - console.debug('tagging', script.text, 'as removed'); - this.d.removeGivenJs(script, reasons.FUNCTIONS_INLINE, false, hash); - } else if (!this.d.loadsHtmlExternalScripts && - check === checkTypes.TRIVIAL_DEFINES_FUNCTION - ) { - console.debug("Tag as accepted doesn't load another external script"); - script.tagAsAccepted(this.d.pageURL, check.reason, hash); - } else if (check.type === checkTypes.TRIVIAL || - check.type === checkTypes.TRIVIAL_DEFINES_FUNCTION || - check.type === checkTypes.WHITELISTED - ) { - // add entry as accepted. - console.debug("Trivial accepted"); - script.tagAsAccepted(this.d.pageURL, check.reason, hash); - } - - // next inline script, if applicable. - this.checkAllInlineScripts(); -}; - -DomChecker.prototype.readyForExternal = function() { - "use strict"; - - console.debug('DomChecker.readyForExternal'); - // done with those inline scripts, continue with - // the rest. - this.checkExternalScripts(); -}; - -/** - * check a single inline script. - */ -DomChecker.prototype.checkSingleInlineScript = function( - script, loadedScript, checker) { - "use strict"; - var check, text; - - console.debug('DomChecker.checkSingleInlineScript'); - - try { - - check = checker.parseTree.freeTrivialCheck; - - // update status. - script.tree = checker; - script.result = check; - console.debug("script result is", check.type); - script.status = statusTypes.CHECKED; - - } catch (e) { - console.debug('problem checking inline scripts', e, e.lineNumber); - this.d.removeGivenJs(script, '', false, checker.hash); - } - - this.processInlineCheckResult(script, check, checker); - -}; - -/** - * checkExternalScripts - * Loop through series of external scripts, - * perform xhr to get their data, and check them - * to see whether they are free/nontrivial - * - */ -DomChecker.prototype.checkExternalScripts = function() { - "use strict"; - - console.debug('DomChecker.checkExternalScripts'); - - var i = 0; - var len = this.d.externalScripts.length; - var that = this; - - console.debug("externalScripts length", len); - if (this.d.removedAllScripts || len === 0) { - // all js has already been removed. - // stop check. - this.wrapUpBeforeLeaving(); - return; - } - - for (; i < len; i++) { - this.xhr( - this.d.externalScripts[i], - function(script, scriptText) { - console.debug("In xhr callback for script url:", script.url); - if (scriptText === false) { - that.d.removeGivenJs(script); - that.d.scriptHasBeenTested(); - that.externalCheckIsDone(); - return; - } - - console.debug('about to analyzeJS for script:', script.url); - that.analyzeJs( - script, - scriptText, - that.checkSingleExternalScript.bind(that)); - } - ); - } -}; - -DomChecker.prototype.wrapUpBeforeLeaving = function() { - "use strict"; - - console.debug("wrap up before leaving triggered"); - console.debug('wrapping up'); - this.d.callback(this.d.dom); - -}; - -DomChecker.prototype.analyzeJs = function(script, scriptText, callback) { - "use strict"; - console.debug('DomChecker.analyzeJs for script:', script.url); - try { - var checker = jsChecker.jsChecker(); - var url = ""; - if (typeof script.url !== "undefined") { - url = script.url; - } else { - url = this.pageURL; - } - checker.searchJs(scriptText, function() { - console.debug("Analyze JS"/*, JSON.stringify(checker)*/); - timer.setTimeout(function() { - callback(script, scriptText, checker); - }, 0); - }, url); - } catch (x) { - console.debug('error', x, x.lineNumber, x.fileName); - } -}; - -/** - * Check a single external script. - */ -DomChecker.prototype.checkSingleExternalScript = function( - script, loadedScript, checker -) { - "use strict"; - var check; - - console.debug('DomChecker.checkSingleExternalScript()'); - try { - check = checker.parseTree.freeTrivialCheck; - - script.tree = checker; - script.result = check; - console.debug('in checkSingleExternalScript, checker.hash is', - checker.hash); - if (script.status != statusTypes.JSWEBLABEL) { - script.status = statusTypes.CHECKED; - } - - if (check.type === checkTypes.FREE || - check.type === checkTypes.FREE_SINGLE_ITEM - ) { - // add entry as accepted. - script.tagAsAccepted(this.d.pageURL, check.reason, checker.hash); - } - - else if (check.type === checkTypes.NONTRIVIAL) { - console.debug("Removing given js", check.reason); - this.d.removeGivenJs(script, check.reason, false, checker.hash); - } - - else if (check.type === checkTypes.TRIVIAL || - check.type === checkTypes.WHITELISTED - ) { - // if it's accepted, allow. - script.tagAsAccepted(this.d.pageURL, check.reason, checker.hash); - } else { - // anything else is nontrivial. Including TRIVIAL_DEFINES_FUNCTION. - console.debug("checker hash for remove is ", checker.hash); - this.d.removeGivenJs( - script, reasons.FUNCTIONS_EXTERNAL, false, checker.hash); - } - - } catch (e) { - console.debug('error in checkExternalScript', - e, e.lineNumber, 'for script', script.url); - - this.d.removeAllJs(); - this.destroy(); - return; - } - console.debug('script url is', script.url, 'result is', script.result); - this.d.scriptHasBeenTested(); - this.externalCheckIsDone(); -}; - -DomChecker.prototype.externalCheckIsDone = function() { - "use strict"; - console.debug('DomChecker.externalCheckIsDone'); - - console.debug('scriptsTested is', this.d.scriptsTested); - console.debug('num external', this.d.numExternalScripts); - - if (this.d.scriptsTested >= this.d.numExternalScripts) { - console.debug('wrapping up external'); - this.wrapUpBeforeLeaving(); - } else { - var scriptsToCheck = this.d.numExternalScripts - this.d.scriptsTested; - console.debug('Not wrapping up! Waiting to check ' + scriptsToCheck + - ' more script(s)'); - - if (this.d.externalScripts[0]) { - console.debug('script 0 is', this.d.externalScripts[0]); - } - if (this.d.externalScripts[1]) { - console.debug('script 1 is', this.d.externalScripts[1]); - } - } -}; - -/** - * xhr - * Perform a XMLHttpRequest on the url given. - * @param url string A URL. - * @return The response text. - */ -DomChecker.prototype.xhr = function(script, responseCallback) { - "use strict"; - - var regex = /^text\/html/i; - var url = script.url; - - try { - // add url to whitelist. - urlTester.addUrl(url); - - // request module. Compatible with Https-Everywhere. - require('html_script_finder/dom_handler/request') - .request(script, responseCallback).request(); - } catch (x) { - console.debug('error', x, x.lineNumber, x.fileName); - responseCallback(script, false); - } -}; - -/** - * exports.domChecker - * Instantiate a brand new clone of the domChecker. - * @param dom obj The given dom for analysis. - * @param pageURL string the URL for the page. - * @param callback function callback when all the work has been performed. - */ -exports.domChecker = function(domHandler) { - "use strict"; - - var domChecker = new DomChecker(); - - domChecker.init(domHandler); - - return domChecker; -}; - -exports.xhr = new DomChecker().xhr; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/dom_gatherer.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/dom_gatherer.js @@ -1,283 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var scriptProperties = require("html_script_finder/dom_handler/script_properties"); - -const scriptTypes = scriptProperties.scriptTypes; -const scriptsCached = require("script_entries/scripts_cache").scriptsCached; - -const statusTypes = scriptProperties.statusTypes; -// object model for script entries. -var scriptObject = require("html_script_finder/dom_handler/script_object"); - -var urlHandler = require("url_handler/url_handler"); - -var attributeHelpers = require("html_script_finder/dom_handler/attributes"); - -// javascript:* -var jsInAttrRe = attributeHelpers.jsInAttrRe; - -// the list of all available event attributes -var intrinsicEvents = attributeHelpers.intrinsicEvents; - -var privacyChecker = require("js_checker/privacy_checker").privacyCheck; - -const types = require("js_checker/constant_types"); - -var checkTypes = types.checkTypes; - -// array reflex valid types as listed in -// http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsScriptLoader.cpp#437 -// anything appended to end of strings is considered valid: -var jsValidTypes = [ - /^text\/javascript/i, - /^text\/ecmascript/i, - /^application\/javascript/i, - /^application\/ecmascript/i, - /^application\/x-javascript/i -]; - -var stripCDATAOpen = /<\!\[CDATA\[/gi; -var stripCDATAClose = /]]>/g; - -var stripHtmlCommentsInScript = function (s) { - s = s.replace(stripCDATAOpen, ''); - s = s.replace(stripCDATAClose, ''); - return s; -}; - - -// gather scripts and javascript in attributes across a dom object. -var DomGatherer = function() { - // domHandler object. - this.d = null; -}; - -/** - * init - * - * assign a reference domHandler object - * to access/updates its properties. - * - */ -DomGatherer.prototype.init = function (domHandler) { - this.d = domHandler; -}; - -/** - * scriptHasInvalidType - * - * Checks that a script does not have a js "template" type. - * Normally any script that has a type attribute other than the - * few allowed ones is not interpreted. But by security, we only - * discard a few of them. - * - * @param script obj The script element. - * @return returns true if it matches a template type. - * - */ -DomGatherer.prototype.scriptHasInvalidType = function (script) { - var i = 0, - le = jsValidTypes.length; - - var type = script.getAttribute('type'); - - if (type === 'librejs/blocked') { - // js has already been blocked. - return true; - } - - if (!type) { - // type isn't set, don't look further. - return false; - } - - for (; i < le; i++) { - if (jsValidTypes[i].test(type)) { - return false; - } - } - - // type is invalid and - // hence cannot be executed. - return true; -}; - -/** - * findScripts - * - * Assigns the array of scripts in the dom to a property - * as well as a number of scripts present for looping purposing. - */ -DomGatherer.prototype.findScripts = function() { - this.d.domScripts = this.d.dom.getElementsByTagName('script'); - this.d.numScripts = this.d.domScripts.length; -}; - -/** - * gatherIntrinsicEvents - * - * Fetches all the event attributes that might contain JavaScript - * as well as all element attributes that start with - * "javascript:". - * - */ -DomGatherer.prototype.gatherIntrinsicEvents = function() { - var i = 0, j, k, - all = this.d.dom.getElementsByTagName('*'), - max = all.length, - that = this, - attrLen, attrib, str, scriptEntry; - - for (; i < max; i++) { - // look for attributes with value javascript:* - attributeHelpers.findJSinAttribute( - all[i], - function (scriptEntry) { - if (scriptEntry !== false) { - - that.d.inlineScripts.push(scriptEntry); - that.d.scripts.push(scriptEntry); - - // add inline script in the count. - that.d.numInlineScripts++; - } - }); - - // look for attributes of on* (onLoad, ...) - attributeHelpers.findOnJSAttribute( - all[i], - function (scriptEntry) { - if (scriptEntry !== false) { - that.d.inlineScripts.push(scriptEntry); - that.d.scripts.push(scriptEntry); - - // add inline script in the count. - that.d.numInlineScripts++; - } - }); - } - -}; - -/** - * gatherScriptsContent - * - * Aggregate all content within on-page JavaScript code. - * Keep a list of all absolute urls to external scripts. - * - */ -DomGatherer.prototype.gatherScriptsContent = function() { - var i = 0, currentScript = '', absolutePath, scriptEntry, - that = this; - try { - for (; i < this.d.numScripts; i++) { - if (this.d.checkScriptForJsWebLabels(this.d.domScripts[i])) { - //break; - absolutePath = urlHandler.resolve( - this.d.pageURL, this.d.domScripts[i].src); - scriptEntry = scriptObject.Script( - {'type': scriptTypes.EXTERNAL, - 'status': statusTypes.JSWEBLABEL, - 'element': this.d.domScripts[i], - 'url': absolutePath}); - scriptEntry.tree = {}; - - this.d.externalScripts.push(scriptEntry); - that.d.scripts.push(scriptEntry); - - this.d.loadsHtmlExternalScripts = true; - - // increment number of scripts found. - this.d.numExternalScripts++; - } - - // check that script has valid type - else if (!this.scriptHasInvalidType(this.d.domScripts[i])) { - - - if (this.d.hasSrc(this.d.domScripts[i]) && - !this.d.scriptHasJsWebLabel(this.d.domScripts[i])) { - - console.debug('an external script', this.d.domScripts[i]); - - absolutePath = urlHandler.resolve( - this.d.pageURL, this.d.domScripts[i].src); - scriptEntry = scriptObject.Script( - {'type': scriptTypes.EXTERNAL, - 'status': statusTypes.UNCHECKED, - 'element': this.d.domScripts[i], - 'url': absolutePath}); - this.d.externalScripts.push(scriptEntry); - that.d.scripts.push(scriptEntry); - - this.d.loadsHtmlExternalScripts = true; - - // increment number of scripts found. - this.d.numExternalScripts++; - - } else if (privacyChecker.checkScriptPrivacyThreat(this.d.domScripts[i].text)) { - this.d.removeGivenJs(scriptObject.Script( - {'type': scriptTypes.SINGLETON, - 'status': statusTypes.UNCHECKED, - 'element': this.d.domScripts[i], - 'text': this.d.domScripts[i].text - }), '', true); - } else if (this.d.domScripts[i].text !== '') { - // using else if since script text is - // ignored if src attribute is set. - // adding this.narcissusBugFixLibreJS to fix comment bug. - var bugfix = require('html_script_finder/bug_fix').narcissusBugFixLibreJS; - currentScript = stripHtmlCommentsInScript(this.d.domScripts[i].text + bugfix); - - scriptEntry = scriptObject.Script( - {'type': scriptTypes.INLINE, - 'status': statusTypes.UNCHECKED, - 'element': this.d.domScripts[i], - 'text': currentScript}); - this.d.inlineScripts.push(scriptEntry); - this.d.scripts.push(scriptEntry); - - // add inline script in the count. - this.d.numInlineScripts++; - } - } - } - } catch (e) { - // Any problem arising, we remove the script. - console.debug('problem gathering scripts', e, e.lineNumber); - this.d.removeAllJs(); - } -}; - -/* - * exports.domGatherer - * Instantiate a brand new clone of the domGatherer. - * @param dom obj The given dom for analysis. - * @param pageURL string the URL for the page. - * @param callback function callback when all the work has been performed. - */ -exports.domGatherer = function (domHandler) { - var dg = new DomGatherer(); - dg.init(domHandler); - return dg; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/request.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/request.js @@ -1,117 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var timer = require("sdk/timers"); - -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); -var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - - -// ensure xhr won't create an infinite loop -// with html content. -var urlTester = require("html_script_finder/url_seen_tester").urlSeenTester; -var urlHandler = require("url_handler/url_handler"); -const scriptsCached = require("script_entries/scripts_cache").scriptsCached; - -var Request = function() { - this.url = null; - this.channel = null; - this.script = null; - this.responseCallback = null; -}; - -/** - * init - */ -Request.prototype.init = function(script, callback) { - this.script = script; - // set initial url - this.url = this.script.url; - - console.debug('In Request.init() for url:', this.url); - - this.responseCallback = callback; - - var iOService = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); - - this.channel = iOService.newChannel(this.url, null, null); -}; - -Request.prototype.request = function() { - var that = this; - var responseReceived = function (data) { - that.responseCallback(that.script, data); - }; - try { - this.channel.asyncOpen({ - QueryInterface: XPCOMUtils.generateQI( - [Ci.nsIRequestObserver, Ci.nsIStreamListener]), - data: "", - charset: null, - - onStartRequest: function(request, context) { - this.charset = request.contentCharset || "UTF-8"; - }, - - onDataAvailable: function (request, context, stream, offset, count) { - try { - var binaryInputStream = Cc["@mozilla.org/binaryinputstream;1"] - .createInstance(Ci.nsIBinaryInputStream); - binaryInputStream.setInputStream(stream); - var data = binaryInputStream.readBytes(count); - this.data += data; - } catch (x) { - console.debug('error in request', x, x.lineNumber); - responseReceived(""); - } - }, - - onStopRequest: function (request, context, result) { - try { - if (this.charset.toLowerCase() != "utf-8") { - var uConv = Cc["@mozilla.org/intl/utf8converterservice;1"] - .createInstance(Ci.nsIUTF8ConverterService); - - this.data = uConv.convertStringToUTF8( - this.data, this.charset, true); - } - } catch (e) { - console.debug("Issue with nsIUTF8ConverterService", e); - console.debug("Charset was", this.charset); - responseReceived(""); - } - responseReceived(this.data); - } - }, null); - } catch(e) { - console.debug("asyncOpen exception", e); - responseReceived(""); - } -}; - -// Instantiate a Request -exports.request = function(script, callback) { - var obj = new Request(); - obj.init(script, callback); - return obj; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/script_object.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/dom_handler/script_object.js @@ -1,210 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var removedScripts = require("script_entries/removed_scripts").removedScripts; - -var acceptedScripts = require("script_entries/accepted_scripts") - .acceptedScripts; -var dryRunScripts = require("script_entries/dryrun_scripts").dryRunScripts; - -var Script = function(props) { - // can be an attribute, an inline script, - // or an external script. - this.type = null; - - /* - * Script.status - The script's current status. - * - * Possible values are: - * - * 0 - unchecked - * 1 - checked - * 2 - accepted - * 3 - rejected - * 4 - jsweblabel - * - * See script_properties.js for definitions. - */ - this.status = null; - - // contains the dom element - this.element = null; - - // the attribute name, if applicable. - this.attribute = null; - - // the script text as a string. - this.value = null; - - // the src url if external. - this.url = null; - - // the script text if inline. - this.text = null; - - this.init(props); -}; - -Script.prototype.init = function(props) { - // check the required elements are present. - if (typeof props === 'undefined') { - throw "Error, missing script entry value in script_object.js"; - } - - // required properties - if (typeof props.type !== 'undefined') { - this.type = props.type; - } else { - throw "type is missing"; - } - - if (typeof props.status !== 'undefined') { - this.status = props.status; - } else { - throw "status is missing"; - } - - if (typeof props.element !== 'undefined') { - this.element = props.element; - } else { - throw "element is missing"; - } - - // conditional properties. - this.url = (props.url) ? props.url : null; - this.text = (props.text) ? props.text : null; - this.jsAttributes = (props.jsAttributes) ? props.jsAttributes : null; - - if (typeof this.text !== 'string' && - this.tree !== null && - typeof this.tree === 'object' && - this.tree.hasOwnProperty('jsCode') - ) { - this.text = this.tree.jsCode; - } -}; - -Script.prototype.tagAsDryRun = function(pageURL, reason, hash) { - var content = this.findContentType(); - var inline = (this.url != undefined) ? false : true; - var url = (inline == false ? this.url : null); - console.debug("url is", url); - this.element.setAttribute('data-librejs', 'dryrun'); - this.element.setAttribute('data-librejs-reason', reason); - - dryRunScripts.addAScript( - pageURL, - {'inline': inline, - 'contents': content, - 'reason': reason, - 'url': url, - 'hash': hash - }); -}; - -Script.prototype.tagAsAccepted = function(pageURL, reason, hash) { - var content = this.findContentType(); - var inline = (this.url != undefined) ? false : true; - var url = (inline == false ? this.url : null); - console.debug("url is", url); - this.element.setAttribute('data-librejs', 'accepted'); - this.element.setAttribute('data-librejs-reason', reason); - - acceptedScripts.addAScript( - pageURL, - {'inline': inline, - 'contents': content, - 'reason': reason, - 'url': url, - 'hash': hash - }); - -}; - -Script.prototype.tagAsRemoved = function(pageURL, reason, hash) { - var content = this.findContentType(); - var inline = (this.url != undefined) ? false : true; - var url = (inline == false ? this.url : null); - this.element.setAttribute('data-librejs', 'rejected'); - this.element.setAttribute('data-librejs-reason', reason); - console.debug("tagAsRemoved hash is", hash); - removedScripts.addAScript(pageURL, { - 'inline': inline, - 'contents': content, - 'reason': reason, - 'url': url, - 'hash': hash - }); - -}; - -Script.prototype.tagAsDryRun = function(pageURL, reason, hash) { - var content = this.findContentType(); - var inline = (this.url != undefined) ? false : true; - var url = (inline == false ? this.url : null); - this.element.setAttribute('data-librejs', 'dryrun'); - this.element.setAttribute('data-librejs-reason', reason); - - dryRunScripts.addAScript( - pageURL, - {'inline': inline, - 'contents': content, - 'reason': reason, - 'url': url, - 'hash': hash - }); -}; - -/** - * removeNarcissusBugLine - * - * Removes the line that is appended to all - * inline scripts and prevent the bug that prevent - * script tags with comments only from being checked. - * - */ -Script.prototype.removeNarcissusBugLine = function(str) { - return str.replace('\n\nthis.narcissusBugFixLibreJS', ''); -}; - -/** - * findContentType - * - * Figure out whether it's an external script, - * an inline script, or an attribute from the property - * that has been set, rather than blindly trusting the given - * constant. - */ -Script.prototype.findContentType = function() { - if (this.url != undefined) { - return ""; - } else if (this.text != undefined) { - return this.element.text; - } else if (this.jsAttributes != undefined) { - // return the array. - return JSON.stringify(this.jsAttributes); - } -}; - -exports.Script = function(props) { - return new Script(props); -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/html_parser.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/html_parser.js @@ -1,160 +0,0 @@ -/* - # ***** BEGIN LICENSE BLOCK ***** - # Version: MPL 1.1/GPL 2.0/LGPL 2.1 - # - # The contents of this file are subject to the Mozilla Public License Version - # 1.1 (the "License"); you may not use this file except in compliance with - # the License. You may obtain a copy of the License at - # http://www.mozilla.org/MPL/ - # - # Software distributed under the License is distributed on an "AS IS" basis, - # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - # for the specific language governing rights and limitations under the - # License. - # - # The Original Code is Microsummarizer. - # - # The Initial Developer of the Original Code is Mozilla. - # Portions created by the Initial Developer are Copyright (C) 2006 - # the Initial Developer. All Rights Reserved. - # - # Contributor(s): - # Myk Melez <myk@mozilla.org> (Original Author) - # Simon Bünzli <zeniko@gmail.com> - # Asaf Romano <mano@mozilla.com> - # Dan Mills <thunder@mozilla.com> - # Ryan Flint <rflint@dslr.net> - # - # Alternatively, the contents of this file may be used under the terms of - # either the GNU General Public License Version 2 or later (the "GPL"), or - # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - # in which case the provisions of the GPL or the LGPL are applicable instead - # of those above. If you wish to allow use of your version of this file only - # under the terms of either the GPL or the LGPL, and not to allow others to - # use your version of this file under the terms of the MPL, indicate your - # decision by deleting the provisions above and replace them with the notice - # and other provisions required by the GPL or the LGPL. If you do not delete - # the provisions above, a recipient may use your version of this file under - # the terms of any one of the MPL, the GPL or the LGPL. - # - # ***** END LICENSE BLOCK ***** - */ - -/* - * The original file is located here: - * http://mxr.mozilla.org/mozilla/source/browser/components/microsummaries/src/nsMicrosummaryService.js?raw=1 - * - */ - -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * html_parser - * - * Takes in an http response (string), loads it into a secured iframe - * so that it can be manipulated as a DOM object. It then returns a - * modified string to be passed along as a replacement of the original - * response. - * - */ - -var {Cc, Ci, Cu} = require("chrome"); - -var domHandlerModule = require("html_script_finder/dom_handler"); - -const PR_UINT32_MAX = 2147483647; - - -exports.htmlParser = function () { - - return { - charset: null, - htmlText: null, - pageURL: null, - fragment: null, - contentType: null, - responseStatus: null, - - parse: function (htmlText, charset, contentType, url, fragment, - responseStatus, parseResult) { - - // DOMParser still has too many issues. - this.htmlText = htmlText; - this.charset = charset; - - if (this.charset === "" || this.charset === undefined) { - this.charset = "utf-8"; - } - this.contentType = contentType; - this.pageURL = url; - this.fragment = fragment; - this.responseStatus = responseStatus; - var that = this; - - var domParser = Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(Ci.nsIDOMParser); - - var dom = domParser.parseFromString(this.htmlText, this.contentType); - // console.debug(dom.getElementsByTagName('body')[0].innerHTML); - domHandlerModule.domHandler(dom, this.pageURL, this.fragment, this.responseStatus, function (newDom) { - parseResult(that.serializeToStream(newDom, that)); - }); - - }, - - /** - * serializeToStream - * Serializes an HTML DOM into a binary stream. Uses - * nsIDOMSerializer only as a backup to when the - * reconstituteHtmlString method fails (not sure if/when it - * happens). - * @param dom obj Reference to the dom object - * @param that obj Reference to the object returned by htmlParser. - * This allows to give access to the iframe. - * @return a binary stream. - */ - serializeToStream: function (dom, that) { - - var newData, len; - - try { - var storageStream = Cc["@mozilla.org/storagestream;1"].createInstance(Ci.nsIStorageStream); - var binaryOutputStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream); - var serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"].createInstance(Ci.nsIDOMSerializer); - var encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=" + this.contentType] - .createInstance(Ci.nsIDocumentEncoder); - - encoder.setCharset(this.charset); - encoder.init(dom, this.contentType, 0); - storageStream.init(8192, PR_UINT32_MAX, null); - - binaryOutputStream.setOutputStream(storageStream.getOutputStream(0)); - encoder.encodeToStream(binaryOutputStream); - return storageStream; - } catch (e) { - console.debug('issue with serializer', e, e.lineNumber); - } - } - - }; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/web_labels/js_web_labels.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/web_labels/js_web_labels.js @@ -1,300 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -// node.js url module. Makes it easier to resolve -// urls in that datauri loaded dom -var urlHandler = require("url_handler/url_handler"); -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); -var data = require("sdk/self").data; - -// license definitions, we are using canonical urls and license -// identifiers. -var licenses = require('js_checker/license_definitions').licenses; - -var getLicenseList = require('html_script_finder/web_labels/find_js_labels') - .getLicenseList; -const types = require("js_checker/constant_types"); - -const addToCache = require("html_script_finder/web_labels/script_hash_worker") - .addToCache; - -// keep web labels in memory so that they can be checked even when they -// are embedded dynamically. -var jsWebLabelEntries = {}; - -// store the url to js web labels already visited during this session -var jsLabelsPagesVisited = {}; - -var WebLabelFinder = function () { - this.dom = null; - this.pageURL = null; - this.jslicenseURL = null; - this.pageContent = null; - this.licenseList = null; - this.callback = null; -}; - -WebLabelFinder.prototype.init = function(dom, pageURL, callback) { - var that = this; - this.pageURL = pageURL; - this.dom = dom; - this.callback = function (a) { - if (typeof a === 'undefined') { - a = null; - } - - // rewrite callback as soon as it is triggered once. - that.callback = function () { - console.debug("Callback already called"); - }; - - callback(a); - }; - this.findJavaScriptLicenses(); - this.pageContent = ''; - this.jslicenseURL = ''; -}; - -WebLabelFinder.prototype.findJavaScriptLicenses = function () { - this.searchForJsLink(); - - if (this.jslicenseURL && !(jsLabelsPagesVisited[this.jslicenseURL])) { - // get content from license page. - console.debug('called fetch license page for', this.jslicenseURL); - this.pageContent = this.fetchLicensePage(); - } else { - console.debug(this.jslicenseURL, "already visited"); - this.callback(); - } -}; - -WebLabelFinder.prototype.searchForJsLink = function() { - console.debug('triggered searchForJsLink'); - if (this.dom) { - var linkTags = this.dom.getElementsByTagName('a'), - i = 0, - len = linkTags.length, - path; - - // loop through all a tags. - for (; i < len; i++) { - if ( - (linkTags[i].hasAttribute('rel') && - linkTags[i].getAttribute('rel') === 'jslicense') || - (linkTags[i].hasAttribute('data-jslicense') && - linkTags[i].getAttribute('data-jslicense') === '1') - ) { - // This page has a web labels link - return this.formatURL(linkTags[i]); - } - } - } - - // no js web labels were found. call back. - this.callback(); - return false; -}; - -WebLabelFinder.prototype.formatURL = function(link) { - this.jslicenseURL = urlHandler.resolve(this.pageURL, link.href); - this.jslicenseURL = urlHandler.addFragment(this.jslicenseURL, 'librejs=true'); - console.debug('license URL found', this.jslicenseURL); - return this.jslicenseURL; -}; - -WebLabelFinder.prototype.fetchLicensePage = function() { - var that = this; - try { - var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(); - - req.onload = function() { - console.debug("Fetching License!"); - console.debug("URL is ", this._url); - - that.licenseList = getLicenseList(this.responseXML); - console.debug("the license list", that.licenseList); - that.matchListWithDefs(this._url); - - // add these entries to the global - // object for dynamically embedded scripts. - jsWebLabelEntries[that.pageURL] = that.licenseList; - jsLabelsPagesVisited[req._url] = 1; - }; - console.debug(this.jslicenseURL); - req.open('GET', this.jslicenseURL, true); - req._url = this.jslicenseURL; - req.responseType = "document"; - req.send(); - } catch (e) { - console.debug(e, e.lineNumber, e.fileName, this.jslicenseURL); - this.callback({}); - } -}; - -/** - * @method isLicenseFree - * Returns true if the given web labels row refers to a script that - * can be executed by LibreJS. - * - * This method has some side effects :-/ - * - * @param {Object} lic - A license node from a JS web labels page. It's - * expected to contain one or more licenses. - * @return {Boolean} - */ -WebLabelFinder.prototype.isLicenseFree = function( - lic, jslicenseURL, callback -) { - // For each license that this license row contains. - var isFree = false; - // licenseStatuses is later used to determine isFree. - var licenseStatuses = []; - - for (var i = 0; i < lic.licenses.length; i++) { - var license; - var found = false; - - // Check if we can look up this license by its identifier. - var identifier = lic.licenses[i]['licenseName']; - if (typeof identifier !== 'undefined' && - typeof licenses[identifier] !== 'undefined' - ) { - console.debug('recognized by index', identifier); - // This license was recognized, and it was free. Add it - // to the array of license status, which we'll look at - // when we're done with this web label row. - licenseStatuses.push(true); - - console.debug("about TO ADD TO XHR: ", lic.fileUrl); - this.listCheck[lic.fileUrl] = 0; - addToCache(lic, 0, jslicenseURL, callback); - - // Break out of the loop cause we found a matching license. - found = true; - continue; - } - - // For each license from the internal license definitions - for (license in licenses) { - if (found === true) { - break; - } - var licDef = licenses[license]; - var licArray = []; - if (!licDef.canonicalUrl) { - continue; - } - if (typeof licDef.canonicalUrl === 'string') { - licArray = [licDef.canonicalUrl]; - } else { - licArray = licDef.canonicalUrl; - } - - // For each of the canonical URLs recognized by this license - // definition - for (var j = 0; j < licArray.length; j++) { - if (urlHandler.removeFragment(licArray[j]) === - urlHandler.removeFragment(lic.licenses[i].licenseUrl) - ) { - if (!require("sdk/url").isValidURI(lic.fileUrl)) { - console.debug(lic.fileUrl, " is not a valid URL"); - callback(); - } - - // This license was recognized, and it was free. Add it - // to the array of license status, which we'll look at - // when we're done with this web label row. - licenseStatuses.push(true); - - console.debug("about TO ADD TO XHR: ", lic.fileUrl); - this.listCheck[lic.fileUrl] = 0; - addToCache(lic, 0, jslicenseURL, callback); - - // Break out of the nearest two loops cause we found - // a matching license - found = true; - break; - } - } - } - } - - // Tally up the licenses we were able to match. - if (licenseStatuses.length > 0 && - // If the number of licenses we matched is at least one, and - // it's the same number as the number of licenses in this Web - // Label column, only then can we recognize this script as free. - // licenseStatus.length should never be larger than - // lic.licenses.length. - licenseStatuses.length >= lic.licenses.length - ) { - isFree = true; - } - - return isFree; -}; - -WebLabelFinder.prototype.matchListWithDefs = function(jslicenseURL) { - var that = this; - var licDef, - license, script; - var cacheCalls = 0; - this.listCheck = {}; - - // nested loop. - cacheCalls = 0; - var callback = function (url) { - cacheCalls++; - that.listCheck[url] = 1; - if (cacheCalls === Object.keys(that.listCheck).length) { - console.debug("triggering callback duh"); - // return array to requester object - callback = false; - that.callback(that.licenseList); - } - }; - require("sdk/timers").setTimeout(function () { - // callback after 60 seconds if it's still not returned. - // using this as a safeguard. - // return array to requester object - if (callback !== false) { - that.callback(that.licenseList); - console.debug(that.listCheck); - } - }, 15000); - - for (var i = 0; i < this.licenseList.length; i++) { - // this.licenseList[i] is the web labels license column - var lic = this.licenseList[i]; - if (this.isLicenseFree(lic, jslicenseURL, callback)) { - lic.free = true; - } - } -}; - -exports.WebLabelFinder = WebLabelFinder; - -// Store the web labels harvested across webpages (only in this session). -exports.jsWebLabelEntries = jsWebLabelEntries; - -exports.jsLabelsPagesVisited = jsLabelsPagesVisited; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/web_labels/script_hash_worker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/html_script_finder/web_labels/script_hash_worker.js @@ -1,77 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -const types = require("js_checker/constant_types"); -const scriptsCached = require("script_entries/scripts_cache").scriptsCached; -const xhr = require('html_script_finder/dom_handler/dom_checker').xhr; -const timers = require("sdk/timers"); - -exports.addToCache = function (lic, delay, jsWebLabelsURL, callback) { - console.debug("jslicenseURL is", jsWebLabelsURL); - if (typeof delay === 'undefined') { - delay = 0; - } - - // get file hash and store as cached. - console.debug('performing xhr for', lic.fileUrl); - timers.setTimeout(function() { - var cb = function (script, contents) { - try { - // add a cache entry. - var hash = scriptsCached.addEntryIfNotCached( - contents, - types.freeWithComment( - 'This script is free according to a JS Web Labels ' + - 'page visited recently (at ' + - jsWebLabelsURL.replace("librejs=true", "") + ' )' - ), - {}, - true, - lic.fileUrl - ); - console.debug('returning xhr from', lic.fileUrl); - if (typeof callback === 'function') { - callback(lic.fileUrl); - } else { - console.debug('callback is not a function:', callback); - } - } catch (e) { - if (typeof callback === 'function') { - callback(lic.fileUrl); - } else { - console.debug('callback is not a function:', callback); - } - } - }; - // just callback after 5 seconds if we don't get the answer yet. - timers.setTimeout(function() { - cb = function() {}; - if (typeof callback === 'function') { - callback(lic.fileUrl); - } else { - console.debug('callback is not a function:', callback); - } - }, 20000); - - xhr({'url': lic.fileUrl}, cb); - }, delay); -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/allowed_referrers.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/allowed_referrers.js @@ -1,69 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var prefChange = require("addon_management/prefchange"); - -var allowed = {}; - -/** - * Contains a list of pages that are allowed - * to execute JavaScript regardless of whether it is - * nonfree and nontrivial. - */ -var AllowedReferrers = function() { -}; - -AllowedReferrers.prototype.addPage = function(url) { - allowed[url] = 1; -}; - -AllowedReferrers.prototype.urlInAllowedReferrers = function (url) { - if (allowed[url] === 1) { - return true; - } - // check if whitelisted. - return this.urlInWhitelist(url); -}; - -AllowedReferrers.prototype.urlInWhitelist = function(url) { - var whitelist = prefChange.getWhitelist(); - var i = 0, le = whitelist.length; - for (; i < le; i++) { - if (whitelist[i].test(url)) { - return true; - } - } -}; - -AllowedReferrers.prototype.clearSinglePageEntry = function(url) { - var index = allowed[url]; - - if (allowed[url] === 1) { - delete allowed[url]; - } -}; - -AllowedReferrers.prototype.clearAllEntries = function() { - allowed = {}; -}; - -exports.allowedReferrers = new AllowedReferrers(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/http_request_observer.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/http_request_observer.js @@ -1,148 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); - -var observerService = Cc["@mozilla.org/observer-service;1"] - .getService(Ci.nsIObserverService); - -// these are our target mime types for response interception. -var targetMimeTypes = /.*(javascript|ecmascript|html).*/i; -//var targetMimeTypes = /.*(html).*/i; - -// ensure xhr won't create an infinite loop -// with html content. -var urlTester = require("html_script_finder/url_seen_tester").urlSeenTester; -var streamLoader = require("http_observer/stream_loader").streamLoader; - -var httpRequestObserver = { - observe: function(request, aTopic, aData) { - console.debug('atopic is', aTopic); - var url, newListener, status; - - if (aTopic === "http-on-examine-response" || - aTopic === "http-on-examine-cached-response" || - aTopic === "http-on-examine-merged-response" - ) { - request.QueryInterface(Ci.nsIHttpChannel); - - if (request.URI.scheme !== 'chrome' && - (request.responseStatus < 300 || - request.responseStatus > 399) && - (targetMimeTypes.test(request.contentType) || - request.contentType === undefined) && - (!urlTester.isWhitelisted(request.URI.spec) && - !urlTester.isWhitelisted(request.originalURI.spec)) - ) { - newListener = new TracingListener(); - request.QueryInterface(Ci.nsITraceableChannel); - newListener.originalListener = request.setNewListener(newListener); - } else if (urlTester.isWhitelisted(request.URI.spec) || - urlTester.isWhitelisted(request.originalURI.spec) - ) { - urlTester.clearUrl(request.URI.spec); - urlTester.clearUrl(request.originalURI.spec); - } - - } - }, - - QueryInterface: function (aIID) { - if (aIID.equals(Ci.nsIObserver) || - aIID.equals(Ci.nsISupports) - ) { - return this; - } - throw Cr.NS_NOINTERFACE; - } -}; - -// Copy response listener implementation. -function TracingListener() { - this.originalListener = null; - this.streamLoader = streamLoader(); -} - -TracingListener.prototype = { - onDataAvailable: function(request, context, inputStream, offset, count) { - try { - this.streamLoader.loader.onDataAvailable( - request, context, inputStream, offset, count); - } catch (x) { - console.debug(x, x.lineNumber, x.fileName, "In this case, charset is"); - } - }, - - onStartRequest: function(request, context) { - this.streamLoader.setOriginalListener(this.originalListener); - this.streamLoader.loader.onStartRequest(request, context); - this.originalListener.onStartRequest(request, context); - }, - - onStopRequest: function(request, context, statusCode) { - try { - this.streamLoader.loader.onStopRequest(request, context, statusCode); - } catch (e) { - console.debug('error in onStopRequest', e, e.lineNumber); - } - }, - - QueryInterface: function (aIID) { - if (aIID.equals(Ci.nsIStreamListener) || - aIID.equals(Ci.nsISupports) - ) { - return this; - } - throw Cr.NS_NOINTERFACE; - }, -}; - -exports.startHttpObserver = function() { - try { - observerService.addObserver(httpRequestObserver, - "http-on-examine-response", false); - observerService.addObserver(httpRequestObserver, - "http-on-examine-cached-response", false); - observerService.addObserver(httpRequestObserver, - "http-on-examine-merged-response", false); - console.debug('turned on http observer'); - } catch (e) { - console.debug(e); - } -}; - -exports.startHttpObserver(); - -/* remove observer */ -exports.removeHttpObserver = function() { - try { - observerService.removeObserver(httpRequestObserver, - "http-on-examine-response"); - observerService.removeObserver(httpRequestObserver, - "http-on-examine-cached-response"); - observerService.removeObserver(httpRequestObserver, - "http-on-examine-merged-response"); - console.debug('turned off http observer'); - } catch (e) { - console.debug(e); - } -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/process_response.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/process_response.js @@ -1,420 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * This module checks http responses by mime type and returns a - * modified response. - */ - -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); - -var jsChecker = require("js_checker/js_checker"); - -const types = require("js_checker/constant_types"); -var checkTypes = types.checkTypes; - -// check if scripts embedded dynamically have a jsWebLabel entry indexed by referrer. -var jsWebLabelEntries = require("html_script_finder/web_labels/js_web_labels").jsWebLabelEntries; - -var htmlParser = require("html_script_finder/html_parser"); - -var removedScripts = require("script_entries/removed_scripts").removedScripts; -var allowedRef = require('http_observer/allowed_referrers').allowedReferrers; - -var acceptedScripts = require("script_entries/accepted_scripts").acceptedScripts; - -// used to display info when a url is whitelisted. -var dryRunScripts = require("script_entries/dryrun_scripts").dryRunScripts; - -// node.js url module. Makes it easier to resolve -// urls in that datauri loaded dom -var urlHandler = require("url_handler/url_handler"); -var isDryRun = require("addon_management/prefchange").isDryRun; - -var jsMimeTypeRe = /.*(javascript|ecmascript).*/i; -var htmlMimeTypeRe = /.*(xhtml\+xml|html|multipart\/x-mixed-replace).*/i; - - -var processResponseObject = { - data: null, - myParser: null, - url: null, - scriptFinder: null, - jsCheckString: null, - referrer: null, - contentType: null, - resInfo: null, - listener: null, - req: null, - - /** - * starts the handling of a new response. - */ - init: function (listener, resInfo) { - this.resInfo = resInfo; - this.req = resInfo.request; - /* needed for this.req.referrer */ - this.req.QueryInterface(Ci.nsIHttpChannel); - this.listener = listener; - this.setData(); - this.setContentType(); - this.setUrls(); - }, - - /** - * Gather the data gathered from onDataAvailable. - */ - setData: function () { - this.data = this.resInfo.receivedData; - //console.debug("\n\nDump of whole data:\n\n", this.data, "\n\n end of dump"); - // Prevents the http response body from being empty, - // which would throw an error. - if (this.data == '' || this.data == undefined) { - this.data = " "; - } - }, - - /** - * Set a standardized lowercase mime type. - */ - setContentType: function() { - if (this.req.contentType != undefined) { - this.contentType = String(this.req.contentType).toLowerCase(); - } - }, - - /** - * setUrls - * Set the current URL of the response, and - * set referrer if applicable. - */ - setUrls: function() { - - if (this.req.URI != undefined) { - this.fragment = urlHandler.getFragment(this.req.URI.spec); - console.debug('fragment is', this.fragment); - this.url = urlHandler.removeFragment(this.req.URI.spec); - } - if (this.req.referrer != undefined) { - this.referrerFragment = urlHandler.getFragment(this.req.referrer.spec); - this.referrer = urlHandler.removeFragment(this.req.referrer.spec); - } - }, - - /** - * processHTML - * Modifies a string of html - */ - processHTML: function() { - var charset = this.req.contentCharset, myParser; - - if (this.req.contentCharset != undefined && this.req.contentCharset != "") { - charset = this.req.contentCharset; - } else { - charset = ""; - } - acceptedScripts.clearScripts(this.req.URI.spec); - removedScripts.clearScripts(this.req.URI.spec); - dryRunScripts.clearScripts(this.req.URI.spec); - - console.debug('charset is', charset); - console.debug( - 'responseStatus for', this.url, 'is', this.req.responseStatus); - - // send data to htmlParser, and pass on modified data to - // originalListener. - - myParser = htmlParser.htmlParser().parse( - this.data, - charset, - this.contentType, - this.url, - this.fragment, - this.req.responseStatus, - this.htmlParseCallback.bind(this)); - }, - - /** - * - * htmlParseCallback - * - * Passed on the callback result to - * the originalListener. - * - */ - htmlParseCallback: function(result) { - - var len = result.length; - - try { - - this.listener.onDataAvailable( - this.req, - this.resInfo.context, - result.newInputStream(0), 0, len); - - - } catch (e) { - - this.req.cancel(this.req.NS_BINDING_ABORTED); - - } - - this.listener.onStopRequest( - this.req, - this.resInfo.context, this.resInfo.statusCode); - - }, - - /** - * processJS - * Process and modify a string of JavaScript. - */ - processJS: function() { - var checker, check, jsCheckString, - that = this; - - try { - // make sure script isn't already listed as free - // in a JS web labels table. - if (this.checkJsWebLabelsForScript()) { - // this is free. we are done. - this.jsListenerCallback(); - return; - } - - // analyze javascript in response. - checker = jsChecker.jsChecker(); - check = checker.searchJs(this.data, function () { - //console.debug("Has been analyzing", that.data); - that.processJsCallback(checker); - }, that.url); - - } catch(e) { - - // any error is considered nontrivial. - console.debug('js error in js app, removing script', e); - console.debug("error", e, e.lineNumber); - // modify data that will be sent to the browser. - this.data = '// LibreJS: Script contents were removed when it was loaded from a page, because another script attempted to load this one dynamically. Please place your cursor in the url bar and press the enter key to see the source.'; - this.jsListenerCallback(); - } - - }, - - /** - * checkJsWebLabelsForScript - * - * check whether script that's been received has an entry - * in a js web labels table (lookup referrer.) - * - */ - checkJsWebLabelsForScript: function () { - - console.debug('checking script', this.url); - console.debug('current list is', JSON.stringify(jsWebLabelEntries)); - if (jsWebLabelEntries[this.referrer] != undefined) { - - var scriptList = jsWebLabelEntries[this.referrer], - i = 0, - len = scriptList.length; - - for (; i < len; i++) { - - if (scriptList[i].fileUrl === this.url && - scriptList[i].free === true) { - - console.debug(this.url, "is free and dynamic!"); - - var scriptObj = { - inline: false, - url: this.url, - contents: this.url, - reason: "This script is free (see JS Web Labels page for detail)" - }; - - acceptedScripts.addAScript( - this.req.referrer.spec, scriptObj, "Script is free"); - - return true; - - } - } - } - }, - - processJsCallback: function(checker) { - try { - var scriptObj; - - var jsCheckString = checker.parseTree.freeTrivialCheck; - console.debug("analyzing js callback for", this.url); - // for testing only. - //var jsCheckString = {'type': checkTypes.FREE_SINGLE_ITEM }; - console.debug('jscheckstring is', jsCheckString.type); - - if (jsCheckString.type === checkTypes.NONTRIVIAL) { - if (!allowedRef.urlInAllowedReferrers(this.req.referrer.spec)) { - //if (true) { - console.debug( - "url", - this.url, - " is found nontrivial", - "with reason", - jsCheckString.reason); - scriptObj = { - inline: false, - contents: '', - removalReason: 'nontrivial', - reason: jsCheckString.reason, - url: this.url, - hash: checker.hash - }; - removedScripts.addAScript(this.req.referrer.spec, scriptObj); - - // modify data that will be sent to the browser. - this.data = '// LibreJS: Script contents were removed when it was loaded from a page, because another script attempted to load this one dynamically and its contents appear to be nonfree/nontrivial. Please hit enter in the location bar to see the actual source.'; - } else { - console.debug("writing to dry run", this.url); - scriptObj = { - inline:false, - contents: '', - removalReason: 'nontrivial', - reason: jsCheckString.reason, - url: this.url, - hash:checker.hash - }; - dryRunScripts.addAScript(this.req.referrer.spec, scriptObj); - } - - this.jsListenerCallback(); - - } else if (jsCheckString.type === checkTypes.FREE || - jsCheckString.type === checkTypes.FREE_SINGLE_ITEM || - jsCheckString.type === checkTypes.TRIVIAL || - jsCheckString.type === checkTypes.TRIVIAL_DEFINES_FUNCTION || - jsCheckString.type === checkTypes.WHITELISTED) { - console.debug( - "found a free script for", - this.url, - this.req.referrer.spec, - jsCheckString.reason); - console.debug('found a free script', this.req.referrer.spec); - - scriptObj = {inline: false, - contents: '', - reason: jsCheckString.reason, - url: this.url, - hash:checker.hash}; - - acceptedScripts.addAScript(this.req.referrer.spec, scriptObj); - this.jsListenerCallback(); - } - - //var end = Date.now(); - console.debug('exec time', this.url, ' -- ', end - start); - } catch (x) { - console.debug('error', x); - } - }, - - /** - * ProcessAllTypes - * Calls processHTML or JS if it finds an appropriate content - * type. For everything else it just passes on the data to the - * original listener. - */ - processAllTypes: function() { - // toggle xlibrejs if X-LibreJS is set. - - // process HTML - if ((htmlMimeTypeRe.test(this.contentType) || - this.req.contentType === undefined)) { - this.processHTML(); - return; - } - - else { - // process external JS files that are called from another - // file (and hence have a referrer). - - if (this.referrer != undefined && - jsMimeTypeRe.test(this.contentType) && - !(acceptedScripts.isFound(this.referrer, { - inline: false, contents: this.url})) && - !(acceptedScripts.isFound(this.referrer, { - inline:false, contents:this.req.originalURI.spec}))) { - - // console.debug('process js triggered for', this.url); - this.processJS(); - - } else { - this.jsListenerCallback(); - } - - } - - }, - - jsListenerCallback: function () { - - var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - - if (typeof this.req.contentCharset !== 'undefined' && - this.req.contentCharset !== '' && - this.req.contentCharset !== null - ) { - converter.charset = this.req.contentCharset; - } else { - converter.charset = "UTF-8"; - } - - var stream = converter.convertToInputStream(this.data); - - try { - this.listener.onDataAvailable( - this.req, - this.resInfo.context, - stream, - 0, stream.available()); - } catch (e) { - this.req.cancel(this.req.NS_BINDING_ABORTED); - } - - this.listener.onStopRequest( - this.req, - this.resInfo.context, - this.resInfo.statusCode); - - } - - -}; - -// creates an instance of processResponseObject. -exports.ProcessResponse = function (listener, resInfo) { - console.debug('triggered'); - var procResponse = Object.create(processResponseObject); - procResponse.init(listener, resInfo); - return procResponse; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/stream_loader.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/http_observer/stream_loader.js @@ -1,160 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); - -const processResponse = require('http_observer/process_response'); -const CHARSETS = [ - '866', 'ansi_x3.4-1968', 'arabic', 'ascii', 'asmo-708', 'big5', - 'big5-hkscs', 'chinese', 'cn-big5', 'cp1250', 'cp1251', 'cp1252', - 'cp1253', 'cp1254', 'cp1255', 'cp1256', 'cp1257', 'cp1258', - 'cp819', 'cp866', 'csbig5', 'cseuckr', 'cseucpkdfmtjapanese', - 'csgb2312', 'csibm866', 'csiso2022jp', 'csiso2022kr', 'csiso58gb231280', - 'csiso88596e', 'csiso88596i', 'csiso88598e', 'csiso88598i', 'csisolatin1', - 'csisolatin2', 'csisolatin3', 'csisolatin4', 'csisolatin5', 'csisolatin6', - 'csisolatin9', 'csisolatinarabic', 'csisolatincyrillic', - 'csisolatingreek', 'csisolatinhebrew', 'cskoi8r', 'csksc56011987', - 'csmacintosh', 'csshiftjis', 'cyrillic', 'dos-874', 'ecma-114', - 'ecma-118', 'elot_928', 'euc-jp', 'euc-kr', 'gb18030', 'gb2312', - 'gb_2312', 'gb_2312-80', 'gbk', 'greek', 'greek8', 'hebrew', - 'hz-gb-2312', 'ibm819', 'ibm866', 'iso-2022-cn', 'iso-2022-cn-ext', - 'iso-2022-jp', 'iso-2022-kr', 'iso88591', 'iso_8859-1', 'iso-8859-1', - 'iso8859-1', 'iso885910', 'iso-8859-10', 'iso8859-10', 'iso885911', - 'iso-8859-11', 'iso8859-11', 'iso_8859-1:1987', 'iso885913', 'iso-8859-13', - 'iso8859-13', 'iso885914', 'iso-8859-14', 'iso8859-14', 'iso885915', - 'iso-8859-15', 'iso8859-15', 'iso-8859-16', 'iso88592', 'iso_8859-2', - 'iso-8859-2', 'iso8859-2', 'iso_8859-2:1987', 'iso88593', 'iso_8859-3', - 'iso-8859-3', 'iso8859-3', 'iso_8859-3:1988', 'iso88594', 'iso_8859-4', - 'iso-8859-4', 'iso8859-4', 'iso_8859-4:1988', 'iso88595', 'iso_8859-5', - 'iso-8859-5', 'iso_8859-5:1988', 'iso88596', 'iso_8859-6', 'iso-8859-6', - 'iso8859-6', 'iso_8859-6:1987', 'iso-8859-6-e', 'iso-8859-6-i', 'iso88597', - 'iso_8859-7', 'iso-8859-7', 'iso8859-7', 'iso_8859-7:1987', 'iso88598', - 'iso_8859-8', 'iso-8859-8', 'iso8859-8', 'iso_8859-8:1988', 'iso-8859-8-e', - 'iso-8859-8i', 'iso-8859-8-i', 'iso88599', 'iso_8859-9', 'iso-8859-9', - 'iso8859-9', 'iso_8859-9:1989', 'iso-ir-100', 'iso-ir-101', 'iso-ir-109', - 'iso-ir-110', 'iso-ir-126', 'iso-ir-127', 'iso-ir-138', 'iso-ir-144', - 'iso-ir-148', 'iso-ir-149', 'iso-ir-157', 'iso-ir-58', 'koi', 'koi8', - 'koi8_r', 'koi8-r', 'koi8-u', 'korean', 'ksc5601', 'ksc_5601', - 'ks_c_5601-1987', 'ks_c_5601-1989', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', - 'l9', 'latin1', 'latin2', 'latin3', 'latin4', 'latin5', 'latin6', 'latin9', - 'logical', 'mac', 'macintosh', 'ms_kanji', 'replacement', 'shift_jis', - 'shift-jis', 'sjis', 'sun_eu_greek', 'tis-620', 'unicode-1-1-utf-8', - 'us-ascii', 'utf-16', 'utf-16be', 'utf-16le', 'utf8', 'utf-8', 'visual', - 'windows-1250', 'windows-1251', 'windows-1252', 'windows-1253', - 'windows-1254', 'windows-1255', 'windows-1256', 'windows-1257', - 'windows-1258', 'windows-31j', 'windows-874', 'windows-949', 'x-cp1250', - 'x-cp1251', 'x-cp1252', 'x-cp1253', 'x-cp1254', 'x-cp1255', 'x-cp1256', - 'x-cp1257', 'x-cp1258', 'x-euc-jp', 'x-gbk', 'x-mac-cyrillic', - 'x-mac-roman', 'x-mac-ukrainian', 'x-sjis', 'x-user-defined', 'x-x-big5' -]; - -var StreamLoader = function() { - this.loader = null; - this.listener = null; - this.originalListener = null; -}; - -StreamLoader.prototype.setOriginalListener = function(listener) { - this.originalListener = listener; -}; - -StreamLoader.prototype.init = function() { - try { - var that = this; - this.listener = new StreamListener(); - - this.listener.callback = function (loader, context, status, data) { - //console.debug("here is the data", data); - var responseInfo = {'request': loader.channel, - 'context': context, - 'statusCode': status, - 'receivedData': data}; - var responseHandler = processResponse.ProcessResponse(that.originalListener, responseInfo); - responseHandler.processAllTypes(); - - that.destroy(); - }; - - this.loader = Cc["@mozilla.org/network/unichar-stream-loader;1"]. - createInstance(Ci.nsIUnicharStreamLoader); - - this.loader.init(this.listener); - } catch (e) { - console.debug(e); - } -}; - -StreamLoader.prototype.destroy = function () { - this.loader = null; - this.listener = null; -}; - -var getRegexForContentType = function (contentType) { - if (/xhtml/i.test(contentType)) { - return /<\?[^>]*?encoding=(?:["']*)([^"'\s\?>]+)(?:["']*)/i; - } - - // return the regular html regexp for anything else. - return /<meta[^>]*?charset=(?:["']*)([^"'\s>]+)(?:["']*)/i; -}; - -var StreamListener = function() {}; - -StreamListener.prototype.QueryInterface = function listener_qi(iid) { - if (iid.equals(Ci.nsISupports) || - iid.equals(Ci.nsIUnicharStreamLoaderObserver)) { - return this; - } - throw Cr.NS_ERROR_NO_INTERFACE; -}; - -StreamListener.prototype.onStreamComplete = function onStreamComplete( - loader, context, status, data) { - this.callback(loader, context, status, data); -}; - -StreamListener.prototype.onDetermineCharset = function onDetermineCharset( - loader, context, data) { - var match, regex; - if (loader.channel.contentCharset !== undefined && - loader.channel.contentCharset !== "" - ) { - return loader.channel.contentCharset; - } else { - match = getRegexForContentType(loader.channel.contentType).exec(data); - if (typeof match !== 'undefined' && - match !== null && - match.length > 0 && - CHARSETS.indexOf(match[1].toLowerCase()) >= 0 - ) { - loader.channel.contentCharset = match[1]; - return match[1]; - } else { - return "UTF-8"; - } - } -}; - -exports.streamLoader = function () { - var l = new StreamLoader(); - l.init(); - return l; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/free_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/free_checker.js @@ -1,233 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var licenses = require('js_checker/license_definitions'); -var simpleStorage = require("sdk/simple-storage"); -const LAZY = licenses.types.LAZY; -var licenseRegex = []; -const END_OF_SCRIPT = require('html_script_finder/bug_fix').END_OF_SCRIPT; -const types = require("js_checker/constant_types"); - -const token = types.token; - -var patternUtils = require('js_checker/pattern_utils').patternUtils; - -var licStartLicEndRe = /@licstartThefollowingistheentirelicensenoticefortheJavaScriptcodeinthis(?:page|file)(.*)?@licendTheaboveistheentirelicensenoticefortheJavaScriptcodeinthis(?:page|file)/mi; -var licenseMagnet = /.*@license ?(magnet\:\?xt=urn\:btih\:[0-9A-Za-z]+).*/; -var licenseEndMagnet = /.*@license-end.*/i; -exports.freeCheck = { - initLicenses: function (licenses) { - for (var item in licenses) { - this.stripLicenseToRegexp(licenses[item]); - } - }, - - /** - * stripLicenseToRegexp - * - * Removes all non-alphanumeric characters except for the - * special tokens, and replace the text values that are - * hardcoded in license_definitions.js - * - */ - stripLicenseToRegexp: function (license) { - var i = 0, - max = license.licenseFragments.length, - item; - - for (; i < max; i++) { - item = license.licenseFragments[i]; - item.regex = patternUtils.removeNonalpha(item.text); - - if (license.licenseFragments[i].type === LAZY) { - - // do not permit words before. Since "Not" could be added - // and make it nonfree. e.g.: Not licensed under the GPLv3. - item.regex = '^(?!.*not).*' + item.regex; - - } - - item.regex = new RegExp( - patternUtils.replaceTokens(item.regex), 'i'); - } - - return license; - }, - - /** - * checkNodeFreeLicense - * - * Check if the node mentions a free license - * in one of its comments. - * - */ - checkNodeFreeLicense: function (n, queue) { - var strippedComment, - magnetLink, - comment = this.getComment(n), - list = licenses.licenses, - i, j, - max, - regex, - frag, - matchLicStart, - matchMagnet, - license, - isMagnetValid = false; - - if (n.counter === 2 && - n.parent != undefined && - n.parent.type === token.SCRIPT && - comment != undefined && - comment != " " - ) { - strippedComment = patternUtils.removeNonalpha(comment); - matchLicStart = strippedComment.match(licStartLicEndRe); - console.debug("matchMagnet is", matchMagnet); - if (matchLicStart) { - strippedComment = matchLicStart[1]; - for (license in list) { - frag = list[license].licenseFragments; - max = list[license].licenseFragments.length; - for (i = 0; i < max; i++) { - if (frag[i].regex.test(strippedComment)) { - return { - licenseName: list[license].licenseName, - type: types.checkTypes.FREE - }; - - } - } - } - } - // check for @license -- @license-end notation. - return this.matchMagnet(comment, queue); - } - }, - - /** - * matchMagnet - * Attempts to find valid @license [magnet] - * and @license-end notation. - */ - matchMagnet: function (comment, queue) { - let matchMagnet = comment.match(licenseMagnet); - if (matchMagnet) { - let magnetLinkRe = new RegExp( - matchMagnet[1].replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") - ); - let list = licenses.licenses; - let queue_end = queue.length; - - for (var license in list) { - frag = list[license].canonicalUrl; - console.debug("frag is ", frag); - if (frag != undefined) { - max = list[license].canonicalUrl.length; - console.debug("max is", max); - for (i = 0;i < max; i++) { - console.debug("current frag is", frag[i]); - if (frag[i].match(magnetLinkRe)) { - for (let i = 0; i < queue_end; i++) { - console.debug(queue[i]); - let n = queue[i]; - comment = this.getComment(n); - if (comment != undefined && - comment.match(licenseEndMagnet) && - this.checkIsLastNode(n) - ) { - // found a closing match. Just accept this script. - return { - licenseName: list[license].licenseName, - type: types.checkTypes.FREE_SINGLE_ITEM - }; - } - } - } - } - } - } - } - return; - }, - - /** - * checkIsLastJsNode. - * returns true if n is the last node. - * Or if nodes before it are only comments etc (not valid code.) - * A special LibreJS node is appended at the end of a script tree to - * check if this is the last (and also for narcissus to keep the last comment - * in the tree.) - * TODO: Refactor LibreJS so that END nodes can have a comment. - */ - checkIsLastNode: function (n) { - // first check if the comment is part of the very last statement. - if (n.value == "this" && n.next == undefined) { - // just make sure the last node is indeed our harmless bit of - // js. - if (n.tokenizer) { - let source = n.tokenizer.source; - let substring = source.substr(n.start, n.end+23); - if (substring == END_OF_SCRIPT) { - return true; - } - else { - console.debug("substring is ", substring); - return false; - } - } - console.debug("Hurra! This is the end of our script"); - return true; - } - - // isn't our last node. - return false; - }, - - /** - * getComment - * - * Grab the comment(s) from the node. Concatenates - * multiple comments. - * - */ - getComment: function (n) { - var i = 0, length, comment = ""; - - if (n.blockComments == undefined || n.blockComments == " ") { - return; - } - - length = n.blockComments.length; - if (length > 0) { - for (; i < length; i++) { - comment += n.blockComments[i]; - } - } - if (comment == "") { - return; - } - return comment; - } -}; - -exports.freeCheck.initLicenses(licenses.licenses); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/js_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/js_checker.js @@ -1,561 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * Copyright (C) 2015 Ruben Rodriguez - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var {Cc, Ci, Cu, Cm, Cr} = require("chrome"); - -var narcissusWorker = require("parser/narcissus_worker") - .narcissusWorker; - -const nonTrivialModule = require("js_checker/nontrivial_checker"); -const freeChecker = require("js_checker/free_checker"); -const relationChecker = require("js_checker/relation_checker"); -const types = require("js_checker/constant_types"); - -const scriptsCached = require("script_entries/scripts_cache").scriptsCached; -var isDryRun = require("addon_management/prefchange").isDryRun; - -var checkTypes = types.checkTypes; - -const token = types.token; - -// for setTimeout. -const timer = require("sdk/timers"); - -var callbackMap = {}; - -/** - * - * Pairs a hash with a given callback - * method from an object. - * - */ -var setHashCallback = function(hash, callback, notification) { - console.debug('setHashCallback', hash); - if (hash in callbackMap && isDryRun()) { - // workaround for issue with dryrun after checking box. - // do nothing. - callbackMap[hash] = callback; - } else if (hash in callbackMap) { - console.debug("callback", callbackMap[hash]); - if (notification && typeof notification.close === 'function') { - notification.close(); - } - throw Error("already being checked."); - } else { - console.debug('setting callbackMap for', hash, 'to', callback); - callbackMap[hash] = callback; - } - console.debug("callback is type: ", callback.constructor); - //callbackMap[hash] = callback; -}; - -var removeHashCallback = function(hash) { - if (hash in callbackMap) { - delete callbackMap[hash]; - } -}; - -/** - * find callback and return result (parse tree). - * - */ -exports.callbackHashResult = function(hash, result) { - console.debug('typeof callbackMap function:', typeof callbackMap[hash]); - console.debug('for hash', hash); - try { - callbackMap[hash](result, hash); - } catch (x) { - console.debug('error in jsChecker', x, 'hash:', hash); - // return tree as false. - console.debug("Error with", x); - if (typeof callbackMap[hash] === 'function') { - callbackMap[hash](false, hash); - } else { - console.debug('callbackHashResult Error', x); - } - } - // remove callback after it's been called. - console.debug('JsChecker.callbackHashResult: calling removeHashCallback'); - removeHashCallback(hash); -}; - -var JsChecker = function() { - this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this.nonTrivialChecker = null; - this.freeToken = false; - this.nontrivialness = false; - this.parseTree = null; - this.relationChecker = null; - this.jsCode = null; - this.resultReady = null; - this.notification = null; - this.walkTreeCancelled = false; - this.shortText = null; - this.hash = null; - this.queue = null; // will contain the nodes of the script. -}; - -/** - * isFreeLicensed - * - * This function returns true if the input script is licensed under - * a free license. Otherwise, it returns false. - */ -JsChecker.prototype.isFreeLicensed = function(script) { - var magnets = '(' + - 'magnet:\\?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt|' + - 'magnet:\\?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt|' + - 'magnet:\\?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt|' + - 'magnet:\\?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt|' + - 'magnet:\\?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt|' + - 'magnet:\\?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt|' + - 'magnet:\\?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt|' + - 'magnet:\\?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt|' + - 'magnet:\\?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt|' + - 'magnet:\\?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt|' + - 'magnet:\\?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt|' + - 'magnet:\\?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt|' + - 'magnet:\\?xt=urn:btih:87f119ba0b429ba17a44b4bffcab33165ebdacc0&dn=freebsd.txt|' + - 'magnet:\\?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt|' + - 'magnet:\\?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt|' + - 'magnet:\\?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt' + - ')'; - - // Remove licensed parts - var re = new RegExp( - '@license +' + magnets + '.*([\n\r].*?)*@license-end', 'g'); - script = script.replace(re, ''); - - // Remove comments and empty lines - re = new RegExp('\/\/.*|/\\*.*?\\*/|^\s*[\n\r]*', 'gm'); - - script = script.replace(re, ""); - - // If only spaces remain, the file has a free license - return (script.match(/\S/) === null); -}; - -/** - * searchJs - * - * Takes in some javascript code (as string). - * Uses Narcissus parser to build an abstract syntax tree. - * Checks for trivialness. - * - */ -JsChecker.prototype.searchJs = function(jsCode, resultReady, url) { - var that = this; - var bugfix = require('html_script_finder/bug_fix').narcissusBugFixLibreJS; - console.debug('JsChecker.searchJs for script url:', url); - this.url = url; - this.resultReady = resultReady; - this.jsCode = jsCode; - this.shortText = jsCode.replace(bugfix, '').substring(0,100); - this.notification = require("ui/notification") - .createNotification(this.shortText).notification; - - var verbatimCode = this.jsCode.replace(bugfix, ''); - this.hash = scriptsCached.getHash(verbatimCode); - var isCached = scriptsCached.isCached(verbatimCode, this.hash); - if (isCached) { - console.debug("We have it cached indeed!"); - // there is an existing entry for this exact copy - // of script text. - console.debug('this script result is cached', this.hash, - isCached.result.type); - console.debug("Return right away"); - // we are not generating a parse tree. - this.parseTree = {}; - // fake the result is from parse tree. - this.parseTree.freeTrivialCheck = isCached.result; - - this.relationChecker = isCached.relationChecker; - // leave without doing parsing/analysis part. - this.resultReady(); - this.removeNotification(); - return; - } - - console.debug('url is not cached:', url); - - try { - // no cache, continue. - this.relationChecker = relationChecker.relationChecker(); - this.freeToken = types.emptyTypeObj(); - this.nontrivialness = types.emptyTypeObj(); - - // use this.hash to keep track of comments made by the nontrivial - // checker code about why/how the code is found to be nontrivial. - this.nonTrivialChecker = - nonTrivialModule.nonTrivialChecker(this.hash); - - // register callback and hash. So that result - // can be passed. - setHashCallback( - this.hash, this.handleTree.bind(this), this.notification); - - // parse using ChromeWorker. - console.debug( - 'JsChecker.searchJs(): starting narcissusWorker.parse()'); - narcissusWorker.parse(this.jsCode, this.hash); - } catch (x) { - console.debug('error', x); - this.handleTree(false, x); - this.removeNotification(); - } -}; - -JsChecker.prototype.handleTree = function(tree, errorMessage) { - var that = this; - - if (tree == false || tree == undefined) { - // error parsing tree. Just return nonfree nontrivial. - this.parseTree = {}; - this.parseTree.freeTrivialCheck = types.nontrivialWithComment( - 'error parsing: ' + errorMessage); - - // cache result with hash of script for future checks. - scriptsCached.addEntry(this.jsCode, this.parseTree.freeTrivialCheck, - this.relationChecker, true, this.url); - this.resultReady(); - } else { - try { - // no need to keep parseTree in property - this.parseTree = {}; //tree; - //console.debug(tree); - this.walkTree(tree); - } catch (x) { - console.debug(x, x.lineNumber, x.fileName); - } - } -}; - -/** - * getCheckerResult - * - * Callback to Assign result from walkTree to property. - * reset parse tree. create cache entry. - * - */ -JsChecker.prototype.getCheckerResult = function(result) { - // done with parse tree. Get rid of it. - this.parseTree = {}; - this.removeNotification(); - - this.parseTree.nonTrivialChecker = this.nonTrivialChecker; - - // actual result stored here. hack since we used parseTree before. - this.parseTree.freeTrivialCheck = result; - - // cache result with hash of script for future checks. - scriptsCached.addEntry(this.jsCode, this.parseTree.freeTrivialCheck, - this.relationChecker, true, this.url); - - this.resultReady(); -}; - -/** - * trivialCheck - * - * Runs nodes through a series of conditional statements - * to find out whether it is trivial or not. - * - * @param {object} n. The current node being studied. - * @param {string} t. The type of node being studied - * (initializer, functionbody, try block, ...) - * - */ -JsChecker.prototype.trivialCheck = function(n) { - return this.nonTrivialChecker.checkNontrivial(n); -}; - -/** - * freeCheck - * - * Check if comments above current node could be a free licence. - * If it is, then the script will be flagged as free. - * - * @param {object} n. The current node being studied. - * (initializer, functionbody, try block, ...) - * - */ -JsChecker.prototype.freeCheck = function(n, ntype) { - var check = freeChecker.freeCheck.checkNodeFreeLicense(n, this.queue); - return check; -}; - -/** - * walkTree - * - * An iterative functionwalking the parse tree generated by - * Narcissus. - * - * @param {object} node. The original node. - * - */ -JsChecker.prototype.walkTree = function(node) { - var queue = [node]; - var i, - len, - n, counter = 0, - result, - processQueue, - that = this; - - this.queue = queue; // set as property. - - // set top node as visited. - node.visited = true; - - /** - * functionwalking the tree for a given - * amount of time, before calling itself again. - */ - processQueue = function() { - var nodeResult, end; - - // record start time of functionexecution. - var start = Date.now(); - - if (that.walkTreeCancelled) { - // tree walking already completed. - return; - } - - while (queue.length) { - n = queue.shift(); - n.counter = counter++; - console.debug("Under review", n.type); - if (n.children != undefined) { - // fetch all the children. - len = n.children.length; - for (i = 0; i < len; i++) { - if (n.children[i] != undefined && - n.children[i].visited == undefined - ) { - // figure out siblings. - if (i > 0) { - n.children[i].previous = n.children[i-1]; - } - - if (i < len) { - n.children[i].next = n.children[i+1]; - } - // set parent property. - n.children[i].parent = n; - n.children[i].visited = true; - queue.push(n.children[i]); - } - } - } - - if (n.type != undefined) { - // fetch all properties that may have nodes. - for (var item in n) { - if (item != 'tokenizer' && - item != 'children' && - item != 'length' && - n[item] != null && - typeof n[item] === 'object' && - n[item].type != undefined && - n[item].visited == undefined - ) { - n[item].visited = true; - // set parent property - n[item].parent = n; - queue.push(n[item]); - } - } - } - - that.checkNode(n); - - if (that.freeToken.type === checkTypes.FREE || - that.freeToken.type === checkTypes.FREE_SINGLE_ITEM - ) { - // nothing more to look for. We are done. - that.walkTreeComplete(that.freeToken); - return; - } else if (that.nontrivialness.type === checkTypes.NONTRIVIAL) { - // nontrivial - // we are done. - that.walkTreeComplete(that.nontrivialness); - return; - } - // call processQueue again if needed. - end = Date.now(); - - if (queue.length) { - // there are more nodes in the queue. - - if ((end - start) > 30) { - - // been running more than 20ms, pause - // for 10 ms before calling processQueue - // again. - timer.setTimeout(processQueue, 8); - return; - } - } else { - // we are done. - that.removeNotification(); - that.walkTreeComplete(); - return; - } - } - }; - - if (node.type === token.SCRIPT) { - // this is the global scope. - node.global = true; - node.parent = null; - - this.relationChecker.storeGlobalDeclarations(node); - - queue.push(node); - processQueue(); - } -}; - -/** - * set walk tree cancelled bool as true. - * the walk tree method won't run after the variable - * is set to true. - */ -JsChecker.prototype.cancelWalkTree = function() { - // prevent any further work on node codes. - this.walkTreeCancelled = true; -}; - -/** - * walkTreeComplete - * - * Trigger when the walkTree has been completed or - * when it has been cut short. - * - */ -JsChecker.prototype.walkTreeComplete = function(result) { - var that = this; - this.removeNotification(); - - if (this.walkTreeCancelled) { - // we already triggered complete. - return; - } - - // we set the token to cancel further processing. - this.cancelWalkTree(); - - if (result != undefined) { - // walkTree was returned faster, use it instead. - this.getCheckerResult(result); - - // we are done. - return; - } - - // if all code was fully analyzed. - if (this.nontrivialness.type === checkTypes.NONTRIVIAL) { - this.getCheckerResult(this.nontrivialness); - } else if (this.freeToken.type === checkTypes.FREE) { - // this is free and may or may not define functions, we don't care. - this.getCheckerResult(this.freeToken); - } else if (this.nontrivialness.type === - checkTypes.TRIVIAL_DEFINES_FUNCTION) { - // trivial scripts should become nontrivial if an external script. - // it may or may not be trivial if inline. - this.getCheckerResult(this.nontrivialness); - } else { - // found no nontrivial constructs or free license, so it's - // trivial. - - this.getCheckerResult( - types.trivialFuncWithComment("This script is trivial")); - } -}; - - -/** - * checkNode - * - * checks a single node. - * - */ -JsChecker.prototype.checkNode = function(n) { - var sub; - var fc = this.freeCheck(n); - var tc = this.trivialCheck(n); - - var nodeResult; - - // check if identifier may be window property (assumption). - this.relationChecker.checkIdentifierIsWindowProperty(n); - - /*if (fc) { - console.debug("FC is", fc, "type is", fc.type); - }*/ - if (fc && fc.type == checkTypes.FREE) { - // this is free! - // freeToken is persistent across nodes analyzed and valid - // for an entire script. - this.freeToken = types.freeWithComment( - "Script appears to be free under the following license: " + - fc.licenseName); - return; - } else if (fc && fc.type == checkTypes.FREE_SINGLE_ITEM) { - console.debug("free single item"); - this.freeToken = types.singleFreeWithComment( - "Script appears to be free under the following license: " + - fc.licenseName); - return; - } - - if (tc) { - if (tc.type === checkTypes.NONTRIVIAL) { - // nontrivial_global is deprecated - this.nontrivialness = tc; - return; - } else if (tc.type === checkTypes.TRIVIAL_DEFINES_FUNCTION) { - this.nontrivialness = tc; - return; - } - } -}; - -JsChecker.prototype.removeNotification = function() { - console.debug('JsChecker.removeNotification()'); - if (this.notification && - typeof this.notification.close === 'function' - ) { - console.debug('removing', this.shortText); - // remove notification early on. - this.notification.close(); - this.notification = null; - } -}; - -exports.jsChecker = function() { - return new JsChecker(); -}; - -exports.removeHashCallback = removeHashCallback; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/license_definitions.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/license_definitions.js @@ -1,284 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ -exports.types = { - SHORT: 'short', - LAZY: 'lazy', - FULL: 'full' -}; - -var type = exports.types; - -/** - * List of all the licenses. - * Currently only short substrings are used with regex. - * - * The licenses are indexed by their "Identifier", which, when possible, - * corresponds to their identifier as specified by SPDX here: - * https://spdx.org/licenses/ - */ -exports.licenses = { - 'CC0-1.0': { - licenseName: 'Creative Commons CC0 1.0 Universal', - identifier: 'CC0-1.0', - canonicalUrl: [ - 'http://creativecommons.org/publicdomain/zero/1.0/legalcode', - 'magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt' - ], - licenseFragments: [] - }, - - - 'GPL-2.0': { - licenseName: 'GNU General Public License (GPL) version 2', - identifier: 'GPL-2.0', - canonicalUrl: [ - 'http://www.gnu.org/licenses/gpl-2.0.html', - 'magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt' - ], - licenseFragments: [{text: "<THISPROGRAM> is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.", type: type.SHORT}, - {text:"Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the \"GPL\"), or the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL.", type: type.SHORT}] - }, - - 'GPL-3.0': { - licenseName: 'GNU General Public License (GPL) version 3', - identifier: 'GPL-3.0', - canonicalUrl: [ - 'http://www.gnu.org/licenses/gpl-3.0.html', - 'magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt' - ], - licenseFragments: [ - {text: "The JavaScript code in this page is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License (GNU GPL) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The code is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. As additional permission under GNU GPL version 3 section 7, you may distribute non-source (e.g., minimized or compacted) forms of that code without the copy of the GNU GPL normally required by section 4, provided you include this license notice and a URL through which recipients can access the Corresponding Source.", type: type.SHORT}, - {text: "<THISPROGRAM> is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.", type: type.SHORT}] - }, - - 'GNU-All-Permissive': { - licenseName: 'GNU All-Permissive License', - licenseFragments: [{text: "Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty.", type: type.SHORT}] - }, - - 'Apache-2.0': { - licenseName: 'Apache License, Version 2.0', - identifier: 'Apache-2.0', - canonicalUrl: [ - 'http://www.apache.org/licenses/LICENSE-2.0', - 'magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt' - ], - licenseFragments: [{text: "Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0", type: type.SHORT}] - }, - - 'LGPL-2.1': { - licenseName: 'GNU Lesser General Public License, version 2.1', - identifier: 'LGPL-2.1', - canonicalUrl: [ - 'http://www.gnu.org/licenses/lgpl-2.1.html', - 'magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt' - ], - licenseFragments: [{text: "<THISLIBRARY> is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.", type: type.SHORT}] - }, - - 'LGPL-3.0': { - licenseName: 'GNU Lesser General Public License, version 3', - identifier: 'LGPL-3.0', - canonicalUrl: [ - 'http://www.gnu.org/licenses/lgpl-3.0.html', - 'magnet:?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt' - ], - licenseFragments: [{text: "<THISPROGRAM> is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.", type: type.SHORT}] - }, - - 'AGPL-3.0': { - licenseName: 'GNU AFFERO GENERAL PUBLIC LICENSE version 3', - identifier: 'AGPL-3.0', - canonicalUrl: [ - 'http://www.gnu.org/licenses/agpl-3.0.html', - 'magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt' - ], - - licenseFragments: [{text: "<THISPROGRAM> is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.", type: type.SHORT}] - }, - - 'BSL-1.0': { - licenseName: 'Boost Software License 1.0', - identifier: 'BSL-1.0', - canonicalUrl: [ - 'http://www.boost.org/LICENSE_1_0.txt', - 'magnet:?xt=urn:btih:89a97c535628232f2f3888c2b7b8ffd4c078cec0&dn=Boost-1.0.txt' - ], - licenseFragments: [{text: "Boost Software License <VERSION> <DATE> Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the \"Software\") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following", type: type.SHORT}] - }, - - 'BSD-3-Clause': { - licenseName: "BSD 3-Clause License", - identifier: 'BSD-3-Clause', - canonicalUrl: [ - 'http://opensource.org/licenses/BSD-3-Clause', - 'magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt' - ], - licenseFragments: [{text: "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.", type: type.SHORT}] - }, - - 'BSD-2-Clause': { - licenseName: "BSD 2-Clause License", - identifier: 'BSD-2-Clause', - licenseFragments: [{text: "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.", type: type.SHORT}] - }, - - 'EPL-1.0': { - licenseName: "Eclipse Public License Version 1.0", - identifier: "EPL-1.0", - canonicalUrl: [ - "http://www.eclipse.org/legal/epl-v10.html", - "magnet:?xt=urn:btih:4c6a2ad0018cd461e9b0fc44e1b340d2c1828b22&dn=epl-1.0.txt" - ], - licenseFragments: [ - { - text: "THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.", - type: type.SHORT - } - ] - }, - - 'MPL-2.0': { - licenseName: 'Mozilla Public License Version 2.0', - identifier: 'MPL-2.0', - canonicalUrl: [ - 'http://www.mozilla.org/MPL/2.0', - 'magnet:?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt' - ], - licenseFragments: [{text: "This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.", type: type.SHORT }] - }, - - 'Expat': { - licenseName: 'Expat License (sometimes called MIT Licensed)', - identifier: 'Expat', - canonicalUrl: [ - 'http://www.jclark.com/xml/copying.txt', - 'magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt' - ], - licenseFragments: [{text: "Copyright <YEAR> <NAME> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", type: type.SHORT}] - }, - - 'X11': { - licenseName: 'X11 License', - identifier: 'X11', - canonicalUrl: [ - 'magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt' - ], - licenseFragments: [{text: "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", type: type.SHORT}] - }, - - 'XFree86-1.1': { - licenseName: "XFree86 1.1 License", - identifier: 'XFree86-1.1', - canonicalUrl: [ - 'http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3', - 'http://www.xfree86.org/current/LICENSE4.html', - 'magnet:?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt' - ], - licenseFragments: [{text: "All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution, and in the same place and form as other copyright, license and disclaimer information.\n3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: \"This product includes software developed by The XFree86 Project, Inc (http://www.xfree86.org/) and its contributors\", in the same place and form as other third-party acknowledgments. Alternately, this acknowledgment may appear in the software itself, in the same form and location as other such third-party acknowledgments.4. Except as contained in this notice, the name of The XFree86 Project, Inc shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The XFree86 Project, Inc.", type: type.SHORT} - ] - }, - - 'FreeBSD': { - licenseName: "FreeBSD License", - identifier: 'FreeBSD', - canonicalUrl: [ - 'http://www.freebsd.org/copyright/freebsd-license.html', - 'magnet:?xt=urn:btih:87f119ba0b429ba17a44b4bffcab33165ebdacc0&dn=freebsd.txt' - ], - licenseFragments: [{text: "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.", type: type.SHORT}] - }, - - 'ISC': { - licenseName: "The ISC License", - identifier: 'ISC', - canonicalUrl: [ - 'https://www.isc.org/downloads/software-support-policy/isc-license/', - 'magnet:?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt' - ], - licenseFragments: [{text: "Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.", type: type.SHORT}, - {text: "Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.", type: type.SHORT}] - }, - - 'jQueryTools': { - licenseName: "jQuery Tools", - licenseFragments: [{ - text: 'NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.', - type: type.SHORT - }] - }, - - 'Artistic-2.0': { - licenseName: "Artistic License 2.0", - identifier: 'Artistic-2.0', - canonicalUrl: [ - "http://www.perlfoundation.org/artistic_license_2_0", - "magnet:?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt" - ], - licenseFragments: [] - }, - - 'PublicDomain': { - licenseName: "Public Domain", - canonicalUrl: [ - 'magnet:?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt' - ], - licenseFragments: [] - }, - - 'CPAL-1.0': { - licenseName: 'Common Public Attribution License Version 1.0 (CPAL)', - identifier: 'CPAL-1.0', - canonicalUrl: [ - 'http://opensource.org/licenses/cpal_1.0', - 'magnet:?xt=urn:btih:84143bc45939fc8fa42921d619a95462c2031c5c&dn=cpal-1.0.txt' - ], - licenseFragments: [ - { - text: 'The contents of this file are subject to the Common Public Attribution License Version 1.0', - type: type.SHORT - }, - { - text: 'The term "External Deployment" means the use, distribution, or communication of the Original Code or Modifications in any way such that the Original Code or Modifications may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Code or Modifications as a distribution under section 3.1 and make Source Code available under Section 3.2.', - type: type.SHORT - } - ] - }, - 'WTFPL': { - licenseName: 'Do What The F*ck You Want To Public License (WTFPL)', - identifier: 'WTFPL', - canonicalUrl: [ - 'http://www.wtfpl.net/txt/copying/', - 'magnet:?xt=urn:btih:723febf9f6185544f57f0660a41489c7d6b4931b&dn=wtfpl.txt' - ], - licenseFragments: [ - { - text: 'DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE', - type: type.SHORT - }, - { - text: '0. You just DO WHAT THE FUCK YOU WANT TO.', - type: type.SHORT - } - ] - } -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js @@ -1,376 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ -const types = require("js_checker/constant_types"); - -// constants from Narcissus for function types. -const DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2; - -const token = types.token; - -var checkTypes = types.checkTypes; - -var utils = { - /** - * nodeContains - * Checks that node contains both a type and a value. - * Shortcut to check for null/undefined. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if matching. - */ - nodeContains: function (n, type, value) { - if (n != undefined) { - return n.type === type && - n.value === value; - } - }, - - /** - * isType - * Checks that node is of a certain type. - * Shortcut to check for null/undefined. - * - * @param {object} n. The current node being studied. - * @return {boolean}. True if it's the right type. - */ - isType: function (n, type) { - return n != undefined && n.type === type; - }, - - isNotType: function (n, type) { - return n != undefined && n.type !== type; - }, - - /** - * hasChildren - * - * Checks the token on the left - * and on the right. - * - * @param {object} n. The current node being studied. - * @param {leftType} token constant. The type on the - * left. - * @param {rightType} token constant. The type of child - * on the right - * - */ - hasChildren: function (n, leftType, rightType) { - if (types == undefined) { - return false; - } - return this.isType(n.children[0], leftType) && - this.isType(n.children[1], rightType); - }, - - /** - * findScriptTag - * - * This method should probably be replaced with DOM testing - * as regex is rather insufficiant, and this wouldn't cover - * tricky constructs as shown in http://ha.ckers.org/xss.html. - */ - findScriptTag: function (n) { - return n.value != undefined && - /<script[^>]*?>/i.test(n.value); - } -}; - -var NonTrivialChecker = function() { - this.definesFunction = false; - this.hash = null; -}; - -/** - * definesFunctionFound - * - * Returns true if it finds a node of type FUNCTION - * that isn't a callback or an IIFE. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ -NonTrivialChecker.prototype.definesFunctionFound = function (n) { - var isFunction = false; - if (n.type === token.FUNCTION && - n.body != undefined) { - - if (n.functionForm !== token.DECLARED_FORM && - ((n.parent.type === token.LIST && - n.parent.parent.type === token.CALL) || - n.parent.type === token.CALL) && - n.name == undefined) { - // this is a callback or an immediately - // invoked function expression "IIFE". - isFunction = false; - } else { - // this is a regular function declaration or - // function expression assigned to a variable. - //console.log("THIS DEFINES FUNCTION"); - isFunction = true; - } - } - - // look for Function constructor. - if (n.type === token.IDENTIFIER && - n.value === 'Function' && - (n.parent.type === token.NEW_WITH_ARGS || - n.parent.type === token.CALL)) { - // this is a Function constructor. - //console.log("THIS DEFINES FUNCTION"); - isFunction = true; - } - - return isFunction; -}; - - -/** - * invokesEval - * - * Returns true (nontrivial) if it finds any use of - * the eval function. For simplicity, we assume any - * use of an identifier "eval" is the eval function. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ -NonTrivialChecker.prototype.invokesEval = function (n) { - return (n.type === token.CALL && - utils.nodeContains(n.children[0], token.IDENTIFIER, 'eval') || - n.type === token.IDENTIFIER && n.value === 'eval'); -}; - -/** - * evalIdentifier - * - * Returns true (nontrivial) if it finds any use of - * the eval function. For simplicity, we assume any - * use of an identifier "eval" is the eval function. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ -NonTrivialChecker.prototype.evalIdentifier = function (n) { - return n.type === token.IDENTIFIER && n.value === 'eval'; -}; - - -/** - * invokesMethodBracketSuffix - * - * Finds a method being invoked using the bracket suffix notation - * rather than the dot notation. It is difficult without keeping track of - * variable values to check for what method is actually being called. - * So we're just flagging any use of this construct as nontrivial. - * e.g., should catch: xhr[a+b]('GET', 'http://www.example.com'); - * Should not catch other uses such as: myArray[num]; - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ -NonTrivialChecker.prototype.invokesMethodBracketSuffix = function (n) { - return n.type === token.CALL && utils.isType(n.children[0], token.INDEX); -}; - -/** - * createsXhrObject - * - * Creates an xhr object. - * Since all "new XMLHttpRequest", "XMLHttpRequest()", - * and "new window.XMLHttpRequest" instantiate the xhr object, - * we assume (without further proof) that any use - * of the identifier "XMLHttpRequest" and "ActiveXObject" - * is an xhr object. - * Constructs like window[a+b]() are already caught by the - * bracket suffix check. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ -NonTrivialChecker.prototype.createsXhrObject = function (n) { - return (n.type === token.IDENTIFIER) && - (n.value === 'XMLHttpRequest' || - n.value === 'ActiveXObject'); -}; - -/** - * invokesXhrOpen - * - * Here we assume the call of an open method must be an xhr request - * (and not some other object) by checking the number of arguments. - * In most cases this method won't be used since createsXhrObject - * will already have caught the xhr. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - */ -NonTrivialChecker.prototype.invokesXhrOpen = function (n) { - return n.type === token.CALL && - utils.hasChildren(n, token.DOT, token.LIST) && - utils.isType(n.children[0].children[0], token.IDENTIFIER) && - utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'open') && - n.children[1].children.length > 1; -}; - -/** - * createsScriptElement - * - * Checks for document.createElement() that create a script. In the case - * it creates an element from a variable, we assume it's a script. In the - * future we might want to check for the value of that string variable - * (e.g., if a variable is assigned 'script', raise a flag) - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - * - */ -NonTrivialChecker.prototype.createsScriptElement = function (n) { - return n.type === token.CALL && - utils.hasChildren(n, token.DOT, token.LIST) && - utils.isType(n.children[0].children[0], token.IDENTIFIER) && - utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'createElement') && - (utils.nodeContains(n.children[1].children[0], token.STRING, 'script') || - utils.isType(n.children[1].children[0], token.IDENTIFIER)); -}; - -/** - * writesScriptAsHtmlString - * - * catches myObj.write('<script></script>'); - * or any myObj.write(myStringVariable); - * or concatenation such as: - * myObj.write('<scri' + stringVariable); - * or 'something' + 'somethingelse'. - * - * To check for javascript here we might want to look at the list - * from ha.ckers.org/xss.html for the future. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - */ -NonTrivialChecker.prototype.writesScriptAsHtmlString = function (n) { - var listArg; - - if (n.type === token.CALL && - utils.hasChildren(n, token.DOT, token.LIST) && - utils.isType(n.children[0].children[0], token.IDENTIFIER) && - utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'write') - ) { - if (utils.isNotType(n.children[1].children[0], token.STRING)) { - // return true if any operation or concatenation. - // We are cautious (as it could - // embed a script) and flag this as nontrivial. - - return true; - } - return utils.findScriptTag(n.children[1].children[0]); - } else { - return false; - } -}; - -/** - * nontrivial anytime we see an identifier as innerHTML - */ -NonTrivialChecker.prototype.innerHTMLIdentifier = function (n) { - if ((n.type === token.IDENTIFIER || - n.type === token.STRING) && - n.value === 'innerHTML' - ) { - return true; - } -}; - -/** - * checkNontrivial - * - * Contains all the conditionals that try to identify, - * step by step, all code that could be flagged as - * nontrivial. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - */ -NonTrivialChecker.prototype.checkNontrivial = function (n, t) { - - if (n.type === token.IDENTIFIER && this.evalIdentifier(n)) { - //console.log("NONTRIVIAL: eval has been found in code"); - return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); - } - - if (this.innerHTMLIdentifier(n)) { - //console.log("NONTRIVIAL: innerHTML identifier"); - return types.nontrivialWithComment("NONTRIVIAL: innerHTML identifier"); - } - - // the node is an identifier - if (n.type === token.IDENTIFIER && this.createsXhrObject(n)) { - //console.log('NONTRIVIAL: Creates an xhr object'); - return types.nontrivialWithComment('NONTRIVIAL: Creates an xhr object'); - } - - // this is a method/function call - if (n.type === token.CALL) { - - if (this.invokesEval(n)) { - //console.log("NONTRIVIAL: eval has been found in code"); - return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); - } - - if (this.invokesMethodBracketSuffix(n)) { - //console.log('NONTRIVIAL: square bracket suffix method call detected'); - return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); - } - - if (this.invokesXhrOpen(n)) { - //console.log('NONTRIVIAL: an open method similar to xhr.open is used'); - return types.nontrivialWithComment('NONTRIVIAL: square bracket suffix method call detected'); - } - - if (this.createsScriptElement(n)) { - //console.log('NONTRIVIAL: creates script element dynamically.'); - return types.nontrivialWithComment('NONTRIVIAL: an open method similar to xhr.open is used'); - } - - if (this.writesScriptAsHtmlString(n)) { - //console.log('NONTRIVIAL: writes script as html dynamically.'); - return types.nontrivialWithComment('NONTRIVIAL: creates script element dynamically.'); - } - } - - // The node is a function definition. - // Most common occurence. - if (this.definesFunctionFound(n)) { - return types.trivialFuncWithComment("Script is trivial but defines one or more functions"); - } - - // found nothing else, so trivial. - return types.trivialWithComment("Script is trivial"); -}; - -exports.nonTrivialChecker = function () { - return new NonTrivialChecker(); -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/privacy_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/privacy_checker.js @@ -1,46 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -const privacyThreatJs = require('js_checker/privacy_threat_definitions.js'); -const patternUtils = require('js_checker/pattern_utils').patternUtils; - -exports.privacyCheck = { - checkScriptPrivacyThreat: function (currentScript) { - var list = privacyThreatJs.js; - var i; - var item; - var max; - - currentScript = patternUtils.removeWhitespace(currentScript); - - for (item in list) { - max = list[item].length; - - for (i = 0; i < max; i++) { - if (list[item][i].test(currentScript)) { - return true; - } - } - } - return false; - } -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/relation_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/relation_checker.js @@ -1,291 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ -/** - * relation_checker.js - * - * Finds out if two scripts are related to each other. - * - */ -const types = require("js_checker/constant_types"); - -const token = types.token; - -// all predefined window properties (methods and variables). -const windowPropertiesHash = { - "addEventListener": 1, "alert": 1, "applicationCache": 1, - "Array": 1, "ArrayBuffer": 1, "atob": 1, "back": 1, "blur": 1, - "Boolean": 1, "btoa": 1, "captureEvents": 1, "CharacterData": 1, - "clearInterval": 1, "clearTimeout": 1, "close": 1, "closed": 1, - "Components": 1, "confirm": 1, "console": 1, "constructor": 1, - "content": 1, "controllers": 1, "crypto": 1, - "CSSStyleDeclaration": 1, "Date": 1, "decodeURI": 1, - "decodeURIComponent": 1, "defaultStatus": 1, - "disableExternalCapture": 1, "dispatchEvent": 1, "Document": 1, - "document": 1, "DocumentType": 1, "dump": 1, "Element": 1, - "enableExternalCapture": 1, "encodeURI": 1, "encodeURIComponent": 1, - "Error": 1, "escape": 1, "eval": 1, "EvalError": 1, "Event": 1, - "find": 1, "Float32Array": 1, "Float64Array": 1, "focus": 1, - "forward": 1, "frameElement": 1, "frames": 1, "fullScreen": 1, - "Function": 1, "Generator": 1, "getComputedStyle": 1, - "getInterface": 1, "getSelection": 1, "globalStorage": 1, - "history": 1, "home": 1, "HTMLBodyElement": 1, "HTMLCollection": 1, - "HTMLDivElement": 1, "HTMLDocument": 1, "HTMLElement": 1, - "HTMLHeadElement": 1, "HTMLHeadingElement": 1, "HTMLHtmlElement": 1, - "HTMLStyleElement": 1, "HTMLUnknownElement": 1, "Infinity": 1, - "innerHeight": 1, "innerWidth": 1, "InstallTrigger": 1, - "Int16Array": 1, "Int32Array": 1, "Int8Array": 1, "InternalError": 1, - "isFinite": 1, "isNaN": 1, "isXMLName": 1, "Iterator": 1, - "JSON": 1, "length": 1, "localStorage": 1, "Location": 1, - "location": 1, "locationbar": 1, "matchMedia": 1, "Math": 1, - "menubar": 1, "moveBy": 1, "moveTo": 1, "mozAnimationStartTime": 1, - "mozIndexedDB": 1, "mozInnerScreenX": 1, "mozInnerScreenY": 1, - "mozPaintCount": 1, "mozRequestAnimationFrame": 1, "name": 1, - "Namespace": 1, "NaN": 1, "navigator": 1, "netscape": 1, - "Node": 1, "NodeList": 1, "Number": 1, "Object": 1, "open": 1, - "openDialog": 1, "opener": 1, "outerHeight": 1, "outerWidth": 1, - "pageXOffset": 1, "pageYOffset": 1, "parent": 1, "parseFloat": 1, - "parseInt": 1, "performance": 1, "personalbar": 1, "pkcs11": 1, - "postMessage": 1, "print": 1, "prompt": 1, "QName": 1, - "RangeError": 1, "ReferenceError": 1, "RegExp": 1, - "releaseEvents": 1, "removeEventListener": 1, "resizeBy": 1, - "resizeTo": 1, "routeEvent": 1, "screen": 1, "screenX": 1, - "screenY": 1, "scroll": 1, "scrollbars": 1, "scrollBy": 1, - "scrollByLines": 1, "scrollByPages": 1, "scrollMaxX": 1, - "scrollMaxY": 1, "scrollTo": 1, "scrollX": 1, "scrollY": 1, - "self": 1, "sessionStorage": 1, "setInterval": 1, "setResizable": 1, - "setTimeout": 1, "showModalDialog": 1, "sizeToContent": 1, - "status": 1, "statusbar": 1, "stop": 1, "StopIteration": 1, - "StorageList": 1, "String": 1, "SyntaxError": 1, "Text": 1, - "toolbar": 1, "top": 1, "TypeError": 1, "Uint16Array": 1, - "Uint32Array": 1, "Uint8Array": 1, "Uint8ClampedArray": 1, - "undefined": 1, "unescape": 1, "uneval": 1, "updateCommands": 1, - "URIError": 1, "URL": 1, "WeakMap": 1, "Window": 1, "window": 1, - "XML": 1, "XMLList": 1, "XPCNativeWrapper": 1}; - -// all predefined document properties. -const documentPropertiesHash = {'activeElement': 1, 'addBinding': 1, - 'addEventListener': 1, 'adoptNode': 1, 'alinkColor': 1, 'anchors': 1, - 'appendChild': 1, 'applets': 1, 'ATTRIBUTE_NODE': 1, 'attributes': 1, - 'baseURI': 1, 'bgColor': 1, 'body': 1, 'captureEvents': 1, - 'CDATA_SECTION_NODE': 1, 'characterSet': 1, 'childNodes': 1, 'clear': - 1, 'cloneNode': 1, 'close': 1, 'COMMENT_NODE': 1, - 'compareDocumentPosition': 1, 'compatMode': 1, 'contentType': 1, - 'cookie': 1, 'createAttribute': 1, 'createAttributeNS': 1, - 'createCDATASection': 1, 'createComment': 1, 'createDocumentFragment': - 1, 'createElement': 1, 'createElementNS': 1, 'createEvent': 1, - 'createExpression': 1, 'createNodeIterator': 1, 'createNSResolver': 1, - 'createProcessingInstruction': 1, 'createRange': 1, 'createTextNode': - 1, 'createTreeWalker': 1, 'currentScript': 1, 'defaultView': 1, - 'designMode': 1, 'dir': 1, 'dispatchEvent': 1, 'doctype': 1, - 'DOCUMENT_FRAGMENT_NODE': 1, 'DOCUMENT_NODE': 1, - 'DOCUMENT_POSITION_CONTAINED_BY': 1, 'DOCUMENT_POSITION_CONTAINS': 1, - 'DOCUMENT_POSITION_DISCONNECTED': 1, 'DOCUMENT_POSITION_FOLLOWING': 1, - 'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC': 1, - 'DOCUMENT_POSITION_PRECEDING': 1, 'DOCUMENT_TYPE_NODE': 1, - 'documentElement': 1, 'documentURI': 1, 'domain': 1, 'ELEMENT_NODE': - 1, 'elementFromPoint': 1, 'embeds': 1, 'enableStyleSheetsForSet': 1, - 'ENTITY_NODE': 1, 'ENTITY_REFERENCE_NODE': 1, 'evaluate': 1, - 'execCommand': 1, 'execCommandShowHelp': 1, 'fgColor': 1, - 'firstChild': 1, 'forms': 1, 'getAnonymousElementByAttribute': 1, - 'getAnonymousNodes': 1, 'getBindingParent': 1, 'getElementById': 1, - 'getElementsByClassName': 1, 'getElementsByName': 1, - 'getElementsByTagName': 1, 'getElementsByTagNameNS': 1, - 'getSelection': 1, 'getUserData': 1, 'hasAttributes': 1, - 'hasChildNodes': 1, 'hasFocus': 1, 'head': 1, 'images': 1, - 'implementation': 1, 'importNode': 1, 'inputEncoding': 1, - 'insertBefore': 1, 'isDefaultNamespace': 1, 'isEqualNode': 1, - 'isSameNode': 1, 'isSupported': 1, 'lastChild': 1, 'lastModified': 1, - 'lastStyleSheetSet': 1, 'linkColor': 1, 'links': 1, - 'loadBindingDocument': 1, 'localName': 1, 'location': 1, - 'lookupNamespaceURI': 1, 'lookupPrefix': 1, 'mozSetImageElement': 1, - 'mozSyntheticDocument': 1, 'namespaceURI': 1, 'nextSibling': 1, - 'nodeName': 1, 'nodeType': 1, 'nodeValue': 1, 'normalize': 1, - 'NOTATION_NODE': 1, 'open': 1, 'ownerDocument': 1, 'parentNode': 1, - 'plugins': 1, 'preferredStyleSheetSet': 1, 'prefix': 1, - 'previousSibling': 1, 'PROCESSING_INSTRUCTION_NODE': 1, - 'queryCommandEnabled': 1, 'queryCommandIndeterm': 1, - 'queryCommandState': 1, 'queryCommandSupported': 1, - 'queryCommandText': 1, 'queryCommandValue': 1, 'querySelector': 1, - 'querySelectorAll': 1, 'readyState': 1, 'referrer': 1, - 'releaseCapture': 1, 'releaseEvents': 1, 'removeBinding': 1, - 'removeChild': 1, 'removeEventListener': 1, 'replaceChild': 1, - 'routeEvent': 1, 'selectedStyleSheetSet': 1, 'setUserData': 1, - 'styleSheets': 1, 'styleSheetSets': 1, 'TEXT_NODE': 1, 'textContent': - 1, 'title': 1, 'URL': 1, 'vlinkColor': 1, 'write': 1, 'writeln': 1, - 'xmlEncoding': 1, 'xmlStandalone': 1, 'xmlVersion': 1}; - -var relationChecker = { - - // identifies scripts across modules. - scriptId: null, - - // stores all left-side identifier in 'assign' types. - assignments: null, - - // stores var declarations in global scope. - variableDeclarations: null, - - // stores top declarations in global scope. - functionDeclarations: null, - - nonWindowProperties: null, - - init: function (scriptId) { - this.scriptId = scriptId; - this.assignments = []; - this.variableDeclarations = {}; - this.functionDeclarations = {}; - this.nonWindowProperties = {}; - }, - - isWindowProperty: function (identifier) { - return (identifier in windowPropertiesHash) ? true : false; - }, - - isDocumentProperty: function (identifier) { - return (identifier in documentPropertiesHash) ? true : false; - }, - - storeNodeVars: function (n) { - if (n.varDecls != undefined) { - var i = 0, le = n.varDecls.length; - for (; i < le; i++) { - this.variableDeclarations[n.varDecls[i].value] = 1; - } - } - }, - - storeNodeFunctions: function (n) { - if (n.funDecls != undefined) { - var i = 0, le = n.funDecls.length; - for (; i < le; i++) { - this.functionDeclarations[n.funDecls[i].name] = 1; - } - } - }, - storeGlobalDeclarations: function (topNode) { - this.storeNodeVars(topNode); - this.storeNodeFunctions(topNode); - }, - storeNodeGlobalDeclarations: function (n) { - if (n.global === true) { - this.storeNodeVars(n); - this.storeNodeFunctions(n); - } - }, - - storeNodeAssignments: function (n) { - if (n.type === token.ASSIGN && - n.children != undefined && - n.children[0].type === token.IDENTIFIER) { - this.assignments.push(n.children[0].value); - } - }, - - // checks the parent script is in global scope. - isInGlobalScope: function (n) { - var currentNode = n; - - while (currentNode != undefined) { - if (currentNode.type === token.SCRIPT && - currentNode.global === true) { - return true; - } else if (currentNode.type === token.SCRIPT) { - return false; - } - currentNode = currentNode.parent; - } - }, - - // looks for an identifier being declared as either a - // variable or a function within the scope. Currently, - // we don't care about assignments. - lookForIdentifierInAllScopes: function (n, val) { - - var currentNode = n, i, le, vars, funcs; - while (currentNode != undefined) { - if (currentNode.varDecls != undefined) { - vars = currentNode.varDecls; - le = vars.length; - for (i = 0; i < le; i++) { - if (vars[i].value === val) { - console.debug('FOUND declaration for', val); - return true; - } - } - } - if (currentNode.funDecls != undefined) { - funcs = currentNode.funDecls; - le = funcs.length; - for (i = 0; i < le; i++) { - if (funcs[i].name === val) { - console.debug('FOUND function declaration for', val); - return true; - } - } - } - currentNode = currentNode.parent; - } - console.debug('did not find declaration or assignment for', val); - }, - - // Heuristic method for window properties. - // this doesn't prove they are window properties, but - // it allows to make a good guess. These variables could have - // been assigned to something else... - checkIdentifierIsWindowProperty: function (n) { - - if (n.type === token.IDENTIFIER && - (n.parent.type === token.CALL || - (n.parent.type === token.DOT && - n.previous != undefined && - (n.previous.type === token.THIS || - (n.previous.type === token.IDENTIFIER && - n.previous.value === 'window')))) && - n.value in windowPropertiesHash) { - - this.lookForIdentifierInAllScopes(n, n.value); - - } - - else if (n.type === token.IDENTIFIER && - n.parent != undefined && - n.parent.type === token.DOT && - n.previous != undefined && - n.previous.type === token.THIS && - this.isInGlobalScope(n)) { - console.debug(n.type, 'use of this in the global scope, seems ok.', n.value); - } - else if (n.type === token.IDENTIFIER) { - // not found. - console.debug(n.type, 'probably not a window prop', n.value); - this.nonWindowProperties[n.value] = 1; - } - } - -}; - -exports.relationChecker = function (scriptId) { - var obj = Object.create(relationChecker); - obj.init(scriptId); - return obj; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/main.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/main.js @@ -1,71 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -// Uncomment the following to start debugging, or do it from about:config. -// var name = "extensions.jid1-KtlZuoiikVfFew@jetpack.sdk.console.logLevel"; -// require("sdk/preferences/service").set(name, "all"); - -const { Cc, Ci } = require("chrome"); - -const librejsStorage = require("settings/storage").librejsStorage; -let addonManage = require("addon_management/install_uninstall"); -let httpObserver = require("http_observer/http_request_observer"); -let prefObserver = require("pref_observer/pref_observer"); -let prefChange = require("addon_management/prefchange"); -let uiInfo = require("ui/ui_info"); -let scriptPanel = require("ui/script_panel.js"); - -require('ui'); - -// set whitelist at startup. -prefChange.init(); -var widgetIsOn = false; - -// read storage file. -var cachedResult = librejsStorage.init(); -librejsStorage.generateCacheFromDB(); - -exports.main = function(options, callbacks) { - if (options.loadReason === 'enable' || - options.loadReason === 'install' - ) { - addonManage.onLoad(); - } -}; - -exports.onUnload = addonManage.onUnload; -exports.onLoad = addonManage.onLoad; - -var prefs = require('sdk/preferences/service'); -var isJavaScriptEnabled = prefs.get('javascript.enabled'); -if (!isJavaScriptEnabled) { - console.debug('JS disabled in add-on init'); - // remove all http notifications - httpObserver.removeHttpObserver(); - // TODO: the narcissus worker could also be stopped at this - // point, but I'm not doing that right now because I don't - // know how to re-enable it. - //narcissusWorker.stopWorker(); -} else { - console.debug('JS enabled in add-on init'); -} -prefObserver.register(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/parser/narcissus_worker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/parser/narcissus_worker.js @@ -1,81 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var data = require("sdk/self").data; -var {Cu} = require("chrome"); -var {ChromeWorker} = Cu.import("resource://gre/modules/Services.jsm", null); -var worker = new ChromeWorker( - data.url("chrome_worker/parser/parse.js")); - -var NarcissusWorker = function() { - this.worker = worker; - var that = this; - - this.worker.onmessage = function(e) { - var jsChecker = require("js_checker/js_checker"); - - console.debug('onmessage', e.data.hash); - try { - console.debug('calling jsChecker.callbackHashResult() for hash:', - e.data.hash); - jsChecker.callbackHashResult(e.data.hash, e.data.tree); - } catch (x) { - console.debug('error on message', x); - jsChecker.callbackHashResult(e.data.hash, false); - } - jsChecker = null; - }; - - // Enabling the catch clause in data/chrome_worker/parser - // instead of here because we can get the hash from there. - /*this.worker.onerror = function (e) { - console.debug( - 'error', e.lineno, - 'in', e.filename, - 'e', e.message, - 'full message', e - ); - // can't get hash from this context - that.worker.postMessage(JSON.stringify({'hash': null})); - };*/ -}; - -NarcissusWorker.prototype.stopWorker = function() { - console.debug('stopping worker'); - this.worker.postMessage('stop'); -}; - -NarcissusWorker.prototype.parse = function(scriptText, hash) { - console.debug('parsing', hash); - try { - this.worker.postMessage(JSON.stringify({ - 'code': scriptText, - 'hash': hash - })); - } catch (x) { - console.debug('error in lib/narcissus_worker.js', x, x.lineNumber); - } - -}; - -var narcissusWorker = new NarcissusWorker(); -exports.narcissusWorker = narcissusWorker; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/pref_observer/pref_observer.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/pref_observer/pref_observer.js @@ -1,72 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var {Cc, Ci} = require("chrome"); -const httpObserver = require("http_observer/http_request_observer"); - -// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Preferences#Using_preference_observers -var prefObserver = { - register: function() { - // First we'll need the preference services to look for preferences. - var prefService = Cc["@mozilla.org/preferences-service;1"] - .getService(Ci.nsIPrefService); - - // For this.branch we ask for the preferences for - // extensions.myextension. and children - this.branch = prefService.getBranch("javascript."); - - // Finally add the observer. - this.branch.addObserver("", this, false); - }, - - unregister: function() { - this.branch.removeObserver("", this); - }, - - observe: function(aSubject, aTopic, aData) { - // aSubject is the nsIPrefBranch we're observing (after appropriate QI) - // aData is the name of the pref that's been changed (relative to - // aSubject) - switch (aData) { - case "enabled": - var prefs = require('sdk/preferences/service'); - var isJavaScriptEnabled = prefs.get('javascript.enabled'); - if (!isJavaScriptEnabled) { - console.debug('JS disabled in observer'); - // remove all http notifications - httpObserver.removeHttpObserver(); - - // TODO: the narcissus worker could also be stopped at this - // point, but I'm not doing that right now because I don't - // know how to re-enable it. - // narcissusWorker.stopWorker(); - } else { - console.debug('JS enabled in observer'); - httpObserver.startHttpObserver(); - } - break; - } - } -}; - -exports.register = function() { - prefObserver.register(); -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/accepted_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/accepted_scripts.js @@ -1,69 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var allScripts = require('script_entries/all_scripts').allScripts; - -var AcceptedScripts = function() { - this.scripts = {}; - this.truncateJsData = allScripts.truncateJsData; - this.getScripts = allScripts.getScripts; - this.isFound = allScripts.isFound; - this.returnWhenFound = allScripts.returnWhenFound; - this.getOrInitScripts = allScripts.getOrInitScripts; - this.setHash = allScripts.setHash; -}; - -AcceptedScripts.prototype.clearScripts = function (url) { - this.scripts[url] = []; -}; - -/** - * addAScript - * adds a single script to the scripts array. - * @param {string} url - the url of the page where it is loaded. - * @param {object} scriptObj - Additional data regarding this script, - * including: inline: boolean, - * contents: string, - * removalReason: string. - */ -AcceptedScripts.prototype.addAScript = function (url, scriptObj) { - var exists; - - if (this.scripts[url] === undefined) { - this.clearScripts(url); - } - - // check if content is actually js code. - if (scriptObj.inline === true) { - this.setHash(scriptObj); - this.truncateJsData(scriptObj); - } - exists = this.isFound(url, scriptObj); - if (!exists) { - this.scripts[url].push(scriptObj); - return true; - } else { - return false; - } -}; - -exports.acceptedScripts = new AcceptedScripts(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/all_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/all_scripts.js @@ -1,110 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var crypto = require('script_entries/crypto'); - -var AllScripts = function() { - this.scripts = {}; -}; - -AllScripts.prototype.truncateJsData = function (scriptObj) { - if (scriptObj.contents === undefined) { - console.debug('this is an inline script', scriptObj.value); - console.debug('this is an src', scriptObj.url); - } - if (scriptObj.contents.length > 1000) { - scriptObj.contents = scriptObj.contents.substring(0, 1000); - scriptObj.contents += '…'; - } -}; - -AllScripts.prototype.setHash = function (scriptObj) { - scriptObj.hash = crypto.sha1Encrypt(scriptObj.contents); - return scriptObj.hash; -}; - -AllScripts.prototype.getScripts = function (url) { - if (!this.scripts[url]) { - return false; - } else { - return this.scripts[url]; - } -}; - -AllScripts.prototype.reverseArray = function (url) { - this.scripts[url].reverse(); -}; - -AllScripts.prototype.getOrInitScripts = function (url) { - if (this.scripts[url] === undefined) { - this.scripts[url] = []; - } - return this.scripts[url]; -}; - -AllScripts.prototype.returnWhenFound = function(url, data) { - var pageScripts = this.getOrInitScripts(url), - i = 0, - le = pageScripts.length; - - // check that entry doesn't exist. - if (data.inline === false) { - for (; i < le; i++) { - if (pageScripts[i].contents === data.url) { - return pageScripts[i]; - } - } - } else if (data.inline === true) { - for (; i < le; i++) { - if (pageScripts[i].hash === crypto.sha1Encrypt(data.contents)) { - return pageScripts[i]; - } - } - } - - return false; -}; - -AllScripts.prototype.isFound = function(url, data) { - var pageScripts = this.getOrInitScripts(url), - i = 0, - le = pageScripts.length; - - // check that entry doesn't exist. - if (data.inline === false) { - for (; i < le; i++) { - if (pageScripts[i].url === data.url) { - return true; - } - } - } else if (data.inline === true) { - for (; i < le; i++) { - if (pageScripts[i].hash === crypto.sha1Encrypt(data.contents)) { - return true; - } - } - } - - return false; -}; - -exports.allScripts = new AllScripts(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/dryrun_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/dryrun_scripts.js @@ -1,78 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var allScripts = require('script_entries/all_scripts').allScripts; -const urlHandler = require('url_handler/url_handler'); - -exports.dryRunScripts = { - scripts: {}, - - truncateJsData: allScripts.truncateJsData, - - getScripts: allScripts.getScripts, - - isFound: allScripts.isFound, - - returnWhenFound: allScripts.returnWhenFound, - - getOrInitScripts: allScripts.getOrInitScripts, - - reverseArray: allScripts.reverseArray, - - setHash: allScripts.setHash, - - clearScripts: function (url) { - this.scripts[url] = []; - }, - - /** - * addAScript - * adds a single script to the scripts array. - * @param {string} url - the url of the page where it is loaded. - * @param {object} scriptObj - Additional data regarding this script, - * including: inline: boolean, - * contents: string, - * removalReason: string. - */ - addAScript: function (url, scriptObj, absoluteUrl) { - var exists; - - if (this.scripts[url] === undefined) { - this.clearScripts(url); - } - if (scriptObj.inline === true) { - this.setHash(scriptObj); - this.truncateJsData(scriptObj); - } else if (absoluteUrl !== undefined && - scriptObj.inline === false) { - scriptObj.contents = urlHandler.resolve(absoluteUrl, scriptObj.contents); - } - exists = this.isFound(url, scriptObj); - - if (!exists) { - this.scripts[url].push(scriptObj); - return true; - } else { - return false; - } - } -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/free_libraries.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/free_libraries.js @@ -1,67 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -// THIS MODULE IS DEPRECATED IN FAVOR OF THE NEW WHITELISTING MODULE (LibreJS 6.0) - -var relationChecker = require("js_checker/relation_checker").relationChecker; -var checkTypes = require("js_checker/constant_types").checkTypes; -var scriptsCached = require("script_entries/scripts_cache").scriptsCached; - - -// find the json database path. -var dbContents = require("sdk/self").data.load("script_libraries/script-libraries.json"); - -const AUTHOR_REASON = "This script has been tagged as free software by LibreJS authors."; - -var freeLibraries = JSON.parse(dbContents); /* a database of the free libraries recognized by default */ - -/* - * List of free libraries and their SHA256 hash. - * This is used to recognize the most common free libraries. - */ - -var init = function () { - - // relationChecker, which roughly checks if variables are window - // variables or not, is useless in this case. Use the same - // object for all entries. - var rc = relationChecker(); - var library, hash; - var freeObj = { "type": 4, "reason": AUTHOR_REASON}; - console.debug("Building init"); - for (hash in freeLibraries) { - library = freeLibraries[hash]; - - // assign empty relationChecker object. - library.relationChecker = rc; - - // make them free and nontrivial. - library.result = freeObj; - - scriptsCached.addObjectEntry(hash, library); - } -}; - -//init(); - -exports.init = init; -exports.AUTHOR_REASON = AUTHOR_REASON; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/removed_scripts.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/removed_scripts.js @@ -1,73 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var allScripts = require('script_entries/all_scripts').allScripts; -const urlHandler = require('url_handler/url_handler'); - -var RemovedScripts = function() { - this.scripts = {}; - this.truncateJsData = allScripts.truncateJsData; - this.getScripts = allScripts.getScripts; - this.isFound = allScripts.isFound; - this.returnWhenFound = allScripts.returnWhenFound; - this.getOrInitScripts = allScripts.getOrInitScripts; - this.reverseArray = allScripts.reverseArray; - this.setHash = allScripts.setHash; -}; - -RemovedScripts.prototype.clearScripts = function (url) { - this.scripts[url] = []; -}; - -/** - * addAScript - * adds a single script to the scripts array. - * @param {string} url - the url of the page where it is loaded. - * @param {object} scriptObj - Additional data regarding this script, - * including: inline: boolean, - * contents: string, - * removalReason: string. - */ -RemovedScripts.prototype.addAScript = function (url, scriptObj, absoluteUrl) { - var exists; - - if (this.scripts[url] === undefined) { - this.clearScripts(url); - } - if (scriptObj.inline === true) { - this.setHash(scriptObj); - this.truncateJsData(scriptObj); - } else if (absoluteUrl !== undefined && - scriptObj.inline === false) { - scriptObj.contents = urlHandler.resolve(absoluteUrl, scriptObj.contents); - } - exists = this.isFound(url, scriptObj); - - if (!exists) { - this.scripts[url].push(scriptObj); - return true; - } else { - return false; - } -}; - -exports.removedScripts = new RemovedScripts(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/scripts_cache.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/script_entries/scripts_cache.js @@ -1,192 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ -var relationCheckerObj = require("js_checker/relation_checker") - .relationChecker; - -// import free_libraries to populate the cache hash map. -var free_libraries = require("script_entries/free_libraries"); - -var crypto = require('script_entries/crypto'); -const checkTypes = require("js_checker/constant_types").checkTypes; - -// cachedResults contains objects with result/relationChecker for -// scripts entries indexed by SHA1sum -var cachedResults = {}; - -/** - * ScriptsCached keeps a cache of whitelisted scripts in the browser - * session. - */ -var ScriptsCached = function() { -}; - -ScriptsCached.prototype.getHash = function(scriptText) { - require('ui/notification').createNotification(scriptText.substring(0,100)); - - return crypto.sha1Encrypt(scriptText); -}; - -/** - * resetCache - * Resets the full cache and re-initialize - * the free libraries list. - */ -ScriptsCached.prototype.resetCache = function () { - cachedResults = {}; - free_libraries.init(); -}; - -/** - * - * addEntry - * - * Adds a script entry to the cache by providing the results - * and the actual script text. - * - */ -ScriptsCached.prototype.addEntry = function( - scriptText, result, relationChecker, allowTrivial, url) { - console.debug("result addEntry is", JSON.stringify(result)); - cachedResults[this.getHash(scriptText)] = { - 'result': result, - 'relationChecker': relationCheckerObj(), - 'allowTrivial': allowTrivial, - 'url': url - }; -}; - -/** - * - * addEntry - * - * Adds a script entry to the cache by providing the results - * using the script's hash. - * - */ -ScriptsCached.prototype.addEntryByHash = function( - hash, result, relationChecker, allowTrivial, url) { - cachedResults[hash] = { - 'result': result, - 'relationChecker': relationCheckerObj(), - 'allowTrivial': allowTrivial, - 'url': url || '' - }; -}; - -/** - * removeEntryByHash - * - * Remove an entry from the cache using hash key. - */ -ScriptsCached.prototype.removeEntryByHash = function(hash) { - delete cachedResults[hash]; -}; - -/** - * addEntryIfNotCached - * - * Checks first if entry is cached before attempting to cache result. - */ -ScriptsCached.prototype.addEntryIfNotCached = function( - scriptText, result, relationChecker, allowTrivial, url) { - // save a bit of computing by getting hash once. - var hash = this.getHash(scriptText); - console.debug('hash is then', hash); - if (!this.isCached(scriptText, hash)) { - cachedResults[hash] = { - 'result': result, - 'relationChecker': relationCheckerObj(), - 'allowTrivial': allowTrivial, - 'url': url || '' - }; - } - return hash; -}; - -/** - * - * addObjectEntry - * - * Adds a script entry by providing an object. - * Used to provide free library hashes from free_libraries.js - * - */ -ScriptsCached.prototype.addObjectEntry = function(hash, script) { - cachedResults[hash] = script; -}; - -ScriptsCached.prototype.isCached = function(scriptText, hash) { - var scriptHash; - console.debug("Is CACHED start?"); - try { - if (typeof hash === 'string') { - scriptHash = hash; - } else { - scriptHash = this.getHash(scriptText); - } - if (typeof scriptHash === 'string') { - let cachedResult = cachedResults[scriptHash]; - if (cachedResult) { - // exact copy of file has already been cached. - console.debug('scriptHash is', cachedResult); - if (cachedResult.relationChecker == "[rl]") { - cachedResult.relationChecker = {}; //relationCheckerObj(); - } - console.debug("Is Cached ENd TRUE"); - return cachedResult; - } - } - return false; - } catch (e) { - console.debug("an error", scriptHash, e, e.linenumber, e.filename); - } -}; - -/** - * Writes allowed scripts to the cache. - * nonfree/nontrivial scripts are not added to the cache. - */ -ScriptsCached.prototype.getCacheForWriting = function() { - var formattedResults = {}; - for (let item in cachedResults) { - let type = cachedResults[item].result.type; - if (type != checkTypes.NONTRIVIAL && - type != checkTypes.TRIVIAL_DEFINES_FUNCTION - ) { - formattedResults[item] = cachedResults[item]; - } - } - return formattedResults; -}; - -/** - * Import data from database into cachedResults. - * Calling this function replaces the current cache if it exists. - */ -ScriptsCached.prototype.bulkImportCache = function(data) { - cachedResults = data; - console.debug("Imported data. Number of keys ISSS ", - Object.keys(cachedResults).length); - console.debug("It looks like ", JSON.stringify(cachedResults)); -}; - -exports.scriptsCached = new ScriptsCached(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/settings/settings_tab.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/settings/settings_tab.js @@ -1,80 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ -const tabs = require("sdk/tabs"); -const data = require("sdk/self").data; -const storage = require("settings/storage").librejsStorage; -const scriptsCached = require("script_entries/scripts_cache").scriptsCached; - -exports.settingsManager = settingsManager; - -let settingsManager = { - settingsTab: { - url: data.url("settings/index.html"), - onReady: function (tab) { - console.debug("populating form"); - var that = this; - let cache_data = scriptsCached.getCacheForWriting(); - let worker = tab.attach({ - contentScriptFile: [ - data.url('settings/js/pagescript-listener.js'), - data.url('settings/js/pagescript-emitter.js') - ] - }); - worker.port.emit("populate-form", cache_data); - worker.port.on("rules-form-delete", function (hash) { - try { - scriptsCached.removeEntryByHash(hash); - } catch (e) { - console.log('caught!', e, e.lineNumber, e.filename); - } - //worker.port.emit("populate-form", scriptsCached.getCacheForWriting()); - }); - worker.port.on("rules-form-delete-all", function () { - scriptsCached.resetCache(); - }); - }, - onActivate: function (tab) { - // just reload the form. - console.debug("Tab is activated again"); - var that = this; - let cache_data = scriptsCached.getCacheForWriting(); - let worker = tab.attach({ - contentScriptFile: [ - data.url('settings/js/pagescript-listener.js'), - data.url('settings/js/pagescript-emitter.js') - ] - }); - worker.port.emit("populate-form", cache_data); - } - }, - - init: function () { - settings.onLoad(function (data) {}); - }, - - open: function () { - console.debug("settings tab data url is", this.settingsTab.url); - tabs.open(this.settingsTab); - } -}; - -exports.settingsManager = settingsManager; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/settings/storage.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/settings/storage.js @@ -1,177 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ -/*jshint esnext: true */ - -const { Cc, Ci, Cu, components } = require("chrome"); - -var { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm"); -var { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm"); -var relationChecker = require("js_checker/relation_checker").relationChecker; -var rc = relationChecker(); // a dummy object for legacy module. -const AUTHOR_REASON = require("script_entries/free_libraries").AUTHOR_REASON; -var relationChecker = require("js_checker/relation_checker").relationChecker; - -const scriptsCached = require("script_entries/scripts_cache").scriptsCached; - -let librejsStorage = { - - file: null, - filename: 'librejs-whitelist.json', - data: [], - - onLoad: function (callback) { - // will read the json file. - this.init(); - this.read(callback); - }, - - init: function () { - // get the "librejs-whitelist.json" file in the profile directory - this.file = FileUtils.getFile("ProfD", [this.filename]); - }, - - read: function (callback) { - // Content type hint is useful on mobile platforms where the filesystem - // would otherwise try to determine the content type. - var channel = NetUtil.newChannel(this.file); - var that = this; - channel.contentType = "application/json"; - try { - NetUtil.asyncFetch(channel, function(inputStream, status) { - - if (!components.isSuccessCode(status)) { - require("script_entries/free_libraries").init(); - that.initialWrite(); - } - - var raw_data = NetUtil.readInputStreamToString( - inputStream, inputStream.available()); - // expand json file back to original contents. - var re = new RegExp( - "[freelib]".replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), - 'g' - ); - raw_data = raw_data.replace(re, AUTHOR_REASON); - //console.debug("raw_data is ", raw_data); - // The file data is contained within inputStream. - // You can read it into a string with - // get string into json also - that.data = JSON.parse(raw_data); - - callback(that.data); - }); - } catch (e) { - that.initialWrite(); - } - }, - - initialWrite: function (callback) { - console.debug("About to write free libraries"); - // our file is not populated with default contents. - // use free_libraries.js to populate. - require("script_entries/free_libraries").init(); - this.writeCacheToDB(callback); - }, - - /** - * writes the contents of scriptsCached to the persistent - * JSON file. - */ - writeCacheToDB: function (callback) { - console.debug("writing to db"); - data = scriptsCached.getCacheForWriting(); - json = JSON.stringify(data); - - // make json file smaller. - var re = new RegExp( - AUTHOR_REASON.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'); - json = json.replace(re, "[freelib]"); - - var rc = JSON.stringify(relationChecker()); - re = new RegExp(rc.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'); - json = json.replace(re, "\"[rl]\""); - //console.debug("this.data is now", this.data); - this.write(callback, json); - }, - generateCacheFromDB: function (callback) { - if (typeof callback === 'undefined') { - callback = function () { - // nothing to do. - }; - } - this.read(function (data) { - scriptsCached.bulkImportCache(data); - }); - }, - write: function (onDataWritten, json) { - - this.init(); - var str; - if (typeof json === 'undefined') { - str = JSON.stringify(this.data); - } else { - // we are passing json already formatted. - str = json; - } - var ostream = FileUtils.openSafeFileOutputStream(this.file); - var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - var istream = converter.convertToInputStream(str); - // The last argument (the callback) is optional. - NetUtil.asyncCopy(istream, ostream, function(status) { - if (!components.isSuccessCode(status)) { - // Handle error! - return; - } - if (!onDataWritten) { - console.debug("onDataWritten is not defined"); - onDataWritten = function () { - console.debug("onDataWritten dummy callback triggered"); - }; - } - // Data has been written to the file. - onDataWritten(); - }); - }, - - /** - * getEntry -- Returns a storage entry if it is present. - */ - getEntry: function (hash) { - var entry = this.data[hash]; - if (entry) { - if (entry.result === '[freelib]') { - entry.result = { - 'type': 4, - 'reason': 'This script has been tagged as free ' + - 'software by LibreJS authors.' - }; - } - entry.relationChecker = rc; - return entry; - } - return false; - } -}; - -exports.librejsStorage = librejsStorage; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui.js @@ -1,188 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -let data = require("sdk/self").data; -let panel = require('sdk/panel'); -let tabs = require("sdk/tabs"); -let {getMostRecentBrowserWindow} = require('sdk/window/utils'); -let {ToggleButton} = require('sdk/ui/button/toggle'); - -let settings_tab = require('settings/settings_tab'); -let allowedRef = require("http_observer/allowed_referrers").allowedReferrers; -let urlHandler = require("url_handler/url_handler"); -let removedScripts = require("script_entries/removed_scripts").removedScripts; -let acceptedScripts = require("script_entries/accepted_scripts") - .acceptedScripts; -let jsLabelsPagesVisited = require('html_script_finder/web_labels/js_web_labels') - .jsLabelsPagesVisited; -let dryRunScripts = require("script_entries/dryrun_scripts").dryRunScripts; -let types = require("js_checker/constant_types"); -const removeHashCallback = require("js_checker/js_checker").removeHashCallback; - -// move to sub-module later -const scriptsCached = require("script_entries/scripts_cache").scriptsCached; - -function generateDataURI (encodedText) { - return "data:text/html;charset=UTF-8;base64," + encodedText; -} - -/** - * UI - * - * A singleton that starts the user interface content scripts. - */ -let UI = exports.UI = { - init: function() { - var mainPanel = panel.Panel({ - contentURL: data.url('display_panel/content/display-panel.html'), - width: 800, - height: 500, - contentScriptFile: [ - data.url('settings/third-party/jquery/jquery.min.js'), - data.url('display_panel/main_panel.js') - ], - onShow: this.showPanelContent, - onHide: function() { - toggleButton.state('window', { checked: false }); - } - }); - - mainPanel.port.on('hideMainPanel', function () { - mainPanel.hide(); - }); - - mainPanel.port.on('allowAllClicked', function (url) { - url = urlHandler.removeFragment(url); - allowedRef.addPage(url); - tabs.activeTab.reload(); - }); - - mainPanel.port.on('disallowAllClicked', function (url) { - console.debug('url is', url); - url = urlHandler.removeFragment(url); - console.debug('before clear, url is in allowedRef', - allowedRef.urlInAllowedReferrers(url)); - allowedRef.clearSinglePageEntry(url); - console.debug('after clear, url is in allowedRef', - allowedRef.urlInAllowedReferrers(url)); - mainPanel.hide(); - tabs.activeTab.reload(); - }); - - mainPanel.port.on('openInTab', function (text) { - var str = generateDataURI(text); - tabs.open(str); - mainPanel.hide(); - }); - - mainPanel.port.on('whitelistByHash', function( - hash, url, name, reason - ) { - console.debug("hash is", hash); - url = urlHandler.removeFragment(url); - /* var cached_result = scriptsCached.isCached(hash); - if (cached_results) { - reason = cached_result['reason']; - }*/ - scriptsCached.addEntryByHash( - hash, types.whitelisted(reason), {}, true, url); - }); - - mainPanel.port.on('removeFromWhitelistByHash', function (hash) { - scriptsCached.removeEntryByHash(hash); - removeHashCallback(hash); - }); - - mainPanel.port.on('openSesame', function () { - // open the settings tab. - settings_tab.settingsManager.open(); - mainPanel.hide(); - }); - - var toggleButton = ToggleButton({ - id: 'librejs-toggle-switch', - label: 'LibreJS', - icon: { - '16': './widget/images/librejs.png', - '32': './widget/images/librejs-32.png', - '64': './widget/images/librejs-64.png' - }, - panel: mainPanel, - onChange: function(state) { - if (state.checked) { - mainPanel.show({ - position: toggleButton - }); - } - } - }); - - var menuitem = require("menuitems").Menuitem({ - id: 'librejs_settings', - menuid: 'menu_ToolsPopup', - label: 'LibreJS Whitelist', - onCommand: function() { - settings_tab.settingsManager.open(); - }, - insertBefore: "menu_pageInfo" - }); - }, - - showPanelContent: function() { - let that = this; - var message, externalEntries, - externalScripts, urlTabIndex, tabData; - - var worker = tabs.activeTab.attach({ - contentScriptFile: [ - data.url('complain/contact_regex.js'), - data.url('complain/link_types.js'), - data.url('settings/third-party/jquery/jquery.min.js'), - data.url('complain/contact_finder.js'), - data.url('complain/pagemod_finder.js'), - data.url('script_detector/script_detector.js') - ], - contentScriptWhen: 'ready', - onMessage: function(respData) { - var url = urlHandler.removeFragment(tabs.activeTab.url); - - if (respData.event === 'scriptsFetched') { - var scriptsData = { - 'jsLabelsPagesVisited': jsLabelsPagesVisited, - 'removed': removedScripts.getScripts(url), - 'accepted': acceptedScripts.getScripts(url), - 'dryRun': dryRunScripts.getScripts(url) - }; - that.postMessage({ - 'pageURL': url, - 'urlData': scriptsData, - 'isAllowed': allowedRef.urlInAllowedReferrers(url) - }); - worker.port.emit('pageUrl', url); - } else { - that.postMessage(respData); - } - } - }); - } -}; - -UI.init(); diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui/notification.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui/notification.js @@ -1,78 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -// this module is used to display a notification when LibreJS -// is running to inform the user it is indeed busy working. -const timer = require("sdk/timers"); -const self = require("sdk/self"); -const isDisplayNotifications = require("addon_management/prefchange") - .isDisplayNotifications; - -exports.createCriticalNotification = function (text) { - if (text === undefined) { - text = ""; - } - var self = require('sdk/self'); - var notif = require("notification-box").NotificationBox({ - 'value': 'librejs-critical-notification-js-web-labels', - 'label': text, - 'priority': 'CRITICAL_LOW', - 'image': self.data.url("assets/images/torchy2.png"), - }); - return notif; -}; - -var fakeNotification = { - 'close': function () { - return; - } -}; - -exports.createNotification = function (jsValue) { - if (!isDisplayNotifications()) { - return fakeNotification; - } - if (jsValue === undefined) { - jsValue = ""; - } - var self = require('sdk/self'); - var notif = require("notification-box").NotificationBox({ - 'value': 'librejs-message', - 'label': 'LibreJS is analyzing: ' + jsValue + " ...", - 'priority': 'INFO_LOW', - 'image': self.data.url("assets/images/torchy2.png"), - /*'buttons': [{'label': "Fine", - 'onClick': function () { }}]*/ - }); - timer.setTimeout(function () { - // ensure notifications are ALWAYS removed at some point. - console.debug("removing after 2 seconds"); - try { - var n = notif.notificationbox - .getNotificationWithValue('librejs-message'); - n.close(); - } catch(x) { - // do nothing - } - }, 2000); - return notif; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui/script_panel.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui/script_panel.js @@ -1,75 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -var urlHandler = require("url_handler/url_handler"); - -/** - * addScriptsToPanelList - * - * Looks for scripts that are either valid or flagged with libreJS - * - */ -exports.addScriptsToPanelList = function (url, respData) { - - var panelRemovedScripts = []; - var panelAcceptedScripts = []; - var panelDryRunScripts = []; - - // use url. remove fragment. - url = urlHandler.removeFragment(url); - var contents, i, reason; - - for (i = 0; i < respData.value.blocked.length; i++) { - // if external script only. - pathToUrl(respData.value.blocked[i], url); - panelRemovedScripts.push(respData.value.blocked[i]); - } - - for (i = 0; i < respData.value.accepted.length; i++) { - - // if external script only. - pathToUrl(respData.value.accepted[i], url); - panelAcceptedScripts.push(respData.value.accepted[i]); - } - for (i = 0; i < respData.value.dryRun.length; i++) { - // if external script only. - pathToUrl(respData.value.dryRun[i], url); - panelDryRunScripts.push(respData.value.dryRun[i]); - } - - return {'removed': panelRemovedScripts, - 'accepted': panelAcceptedScripts, - 'dryRun': panelDryRunScripts}; -}; - - -/** - * pathToUrl - * - * convert a relative path to a url. - * - */ -var pathToUrl = function (scriptEntry, url) { - if (scriptEntry.inline === false) { - scriptEntry.url = urlHandler.resolve(url, scriptEntry.url); - } -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui/ui_info.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/ui/ui_info.js @@ -1,204 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -// page mod executing content script at every page load. - -var data = require("sdk/self").data; -var pageMod = require("sdk/page-mod"); -var urlHandler = require("url_handler/url_handler"); -var pageWorker = require("sdk/page-worker"); -var tabs = require("sdk/tabs"); -var prefs = require("addon_management/prefchange"); - -// contain list of recently found contact links or email addresses. -var contactList = {}; - -// constants. Also available in lib/ui_info.js -const CERTAIN_EMAIL_ADDRESS_FOUND = 'certainEmailAddressFound'; -const UNCERTAIN_EMAIL_ADDRESS_FOUND = 'uncertainEmailAddresFound'; - -// Looking for contact links -const CERTAIN_LINK_FOUND = 'certainLinkFound'; -const PROBABLE_LINK_FOUND = 'probableLinkFound'; -const UNCERTAIN_LINK_FOUND = 'uncertainLinkFound'; -const LINK_NOT_FOUND = 'contactLinkNotFound'; - -// Looking for identi.ca and twitter accounts. -const TWITTER_LINK_FOUND = 'twitterLinkFound'; -const IDENTICA_LINK_FOUND = 'identicaLinkFound'; - -// phone number and address -const PHONE_NUMBER_FOUND = 'phoneNumberFound'; -const SNAIL_ADDRESS_FOUND = 'snailAddressFound'; - -/** - * main pageMod. - * Find blocked script in all pages being opened. - * Launch the scripts that search for a complaint contact. - * - */ - -pageMod.PageMod({ - include: ['file://*', '*', 'data:*', 'about:*'], - contentScriptWhen: 'end', - - contentScriptFile: [ - data.url('complain/contact_regex.js'), - data.url('complain/link_types.js'), - data.url('settings/third-party/jquery/jquery.min.js'), - data.url('complain/contact_finder.js'), - data.url('complain/pagemod_finder.js'), - data.url('script_detector/script_detector.js') - ], - - onAttach: function onAttach(worker) { - if (worker.tab !== undefined && prefs.isComplaintTab()) { - // this is a tab. - if (!foundInContactList(worker.url)) { - // the hostname doesn't appear in the object literal. - // run script fetching/complaint feature if applicable. - tabProcess(worker); - } else { - worker.postMessage(foundInContactList(worker.url)); - } - } - } -}); - -/** - * foundInContactList - * - * Provides link if contact link is found for given url, or else - * false. - */ -var foundInContactList = function (url) { - var hostname = urlHandler.getHostname(url); - if (contactList[hostname] !== undefined) { - return contactList[hostname]; - } else { - return false; - } -}; - -/** - * tabProcess - * Find blocked/accepted scripts, prepare - * display panel and complaint panel. - */ -var tabProcess = function (worker) { - var visitedUrl = {}; - - // webmaster email is better than a webpage. - worker.emailFound = false; - var modUrl = '', - searchUrl = ''; - - modUrl = worker.url; - console.debug('pagemod triggered'); - - worker.port.emit('prefs', { - complaintEmailSubject: prefs.complaintEmailSubject(), - complaintEmailBody: prefs.complaintEmailBody() - }); - - // send local path to complain button graphic. - worker.port.emit('assetsUri', - {'event': 'assets-uri', - 'value': data.url('assets/')}); - worker.port.emit('pageUrl', - {'event': 'page-url', - 'value': modUrl}); - - worker.on('message', function (respData) { - console.debug('worker is receiving a message', respData.event); - var pw; - - worker.on('detach', function () { - console.debug('detaching worker'); - if (pw) { - pw.destroy(); - } - }); - if (respData.contact !== undefined) { - // pass the message to the complaint display panel. - worker.port.emit('complaintLinkFound', respData); - } else if (respData.event === 'complaintSearch') { - if (worker.tab) { - console.debug('worker tab url', worker.tab.url); - } - if (!(respData.urlSearch.linkValue in visitedUrl)) { - visitedUrl[respData.urlSearch.linkValue] = 1; - respData.urlSearch.linkValue = urlHandler.addFragment( - respData.urlSearch.linkValue, 'librejs=true'); - pw = searchSecondLevelPage( - this, respData.urlSearch.linkValue, this.url); - } - // currently not needed. - /*else { - console.debug(respData.urlSearch.linkValue, 'already visited'); - }*/ - } - }); -}; - -var searchSecondLevelPage = function( - worker, urlToSearch, originalUrl) { - return; - var originalWorker = worker; - - console.debug('searchSecondLevelPage'); - console.debug(urlToSearch, 'and', originalUrl); - - if (urlHandler.haveSameHostname(urlToSearch, originalUrl)) { - return pageWorker.Page({ - contentURL: urlToSearch, - contentScriptFile: [ - data.url('complain/contact_regex.js'), - data.url('complain/link_types.js'), - data.url('settings/third-party/jquery/jquery.min.js'), - data.url('complain/contact_finder.js'), - data.url('complain/worker_finder.js') - ], - contentScriptWhen: "end", - onMessage: function (respData) { - console.debug(JSON.stringify(respData)); - console.debug(originalWorker.url); - originalWorker.postMessage(respData); - - if (respData.event === 'destroy') { - try { - console.debug('destroying worker', this.contentURL); - this.destroy(); - } catch (e) { - console.debug('in worker', e); - } - } - } - }); - } -}; - -exports.testModule = { - 'contactList': contactList, - 'foundInContactList': foundInContactList, - 'tabProcess': tabProcess -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_url.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_url.js @@ -1,691 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var punycode = require('url_handler/node_punycode'); - -exports.parse = urlParse; -exports.resolve = urlResolve; -exports.resolveObject = urlResolveObject; -exports.format = urlFormat; - -exports.Url = Url; - -function Url() { - this.protocol = null; - this.slashes = null; - this.auth = null; - this.host = null; - this.port = null; - this.hostname = null; - this.hash = null; - this.search = null; - this.query = null; - this.pathname = null; - this.path = null; - this.href = null; -} - -// Reference: RFC 3986, RFC 1808, RFC 2396 - -// define these here so at least they only have to be -// compiled once on the first module load. -var protocolPattern = /^([a-z0-9.+-]+:)/i, - portPattern = /:[0-9]*$/, - - // RFC 2396: characters reserved for delimiting URLs. - // We actually just auto-escape these. - delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], - - // RFC 2396: characters not allowed for various reasons. - unwise = ['{', '}', '|', '\\', '^', '~', '`'].concat(delims), - - // Allowed by RFCs, but cause of XSS attacks. Always escape these. - autoEscape = ['\''].concat(delims), - // Characters that are never ever allowed in a hostname. - // Note that any invalid chars are also handled, but these - // are the ones that are *expected* to be seen, so we fast-path - // them. - nonHostChars = ['%', '/', '?', ';', '#'] - .concat(unwise).concat(autoEscape), - hostEndingChars = ['/', '?', '#'], - hostnameMaxLen = 255, - hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/, - hostnamePartStart = /^([a-z0-9A-Z_-]{0,63})(.*)$/, - // protocols that can allow "unsafe" and "unwise" chars. - unsafeProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that never have a hostname. - hostlessProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that always contain a // bit. - slashedProtocol = { - 'http': true, - 'https': true, - 'ftp': true, - 'gopher': true, - 'file': true, - 'http:': true, - 'https:': true, - 'ftp:': true, - 'gopher:': true, - 'file:': true - }, - querystring = require('url_handler/node_querystring'); - -function urlParse(url, parseQueryString, slashesDenoteHost) { - if (url && typeof(url) === 'object' && url instanceof Url) return url; - - var u = new Url; - u.parse(url, parseQueryString, slashesDenoteHost); - return u; -} - -Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { - if (typeof url !== 'string') { - throw new TypeError("Parameter 'url' must be a string, not " + typeof url); - } - - // Copy chrome, IE, opera backslash-handling behavior. - // See: https://code.google.com/p/chromium/issues/detail?id=25916 - var hashSplit = url.split('#'); - hashSplit[0] = hashSplit[0].replace(/\\/g, '/'); - url = hashSplit.join('#'); - - var rest = url; - - // trim before proceeding. - // This is to support parse stuff like " http://foo.com \n" - rest = rest.trim(); - - var proto = protocolPattern.exec(rest); - if (proto) { - proto = proto[0]; - var lowerProto = proto.toLowerCase(); - this.protocol = lowerProto; - rest = rest.substr(proto.length); - } - - // figure out if it's got a host - // user@server is *always* interpreted as a hostname, and url - // resolution will treat //foo/bar as host=foo,path=bar because that's - // how the browser resolves relative URLs. - if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { - var slashes = rest.substr(0, 2) === '//'; - if (slashes && !(proto && hostlessProtocol[proto])) { - rest = rest.substr(2); - this.slashes = true; - } - } - - if (!hostlessProtocol[proto] && - (slashes || (proto && !slashedProtocol[proto]))) { - - // there's a hostname. - // the first instance of /, ?, ;, or # ends the host. - // - // If there is an @ in the hostname, then non-host chars *are* allowed - // to the left of the last @ sign, unless some host-ending character - // comes *before* the @-sign. - // URLs are obnoxious. - // - // ex: - // http://a@b@c/ => user:a@b host:c - // http://a@b?@c => user:a host:c path:/?@c - - // v0.12 TODO(isaacs): This is not quite how Chrome does things. - // Review our test case against browsers more comprehensively. - - // find the first instance of any hostEndingChars - var hostEnd = -1; - for (var i = 0; i < hostEndingChars.length; i++) { - var hec = rest.indexOf(hostEndingChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - - // at this point, either we have an explicit point where the - // auth portion cannot go past, or the last @ char is the decider. - var auth, atSign; - if (hostEnd === -1) { - // atSign can be anywhere. - atSign = rest.lastIndexOf('@'); - } else { - // atSign must be in auth portion. - // http://a@b/c@d => host:b auth:a path:/c@d - atSign = rest.lastIndexOf('@', hostEnd); - } - - // Now we have a portion which is definitely the auth. - // Pull that off. - if (atSign !== -1) { - auth = rest.slice(0, atSign); - rest = rest.slice(atSign + 1); - this.auth = decodeURIComponent(auth); - } - - // the host is the remaining to the left of the first non-host char - hostEnd = -1; - for (var i = 0; i < nonHostChars.length; i++) { - var hec = rest.indexOf(nonHostChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - // if we still have not hit it, then the entire thing is a host. - if (hostEnd === -1) - hostEnd = rest.length; - - this.host = rest.slice(0, hostEnd); - rest = rest.slice(hostEnd); - - // pull out port. - this.parseHost(); - - // we've indicated that there is a hostname, - // so even if it's empty, it has to be present. - this.hostname = this.hostname || ''; - - // if hostname begins with [ and ends with ] - // assume that it's an IPv6 address. - var ipv6Hostname = this.hostname[0] === '[' && - this.hostname[this.hostname.length - 1] === ']'; - - // validate a little. - if (!ipv6Hostname) { - var hostparts = this.hostname.split(/\./); - for (var i = 0, l = hostparts.length; i < l; i++) { - var part = hostparts[i]; - if (!part) continue; - if (!part.match(hostnamePartPattern)) { - var newpart = ''; - for (var j = 0, k = part.length; j < k; j++) { - if (part.charCodeAt(j) > 127) { - // we replace non-ASCII char with a temporary placeholder - // we need this to make sure size of hostname is not - // broken by replacing non-ASCII by nothing - newpart += 'x'; - } else { - newpart += part[j]; - } - } - // we test again with ASCII char only - if (!newpart.match(hostnamePartPattern)) { - var validParts = hostparts.slice(0, i); - var notHost = hostparts.slice(i + 1); - var bit = part.match(hostnamePartStart); - if (bit) { - validParts.push(bit[1]); - notHost.unshift(bit[2]); - } - if (notHost.length) { - rest = '/' + notHost.join('.') + rest; - } - this.hostname = validParts.join('.'); - break; - } - } - } - } - - if (this.hostname.length > hostnameMaxLen) { - this.hostname = ''; - } else { - // hostnames are always lower case. - this.hostname = this.hostname.toLowerCase(); - } - - if (!ipv6Hostname) { - // IDNA Support: Returns a punycoded representation of "domain". - // It only converts parts of the domain name that - // have non-ASCII characters, i.e. it doesn't matter if - // you call it with a domain that already is ASCII-only. - this.hostname = punycode.toASCII(this.hostname); - } - - var p = this.port ? ':' + this.port : ''; - var h = this.hostname || ''; - this.host = h + p; - this.href += this.host; - - // strip [ and ] from the hostname - // the host field still retains them, though - if (ipv6Hostname) { - this.hostname = this.hostname.substr(1, this.hostname.length - 2); - if (rest[0] !== '/') { - rest = '/' + rest; - } - } - } - - // now rest is set to the post-host stuff. - // chop off any delim chars. - if (!unsafeProtocol[lowerProto]) { - - // First, make 100% sure that any "autoEscape" chars get - // escaped, even if encodeURIComponent doesn't think they - // need to be. - for (var i = 0, l = autoEscape.length; i < l; i++) { - var ae = autoEscape[i]; - var esc = encodeURIComponent(ae); - if (esc === ae) { - esc = escape(ae); - } - rest = rest.split(ae).join(esc); - } - } - - - // chop off from the tail first. - var hash = rest.indexOf('#'); - if (hash !== -1) { - // got a fragment string. - this.hash = rest.substr(hash); - rest = rest.slice(0, hash); - } - var qm = rest.indexOf('?'); - if (qm !== -1) { - this.search = rest.substr(qm); - this.query = rest.substr(qm + 1); - if (parseQueryString) { - this.query = querystring.parse(this.query); - } - rest = rest.slice(0, qm); - } else if (parseQueryString) { - // no query string, but parseQueryString still requested - this.search = ''; - this.query = {}; - } - if (rest) this.pathname = rest; - if (slashedProtocol[lowerProto] && - this.hostname && !this.pathname) { - this.pathname = '/'; - } - - //to support http.request - if (this.pathname || this.search) { - var p = this.pathname || ''; - var s = this.search || ''; - this.path = p + s; - } - - // finally, reconstruct the href based on what has been validated. - this.href = this.format(); - return this; -}; - -// format a parsed object into a url string -function urlFormat(obj) { - // ensure it's an object, and not a string url. - // If it's an obj, this is a no-op. - // this way, you can call url_format() on strings - // to clean up potentially wonky urls. - if (typeof(obj) === 'string') obj = urlParse(obj); - if (!(obj instanceof Url)) return Url.prototype.format.call(obj); - return obj.format(); -} - -Url.prototype.format = function() { - var auth = this.auth || ''; - if (auth) { - auth = encodeURIComponent(auth); - auth = auth.replace(/%3A/i, ':'); - auth += '@'; - } - - var protocol = this.protocol || '', - pathname = this.pathname || '', - hash = this.hash || '', - host = false, - query = ''; - - if (this.host) { - host = auth + this.host; - } else if (this.hostname) { - host = auth + (this.hostname.indexOf(':') === -1 ? - this.hostname : - '[' + this.hostname + ']'); - if (this.port) { - host += ':' + this.port; - } - } - - if (this.query && typeof this.query === 'object' && - Object.keys(this.query).length) { - query = querystring.stringify(this.query); - } - - var search = this.search || (query && ('?' + query)) || ''; - - if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - - // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. - // unless they had them to begin with. - if (this.slashes || - (!protocol || slashedProtocol[protocol]) && host !== false) { - host = '//' + (host || ''); - if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; - } else if (!host) { - host = ''; - } - - if (hash && hash.charAt(0) !== '#') hash = '#' + hash; - if (search && search.charAt(0) !== '?') search = '?' + search; - - pathname = pathname.replace(/[?#]/g, function(match) { - return encodeURIComponent(match); - }); - search = search.replace('#', '%23'); - - return protocol + host + pathname + search + hash; -}; - -function urlResolve(source, relative) { - return urlParse(source, false, true).resolve(relative); -} - -Url.prototype.resolve = function(relative) { - return this.resolveObject(urlParse(relative, false, true)).format(); -}; - -function urlResolveObject(source, relative) { - if (!source) return relative; - return urlParse(source, false, true).resolveObject(relative); -} - -Url.prototype.resolveObject = function(relative) { - if (typeof relative === 'string') { - var rel = new Url(); - rel.parse(relative, false, true); - relative = rel; - } - - var result = new Url(); - Object.keys(this).forEach(function(k) { - result[k] = this[k]; - }, this); - - // hash is always overridden, no matter what. - // even href="" will remove it. - result.hash = relative.hash; - - // if the relative url is empty, then there's nothing left to do here. - if (relative.href === '') { - result.href = result.format(); - return result; - } - - // hrefs like //foo/bar always cut to the protocol. - if (relative.slashes && !relative.protocol) { - // take everything except the protocol from relative - Object.keys(relative).forEach(function(k) { - if (k !== 'protocol') - result[k] = relative[k]; - }); - - //urlParse appends trailing / to urls like http://www.example.com - if (slashedProtocol[result.protocol] && - result.hostname && !result.pathname) { - result.path = result.pathname = '/'; - } - - result.href = result.format(); - return result; - } - - if (relative.protocol && relative.protocol !== result.protocol) { - // if it's a known url protocol, then changing - // the protocol does weird things - // first, if it's not file:, then we MUST have a host, - // and if there was a path - // to begin with, then we MUST have a path. - // if it is file:, then the host is dropped, - // because that's known to be hostless. - // anything else is assumed to be absolute. - if (!slashedProtocol[relative.protocol]) { - Object.keys(relative).forEach(function(k) { - result[k] = relative[k]; - }); - result.href = result.format(); - return result; - } - - result.protocol = relative.protocol; - if (!relative.host && !hostlessProtocol[relative.protocol]) { - var relPath = (relative.pathname || '').split('/'); - while (relPath.length && !(relative.host = relPath.shift())); - if (!relative.host) relative.host = ''; - if (!relative.hostname) relative.hostname = ''; - if (relPath[0] !== '') relPath.unshift(''); - if (relPath.length < 2) relPath.unshift(''); - result.pathname = relPath.join('/'); - } else { - result.pathname = relative.pathname; - } - result.search = relative.search; - result.query = relative.query; - result.host = relative.host || ''; - result.auth = relative.auth; - result.hostname = relative.hostname || relative.host; - result.port = relative.port; - // to support http.request - if (result.pathname || result.search) { - var p = result.pathname || ''; - var s = result.search || ''; - result.path = p + s; - } - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; - } - - var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), - isRelAbs = ( - relative.host || - relative.pathname && relative.pathname.charAt(0) === '/' - ), - mustEndAbs = (isRelAbs || isSourceAbs || - (result.host && relative.pathname)), - removeAllDots = mustEndAbs, - srcPath = result.pathname && result.pathname.split('/') || [], - relPath = relative.pathname && relative.pathname.split('/') || [], - psychotic = result.protocol && !slashedProtocol[result.protocol]; - - // if the url is a non-slashed url, then relative - // links like ../.. should be able - // to crawl up to the hostname, as well. This is strange. - // result.protocol has already been set by now. - // Later on, put the first path part into the host field. - if (psychotic) { - result.hostname = ''; - result.port = null; - if (result.host) { - if (srcPath[0] === '') srcPath[0] = result.host; - else srcPath.unshift(result.host); - } - result.host = ''; - if (relative.protocol) { - relative.hostname = null; - relative.port = null; - if (relative.host) { - if (relPath[0] === '') relPath[0] = relative.host; - else relPath.unshift(relative.host); - } - relative.host = null; - } - mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); - } - - if (isRelAbs) { - // it's absolute. - result.host = (relative.host || relative.host === '') ? - relative.host : result.host; - result.hostname = (relative.hostname || relative.hostname === '') ? - relative.hostname : result.hostname; - result.search = relative.search; - result.query = relative.query; - srcPath = relPath; - // fall through to the dot-handling below. - } else if (relPath.length) { - // it's relative - // throw away the existing file, and take the new path instead. - if (!srcPath) srcPath = []; - srcPath.pop(); - srcPath = srcPath.concat(relPath); - result.search = relative.search; - result.query = relative.query; - } else if (relative.search !== null && relative.search !== undefined) { - // just pull out the search. - // like href='?foo'. - // Put this after the other two cases because it simplifies the booleans - if (psychotic) { - result.hostname = result.host = srcPath.shift(); - //occationaly the auth can get stuck only in host - //this especialy happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - result.search = relative.search; - result.query = relative.query; - //to support http.request - if (result.pathname !== null || result.search !== null) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.href = result.format(); - return result; - } - - if (!srcPath.length) { - // no path at all. easy. - // we've already handled the other stuff above. - result.pathname = null; - //to support http.request - if (result.search) { - result.path = '/' + result.search; - } else { - result.path = null; - } - result.href = result.format(); - return result; - } - - // if a url ENDs in . or .., then it must get a trailing slash. - // however, if it ends in anything else non-slashy, - // then it must NOT get a trailing slash. - var last = srcPath.slice(-1)[0]; - var hasTrailingSlash = ( - (result.host || relative.host) && (last === '.' || last === '..') || - last === ''); - - // strip single dots, resolve double dots to parent dir - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = srcPath.length; i >= 0; i--) { - last = srcPath[i]; - if (last == '.') { - srcPath.splice(i, 1); - } else if (last === '..') { - srcPath.splice(i, 1); - up++; - } else if (up) { - srcPath.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (!mustEndAbs && !removeAllDots) { - for (; up--; up) { - srcPath.unshift('..'); - } - } - - if (mustEndAbs && srcPath[0] !== '' && - (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { - srcPath.unshift(''); - } - - if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { - srcPath.push(''); - } - - var isAbsolute = srcPath[0] === '' || - (srcPath[0] && srcPath[0].charAt(0) === '/'); - - // put the host back - if (psychotic) { - result.hostname = result.host = isAbsolute ? '' : - srcPath.length ? srcPath.shift() : ''; - //occationaly the auth can get stuck only in host - //this especialy happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - - mustEndAbs = mustEndAbs || (result.host && srcPath.length); - - if (mustEndAbs && !isAbsolute) { - srcPath.unshift(''); - } - - if (!srcPath.length) { - result.pathname = null; - result.path = null; - } else { - result.pathname = srcPath.join('/'); - } - - //to support request.http - if (result.pathname !== null || result.search !== null) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.auth = relative.auth || result.auth; - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; -}; - -Url.prototype.parseHost = function() { - var host = this.host; - var port = portPattern.exec(host); - if (port) { - port = port[0]; - if (port !== ':') { - this.port = port.substr(1); - } - host = host.substr(0, host.length - port.length); - } - if (host) this.hostname = host; -}; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/url_handler.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/url_handler.js @@ -1,116 +0,0 @@ -/** - * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. - * * - * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros - * Copyright (C) 2014, 2015 Nik Nyby - * - * This file is part of GNU LibreJS. - * - * GNU LibreJS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNU LibreJS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * url_handler - * A module using the url tool from Node.js to perform operations on - * urls at various spots (tabs, caching, ...) in the add-on. - * - */ - -// node.js url module. Makes it easier to resolve -// urls in that datauri loaded dom -var nodeJsUrl = require("url_handler/node_url"); - -var urlUtils = { - getFragment: function (url) { - var parse = nodeJsUrl.parse(url); - if (parse.hash !== undefined) { - return(parse.hash); - } - }, - - removeFragment: function (url) { - var parse = nodeJsUrl.parse(url); - if (parse.hash !== undefined) { - // Amazon track package bug fix. - // when url has query string and fragment - // the add-on wouldn't remove cache entry - // properly. - delete parse.hash; - } - return nodeJsUrl.format(parse); - }, - - addFragment: function (url, query) { - var parse = nodeJsUrl.parse(url); - - // replace hash if it exists. - parse.hash = '#' + query; - - return nodeJsUrl.format(parse); - }, - - addQuery: function (url, query) { - var parse = nodeJsUrl.parse(url); - console.debug('my parse search', parse.search); - if (parse.search === undefined) { - parse.search = '?' + query; - } else { - parse.search = parse.search + '&' + query; - console.debug('parse search is now' + parse.search); - } - return nodeJsUrl.format(parse); - }, - - getHostname: function (url) { - return nodeJsUrl.parse(url).hostname; - }, - - /** - * remove www from hostname. - */ - removeWWW: function (str) { - if (str !== undefined) { - return str.replace("www.", "", 'i'); - } - return ""; - }, - - /** - * - * haveSameHostname - * Compare that two urls have the same hostname. - * - */ - haveSameHostname: function (url1, url2) { - try { - var host1 = this.removeWWW(this.getHostname(url1)).toLowerCase(); - var host2 = this.removeWWW(this.getHostname(url2)).toLowerCase(); - return host1 === host2; - } catch (x) { - console.debug('error with url_handler', x, x.fileName, x.lineNumber); - } - } -}; - -exports.parse = nodeJsUrl.parse; -exports.resolve = nodeJsUrl.resolve; -exports.resolveObject = nodeJsUrl.resolveObject; -exports.format = nodeJsUrl.format; -exports.removeFragment = urlUtils.removeFragment; -exports.addQuery = urlUtils.addQuery; -exports.getFragment = urlUtils.getFragment; -exports.addFragment = urlUtils.addFragment; -exports.getHostname = urlUtils.getHostname; -exports.haveSameHostname = urlUtils.haveSameHostname; -exports.removeWWW = urlUtils.removeWWW; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/menuitems/lib/menuitems.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/menuitems/lib/menuitems.js @@ -1,195 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const windowUtils = require("sdk/deprecated/window-utils"); -const { Class } = require("sdk/core/heritage"); -const { validateOptions } = require("sdk/deprecated/api-utils"); -const { on, emit, once, off } = require("sdk/event/core"); -const { isBrowser } = require("sdk/window/utils"); -const { EventTarget } = require('sdk/event/target'); -const { unload } = require("unload+"); - -const menuitemNS = require("sdk/core/namespace").ns(); -const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - -function MenuitemOptions(options) { - return validateOptions(options, { - id: { is: ['string'] }, - menuid: { is: ['undefined', 'string'] }, - insertbefore: { is: ['undefined', 'string', 'object'] }, - label: { is: ["string"] }, - disabled: { is: ["undefined", "boolean"], map: function(v) !!v}, - accesskey: { is: ["undefined", "string"] }, - key: { is: ["undefined", "string"] }, - checked: { is: ['undefined', 'boolean'] }, - className: { is: ["undefined", "string"] }, - onCommand: { is: ['undefined', 'function'] } - }); -} - -let Menuitem = Class({ - extends: EventTarget, - initialize: function(options) { - options = menuitemNS(this).options = MenuitemOptions(options); - EventTarget.prototype.initialize.call(this, options); - - menuitemNS(this).destroyed = false; - menuitemNS(this).unloaders = []; - menuitemNS(this).menuitems = addMenuitems(this, options).menuitems; - }, - get id() menuitemNS(this).options.id, - get label() menuitemNS(this).options.label, - set label(val) updateProperty(this, 'label', val), - get checked() menuitemNS(this).options.checked, - set checked(val) updateProperty(this, 'checked', !!val), - get disabled() menuitemNS(this).options.disabled, - set disabled(val) updateProperty(this, 'disabled', !!val), - get key() menuitemNS(this).options.key, - set key(val) updateProperty(this, 'key', val), - clone: function (overwrites) { - let opts = Object.clone(menuitemNS(this).options); - for (let key in overwrites) { - opts[key] = ovrewrites[key]; - } - return Menuitem(opts); - }, - get menuid() menuitemNS(this).options.menuid, - set menuid(val) { - let options = menuitemNS(this).options; - options.menuid = val; - - forEachMI(function(menuitem, i, $) { - updateMenuitemParent(menuitem, options, $); - }); - }, - destroy: function() { - if (!menuitemNS(this).destroyed) { - menuitemNS(this).destroyed = true; - menuitemNS(this).unloaders.forEach(function(u) u()); - menuitemNS(this).unloaders = null; - menuitemNS(this).menuitems = null; - } - return true; - } -}); - -function addMenuitems(self, options) { - let menuitems = []; - - // setup window tracker - windowUtils.WindowTracker({ - onTrack: function (window) { - if (!isBrowser(window) || menuitemNS(self).destroyed) return; - - // add the new menuitem to a menu - var menuitem = updateMenuitemAttributes( - window.document.createElementNS(NS_XUL, "menuitem"), options); - var menuitems_i = menuitems.push(menuitem) - 1; - - // add the menutiem to the ui - updateMenuitemParent(menuitem, options, function(id) window.document.getElementById(id)); - - menuitem.addEventListener("command", function() { - if (!self.disabled) - emit(self, 'command'); - }, true); - - // add unloader - let unloader = function unloader() { - menuitem.parentNode && menuitem.parentNode.removeChild(menuitem); - menuitems[menuitems_i] = null; - }; - menuitemNS(self).unloaders.push(function() { - remover(); - unloader(); - }); - let remover = unload(unloader, window); - } - }); - return {menuitems: menuitems}; -} - -function updateMenuitemParent(menuitem, options, $) { - // add the menutiem to the ui - if (Array.isArray(options.menuid)) { - let ids = options.menuid; - for (var len = ids.length, i = 0; i < len; i++) { - if (tryParent($(ids[i]), menuitem, options.insertbefore)) - return true; - } - } - else { - return tryParent($(options.menuid), menuitem, options.insertbefore); - } - return false; -} - -function updateMenuitemAttributes(menuitem, options) { - menuitem.setAttribute("id", options.id); - menuitem.setAttribute("label", options.label); - - if (options.accesskey) - menuitem.setAttribute("accesskey", options.accesskey); - - if (options.key) - menuitem.setAttribute("key", options.key); - - menuitem.setAttribute("disabled", !!options.disabled); - - if (options.image) { - menuitem.classList.add("menuitem-iconic"); - menuitem.style.listStyleImage = "url('" + options.image + "')"; - } - - if (options.checked) - menuitem.setAttribute('checked', options.checked); - - if (options.className) - options.className.split(/\s+/).forEach(function(name) menuitem.classList.add(name)); - - return menuitem; -} - -function updateProperty(menuitem, key, val) { - menuitemNS(menuitem).options[key] = val; - - forEachMI(function(menuitem) { - menuitem.setAttribute(key, val); - }, menuitem); - return val; -} - -function forEachMI(callback, menuitem) { - menuitemNS(menuitem).menuitems.forEach(function(mi, i) { - if (!mi) return; - callback(mi, i, function(id) mi.ownerDocument.getElementById(id)); - }); -} - -function tryParent(parent, menuitem, before) { - if (parent) parent.insertBefore(menuitem, insertBefore(parent, before)); - return !!parent; -} - -function insertBefore(parent, insertBefore) { - if (typeof insertBefore == "number") { - switch (insertBefore) { - case MenuitemExport.FIRST_CHILD: - return parent.firstChild; - } - return null; - } - else if (typeof insertBefore == "string") { - return parent.querySelector("#" + insertBefore); - } - return insertBefore; -} - -function MenuitemExport(options) { - return Menuitem(options); -} -MenuitemExport.FIRST_CHILD = 1; - -exports.Menuitem = MenuitemExport; diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/notification-box/lib/notification-box.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/notification-box/lib/notification-box.js @@ -1,129 +0,0 @@ -/* - * Copyrights Loic J. Duros 2012 - * lduros@member.fsf.org - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { Cc, Ci } = require("chrome"); -const { getMostRecentBrowserWindow } = require('sdk/window/utils'); -/* I haven't found this sort of validation functions in the SDK, -except for the deprecated api-utils module. */ -let isString = function (str) { - return typeof(str) == 'string' || str instanceof String; -}; - -let isArray = function (obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; -}; - -exports.NotificationBox = function (options) { - options = options || {}; - let mainWindow = getWindow(); - let nb = mainWindow.gBrowser.getNotificationBox(); - let notification, priority, label, image, value, buttons = []; - - if (options.value && isString(options.value)) { - notification = nb.getNotificationWithValue(options.value); - value = options.value; - } - else { - notification = nb.getNotificationWithValue(''); - value = ''; - } - - // Add label or create empty notification. - if (options.label && isString(options.label)) - label = options.label; - else - label = ""; - - // Set priority of the notification (from info low, to critical - // block. - if (options.priority && options.priority in PRIORITY) - priority = nb[PRIORITY[options.priority]]; - else - priority = nb[PRIORITY.INFO_LOW]; - - // Set a custom icon for the notification or use the regular info - // icon. - if (options.image && isString(options.image)) - image = options.image; - else - image = 'chrome://browser/skin/Info.png'; - - // Add buttons. - if (isArray(options.buttons)) { - for (let i = 0, length = options.buttons.length; i < length; i++) { - buttons.push(NotificationButton(options.buttons[i])); - } - } - else if (typeof(options.buttons) === 'object') { - // If it's not an array of buttons, then it should be a single button. - buttons.push(NotificationButton(options.buttons)); - } - else { - buttons = null; - } - - // add new notification to notificationbox. - nb.appendNotification(label, value, - image, - priority, buttons); - - return {'notificationbox': nb, 'notification': notification}; -}; - - - -var NotificationButton = function (options) { - - options = options || {}; - let accessKey, onClick, label, popup; - - if (options.accessKey) - accessKey = options.accessKey; - else - accessKey = ''; - - if (options.onClick) - onClick = options.onClick; - else - onClick = function () {}; - - if (options.label) - label = options.label; - else - label = ""; - - // no popup for now... maybe we can use a panel later. - popup = null; - - return {label: label, - accessKey: accessKey, - callback: onClick, - popup: popup}; - -}; - -const PRIORITY = { - 'INFO_LOW': 'PRIORITY_INFO_LOW', - 'INFO_MEDIUM': 'PRIORITY_INFO_MEDIUM', - 'INFO_HIGH': 'PRIORITY_INFO_HIGH', - 'WARNING_LOW': 'PRIORITY_WARNING_LOW', - 'WARNING_MEDIUM': 'PRIORITY_WARNING_MEDIUM', - 'WARNING_HIGH': 'PRIORITY_WARNING_HIGH', - 'CRITICAL_LOW': 'PRIORITY_CRITICAL_LOW', - 'CRITICAL_MEDIUM': 'PRIORITY_CRITICAL_MEDIUM', - 'CRITICAL_HIGH': 'PRIORITY_CRITICAL_HIGH', - 'CRITICAL_BLOCK': 'PRIORITY_CRITICAL_BLOCK' -}; - -let getWindow = function () { - return getMostRecentBrowserWindow(); -}; - -exports.PRIORITY = PRIORITY; - diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/vold-utils/lib/unload+.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/vold-utils/lib/unload+.js @@ -1,80 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const { Class } = require("sdk/core/heritage"); -const unloadNS = require("sdk/core/namespace").ns(); - -var Unloader = exports.Unloader = Class({ - initialize: function Unloader() { - let unloaders = unloadNS(this).unloaders = []; - - let unloadersUnlaod = unloadNS(this).unloadersUnlaod = function() { - unloaders.slice().forEach(function(u) u()); - unloaders.length = 0; - } - - require("sdk/system/unload").when(unloadersUnlaod); - }, - unload: function unload(callback, container) { - // Calling with no arguments runs all the unloader callbacks - if (callback == null) { - unloadNS(this).unloadersUnlaod(); - return null; - } - - var remover = removeUnloader.bind(null, unloader, unloadNS(this).unloaders); - - // The callback is bound to the lifetime of the container if we have one - if (container != null) { - // Remove the unloader when the container unloads - container.addEventListener("unload", remover, false); - - // Wrap the callback to additionally remove the unload listener - let origCallback = callback; - callback = function() { - container.removeEventListener("unload", remover, false); - origCallback(); - } - } - - // Wrap the callback in a function that ignores failures - function unloader() { - try { - callback(); - } - catch(e) { - console.error(e); - } - } - unloadNS(this).unloaders.push(unloader); - - // Provide a way to remove the unloader - return remover; - } -}); - -function removeUnloader(unloader, unloaders) { - let index = unloaders.indexOf(unloader); - if (index != -1) - unloaders.splice(index, 1); -} - -/** - * Save callbacks to run when unloading. Optionally scope the callback to a - * container, e.g., window. Provide a way to run all the callbacks. - * - * @usage unload(): Run all callbacks and release them. - * - * @usage unload(callback): Add a callback to run on unload. - * @param [function] callback: 0-parameter function to call on unload. - * @return [function]: A 0-parameter function that undoes adding the callback. - * - * @usage unload(callback, container) Add a scoped callback to run on unload. - * @param [function] callback: 0-parameter function to call on unload. - * @param [node] container: Remove the callback when this container unloads. - * @return [function]: A 0-parameter function that undoes adding the callback. - */ -const gUnload = Unloader(); -exports.unload = gUnload.unload.bind(gUnload);