/* * Copyright ©2010-2014 Kris Maglione * Distributable under the terms of the MIT license. * * Documentation is at the tail of this file. */ "use strict"; if (!("noscriptOverlay" in window)) { if (!userContext.noscriptIgnoreMissing) dactyl.echoerr("This plugin requires the NoScript add-on."); throw Finished(); } /* * this.globalJS ? !this.alwaysBlockUntrustedContent || !this.untrustedSites.matches(s) * : this.jsPolicySites.matches(s) && !this.untrustedSites.matches(s) && !this.isForbiddenByHttpsStatus(s)); */ function getSites() { // This logic comes directly from NoScript. To my mind, it's insane. const ns = services.noscript; const global = options["script"]; const groups = { allowed: ns.jsPolicySites, temp: ns.tempSites, untrusted: ns.untrustedSites }; const show = RealSet(options["noscript-list"]); const sites = window.noscriptOverlay.getSites(); const blockUntrusted = global && ns.alwaysBlockUntrustedContent; let res = []; for (let site of array.iterValues(Array.concat(sites.topSite, sites))) { let ary = []; let untrusted = groups.untrusted.matches(site); let matchingSite = null; if (!untrusted) matchingSite = groups.allowed.matches(site) || blockUntrusted && site; let enabled = Boolean(matchingSite); if (site == sites.topSite && !ns.dom.getDocShellForWindow(content).allowJavascript) enabled = false; let hasPort = /:\d+$/.test(site); if (enabled && !global || untrusted) { if (!enabled || global) matchingSite = untrusted; if (hasPort && ns.ignorePorts) if (site = groups.allowed.matches(site.replace(/:\d+$/, ""))) matchingSite = site; ary.push(matchingSite); } else { if ((!hasPort || ns.ignorePorts) && (show.has("full") || show.has("base"))) { let domain = !ns.isForbiddenByHttpsStatus(site) && ns.getDomain(site); if (domain && ns.isJSEnabled(domain) == enabled) { ary = util.subdomains(domain); if (!show.has("base") && ary.length > 1) ary = ary.slice(1); if (!show.has("full")) ary = ary.slice(0, 1); } } if (show.has("address") || ary.length == 0) { ary.push(site); if (hasPort && ns.ignorePorts) { site = site.replace(/:\d+$/, ""); if (!groups.allowed.matches(site)) ary.push(site); } } } res = res.concat(ary); } let seen = RealSet(); return res.filter(function (h) { let res = !seen.has(h); seen.add(h); return res; }); } function getObjects() { let sites = noscriptOverlay.getSites(); let general = [], specific = []; for (let group of values(sites.pluginExtras)) for (let obj of array.iterValues(group)) { if (!obj.placeholder && (ns.isAllowedObject(obj.url, obj.mime) || obj.tag)) continue; specific.push(obj.mime + "@" + obj.url); general.push("*@" + obj.url); general.push("*@" + obj.site); } sites = buffer.allFrames().map(function (f) f.location.host); for (let filter of values(options["noscript-objects"])) { let host = util.getHost(util.split(filter, /@/, 2)[1]); if (sites.some(function (s) s == host)) specific.push(filter); } let seen = RealSet(); return specific.concat(general).filter(function (site) { let res = !seen.has(site); seen.add(site); return res; }); } var onUnload = overlay.overlayObject(gBrowser, { // Extend NoScript's bookmarklet handling hack to the command-line // Modified from NoScript's own wrapper. loadURIWithFlags: function loadURIWithFlags(url) { let args = arguments; function load() loadURIWithFlags.superapply(gBrowser, args); if (!commandline.command || !util.isDactyl(Components.stack.caller)) return load(); try { for (let [cmd, args] of commands.parseCommands(commandline.command)) var origURL = args.literalArg; let isJS = function isJS(url) /^(?:data|javascript):/i.test(url); let allowJS = prefs.get("noscript.allowURLBarJS", true); if (isJS(origURL) && allowJS) { if (services.noscript.executeJSURL(origURL, load)) return; } else if (url != origURL && isJS(url)) { if(services.noscript.handleBookmark(url, load)) return; } } catch (e) { util.reportError(e); } return load(); } }); highlight.loadCSS(literal(/* NoScriptAllowed color: green; NoScriptBlocked color: #444; font-style: italic; NoScriptTemp color: blue; NoScriptUntrusted color: #c00; font-style: italic; */)); let groupProto = {}; ["temp", "jsPolicy", "untrusted"].forEach(function (group) memoize(groupProto, group, function () services.noscript[group + "Sites"].matches(this.site))); let groupDesc = { NoScriptTemp: "Temporarily allowed", NoScriptAllowed: "Allowed permanently", NoScriptUntrusted: "Untrusted", NoScriptBlocked: "Blocked" }; function splitContext(context, list) { for (let [name, title, filter] of values(list)) { let ctxt = context.split(name); ctxt.title = [title]; ctxt.filters.push(filter); } } completion.noscriptObjects = function (context) { let whitelist = options.get("noscript-objects").set; context = context.fork(); context.compare = CompletionContext.Sort.unsorted; context.generate = getObjects; context.keys = { text: util.identity, description: function (key) whitelist.has(key) ? "Allowed" : "Forbidden" }; splitContext(context, getObjects, [ ["forbidden", "Forbidden objects", function (item) !whitelist.has(item.item)], ["allowed", "Allowed objects", function (item) whitelist.has(item.item)]]); }; completion.noscriptSites = function (context) { context.compare = CompletionContext.Sort.unsorted; context.generate = getSites; context.keys = { text: util.identity, description: function (site) groupDesc[this.highlight] + (this.groups.untrusted && this.highlight != "NoScriptUntrusted" ? " (untrusted)" : ""), highlight: function (site) this.groups.temp ? "NoScriptTemp" : this.groups.jsPolicy ? "NoScriptAllowed" : this.groups.untrusted ? "NoScriptUntrusted" : "NoScriptBlocked", groups: function (site) ({ site: site, __proto__: groupProto }) }; splitContext(context, [ ["normal", "Active sites", function (item) item.groups.jsPolicy || !item.groups.untrusted], ["untrusted", "Untrusted sites", function (item) !item.groups.jsPolicy && item.groups.untrusted]]); context.maxItems = 100; } services.add("noscript", "@maone.net/noscript-service;1"); var PrefBase = "noscript."; var Pref = Struct("text", "pref", "description"); let prefs = { forbid: [ ["bookmarklet", "forbidBookmarklets", "Forbid bookmarklets"], ["collapse", "collapseObject", "Collapse forbidden objects"], ["flash", "forbidFlash", "Block Adobe® Flash® animations"], ["fonts", "forbidFonts", "Forbid remote font loading"], ["frame", "forbidFrames", "Block foreign elements"], ["iframe", "forbidIFrames", "Block foreign