2 * Copyright ©2010 Kris Maglione <maglione.k at Gmail>
3 * Distributable under the terms of the MIT license.
5 * Documentation is at the tail of this file.
9 dactyl.assert("noscriptOverlay" in window,
10 "This plugin requires the NoScript add-on.");
13 * this.globalJS ? !this.alwaysBlockUntrustedContent || !this.untrustedSites.matches(s)
14 * : this.jsPolicySites.matches(s) && !this.untrustedSites.matches(s) && !this.isForbiddenByHttpsStatus(s));
18 // This logic comes directly from NoScript. To my mind, it's insane.
19 const ns = services.noscript;
20 const global = options["script"];
21 const groups = { allowed: ns.jsPolicySites, temp: ns.tempSites, untrusted: ns.untrustedSites };
22 const show = Set(options["noscript-list"]);
23 const sites = window.noscriptOverlay.getSites();
25 const blockUntrusted = global && ns.alwaysBlockUntrustedContent;
28 for (let site in array.iterValues(Array.concat(sites.topSite, sites))) {
31 let untrusted = groups.untrusted.matches(site);
32 let matchingSite = null;
34 matchingSite = groups.allowed.matches(site) || blockUntrusted && site;
36 let enabled = Boolean(matchingSite);
37 if (site == sites.topSite && !ns.dom.getDocShellForWindow(content).allowJavascript)
40 let hasPort = /:\d+$/.test(site);
42 if (enabled && !global || untrusted) {
43 if (!enabled || global)
44 matchingSite = untrusted;
46 if (hasPort && ns.ignorePorts)
47 if (site = groups.allowed.matches(site.replace(/:\d+$/, "")))
49 ary.push(matchingSite);
52 if ((!hasPort || ns.ignorePorts) && (show.full || show.base)) {
53 let domain = !ns.isForbiddenByHttpsStatus(site) && ns.getDomain(site);
54 if (domain && ns.isJSEnabled(domain) == enabled) {
55 ary = util.subdomains(domain);
56 if (!show.base && ary.length > 1)
59 ary = ary.slice(0, 1);
63 if (show.address || ary.length == 0) {
66 if (hasPort && ns.ignorePorts) {
67 site = site.replace(/:\d+$/, "");
68 if (!groups.allowed.matches(site))
73 res = res.concat(ary);
77 return res.filter(function (h) !Set.add(seen, h));
79 function getObjects() {
80 let sites = noscriptOverlay.getSites();
81 let general = [], specific = [];
82 for (let group in values(sites.pluginExtras))
83 for (let obj in array.iterValues(group)) {
84 if (!obj.placeholder && (ns.isAllowedObject(obj.url, obj.mime) || obj.tag))
86 specific.push(obj.mime + "@" + obj.url);
87 general.push("*@" + obj.url);
88 general.push("*@" + obj.site);
90 let sites = buffer.allFrames().map(function (f) f.location.host);
91 for (let filter in values(options["noscript-objects"])) {
92 let host = util.getHost(util.split(filter, /@/, 2)[1]);
93 if (sites.some(function (s) s == host))
94 specific.push(filter);
97 return specific.concat(general).filter(function (site) !Set.add(seen, site));
100 var onUnload = overlay.overlayObject(gBrowser, {
101 // Extend NoScript's bookmarklet handling hack to the command-line
102 // Modified from NoScript's own wrapper.
103 loadURIWithFlags: function loadURIWithFlags(url) {
104 let args = arguments;
105 function load() loadURIWithFlags.superapply(gBrowser, args);
107 if (!commandline.command || !util.isDactyl(Components.stack.caller))
111 for (let [cmd, args] in commands.parseCommands(commandline.command))
112 var origURL = args.literalArg;
114 let isJS = function isJS(url) /^(?:data|javascript):/i.test(url);
115 let allowJS = prefs.get("noscript.allowURLBarJS", true);
117 if (isJS(origURL) && allowJS) {
118 if (services.noscript.executeJSURL(origURL, load))
121 else if (url != origURL && isJS(url)) {
122 if(services.noscript.handleBookmark(url, load))
133 highlight.loadCSS(literal(/*
134 NoScriptAllowed color: green;
135 NoScriptBlocked color: #444; font-style: italic;
136 NoScriptTemp color: blue;
137 NoScriptUntrusted color: #c00; font-style: italic;
141 ["temp", "jsPolicy", "untrusted"].forEach(function (group)
142 memoize(groupProto, group, function () services.noscript[group + "Sites"].matches(this.site)));
144 NoScriptTemp: "Temporarily allowed",
145 NoScriptAllowed: "Allowed permanently",
146 NoScriptUntrusted: "Untrusted",
147 NoScriptBlocked: "Blocked"
150 function splitContext(context, list) {
151 for (let [name, title, filter] in values(list)) {
152 let ctxt = context.split(name);
153 ctxt.title = [title];
154 ctxt.filters.push(filter);
158 completion.noscriptObjects = function (context) {
159 let whitelist = options.get("noscript-objects").set;
160 context = context.fork();
161 context.compare = CompletionContext.Sort.unsorted;
162 context.generate = getObjects;
165 description: function (key) Set.has(whitelist, key) ? "Allowed" : "Forbidden"
167 splitContext(context, getObjects, [
168 ["forbidden", "Forbidden objects", function (item) !Set.has(whitelist, item.item)],
169 ["allowed", "Allowed objects", function (item) Set.has(whitelist, item.item)]]);
171 completion.noscriptSites = function (context) {
172 context.compare = CompletionContext.Sort.unsorted;
173 context.generate = getSites;
176 description: function (site) groupDesc[this.highlight] +
177 (this.groups.untrusted && this.highlight != "NoScriptUntrusted" ? " (untrusted)" : ""),
179 highlight: function (site) this.groups.temp ? "NoScriptTemp" :
180 this.groups.jsPolicy ? "NoScriptAllowed" :
181 this.groups.untrusted ? "NoScriptUntrusted" :
183 groups: function (site) ({ site: site, __proto__: groupProto })
185 splitContext(context, [
186 ["normal", "Active sites", function (item) item.groups.jsPolicy || !item.groups.untrusted],
187 ["untrusted", "Untrusted sites", function (item) !item.groups.jsPolicy && item.groups.untrusted]]);
188 context.maxItems = 100;
191 services.add("noscript", "@maone.net/noscript-service;1");
193 var PrefBase = "noscript.";
194 var Pref = Struct("text", "pref", "description");
197 ["bookmarklet", "forbidBookmarklets", "Forbid bookmarklets"],
198 ["collapse", "collapseObject", "Collapse forbidden objects"],
199 ["flash", "forbidFlash", "Block Adobe® Flash® animations"],
200 ["fonts", "forbidFonts", "Forbid remote font loading"],
201 ["frame", "forbidFrames", "Block foreign <frame> elements"],
202 ["iframe", "forbidIFrames", "Block foreign <iframe> elements"],
203 ["java", "forbidJava", "Block Java™ applets"],
204 ["media", "forbidMedia", "Block <audio> and <video> elements"],
205 ["placeholder", "showPlaceholder", "Replace forbidden objects with a placeholder"],
206 ["plugins", "forbidPlugins", "Forbid other plugins"],
207 ["refresh", "forbidMetaRefresh", "Block <meta> page directions"],
208 ["silverlight", "forbidSilverlight", "Block Microsoft® Silverlight™ objects"],
209 ["trusted", "contentBlocker", "Block media and plugins even on trusted sites"],
210 ["webbug", "blockNSWB", "Block “web bug” tracking images"],
211 ["xslt", "forbidXSLT", "Forbid XSLT stylesheets"]
214 ["address", "showAddress", "Show the full address (http://www.google.com)"],
215 ["base", "showBaseDomain", "Show the base domain (google.com)"],
216 ["full", "showDomain", "Show the full domain (www.google.com)"]
219 for (let [k, v] in Iterator(prefs))
220 prefs[k] = array(v).map(function (v) [v[0], Pref.fromArray(v.map(UTF8))]).toObject();
222 function getPref(pref) modules.prefs.get(PrefBase + pref);
223 function setPref(pref, val) modules.prefs.set(PrefBase + pref, val);
225 prefs.complete = function prefsComplete(group) function (context) {
226 context.keys = { text: "text", description: "description" };
227 context.completions = values(prefs[group]);
229 prefs.get = function prefsGet(group) [p.text for (p in values(this[group])) if (getPref(p.pref))];
230 prefs.set = function prefsSet(group, val) {
231 for (let p in values(this[group]))
232 setPref(p.pref, val.indexOf(p.text) >= 0);
235 prefs.descs = function prefDescs(group) ["dl", {},
236 template.map(values(this[group]), function (pref)
237 [["dt", {}, pref.text], ["dd", {}, pref.description]])];
239 function groupParams(group) ( {
240 getter: function () prefs.get(group),
241 completer: prefs.complete(group),
242 setter: function (val) prefs.set(group, val),
246 group.options.add(["noscript-forbid", "nsf"],
247 "The set of permissions forbidden to untrusted sites",
249 groupParams("forbid"));
250 group.options.add(["noscript-list", "nsl"],
251 "The set of domains to show in the menu and completion list",
253 groupParams("list"));
255 group.options.add(["script"],
256 "Whether NoScript is enabled",
259 getter: function () services.noscript.jsEnabled,
260 setter: function (val) services.noscript.jsEnabled = val,
267 names: ["noscript-sites", "nss"],
268 description: "The list of sites allowed to execute scripts",
269 action: function (add, sites) sites.length && noscriptOverlay.safeAllow(sites, add, false, -1),
270 completer: function (context) completion.noscriptSites(context),
271 has: function (val) Set.has(services.noscript.jsPolicySites.sitesMap, val) &&
272 !Set.has(services.noscript.tempSites.sitesMap, val),
273 get set() Set.subtract(
274 services.noscript.jsPolicySites.sitesMap,
275 services.noscript.tempSites.sitesMap)
277 names: ["noscript-tempsites", "nst"],
278 description: "The list of sites temporarily allowed to execute scripts",
279 action: function (add, sites) sites.length && noscriptOverlay.safeAllow(sites, add, true, -1),
280 completer: function (context) completion.noscriptSites(context),
281 get set() services.noscript.tempSites.sitesMap
283 names: ["noscript-untrusted", "nsu"],
284 description: "The list of untrusted sites",
285 action: function (add, sites) sites.length && services.noscript.setUntrusted(sites, add),
286 completer: function (context) completion.noscriptSites(context),
287 get set() services.noscript.untrustedSites.sitesMap
289 names: ["noscript-objects", "nso"],
290 description: "The list of allowed objects",
291 get set() Set(array.flatten(
292 [Array.concat(v).map(function (v) v + "@" + this, k)
293 for ([k, v] in Iterator(services.noscript.objectWhitelist))])),
294 action: function (add, patterns) {
295 for (let pattern in values(patterns)) {
296 let [mime, site] = util.split(pattern, /@/, 2);
298 services.noscript.allowObject(site, mime);
300 let list = services.noscript.objectWhitelist[site];
303 delete services.noscript.objectWhitelist[site];
304 services.noscript.objectWhitelistLen--;
307 let types = list.filter(function (type) type != mime);
308 services.noscript.objectWhitelistLen -= list.length - types.length;
309 services.noscript.objectWhitelist[site] = types;
311 delete services.noscript.objectWhitelist[site];
317 services.noscript.reloadAllowedObjects(config.browser.selectedBrowser);
319 completer: function (context) completion.noscriptObjects(context)
321 ].forEach(function (params)
322 group.options.add(params.names, params.description,
325 completer: function (context) {
326 context.anchored = false;
327 if (params.completer)
328 params.completer(context)
330 domains: params.domains || function (values) values,
331 has: params.has || function (val) Set.has(params.set, val),
333 getter: params.getter || function () Object.keys(params.set),
334 setter: function (values) {
335 let newset = Set(values);
336 let current = params.set;
337 let value = this.value;
338 params.action(true, values.filter(function (site) !Set.has(current, site)))
339 params.action(false, value.filter(function (site) !Set.has(newset, site)));
344 validator: params.validator || function () true
348 ["plugin", { name: "noscript",
350 href: "http://dactyl.sf.net/pentadactyl/plugins#noscript-plugin",
351 summary: "NoScript integration",
353 ["author", { email: "maglione.k@gmail.com" }, "Kris Maglione"],
354 ["license", { href: "http://opensource.org/licenses/mit-license.php" }, "MIT"],
355 ["project", { name: "Pentadactyl", "min-version": "1.0" }],
358 "This plugin provides tight integration with the NoScript add-on. ",
359 "In addition to commands and options to control the behavior of ",
360 "NoScript, this plugin also provides integration with both the ",
361 config.appName, " and ", config.host, " sanitization systems sorely ",
362 "lacking in the add-on itself. Namely, when data for a domain is ",
363 "purged, all of its associated NoScript permissions are purged as ",
364 "well, and temporary permissions are purged along with session ",
368 "As most options provided by this script directly alter NoScript ",
369 "preferences, which are persistent, their values are automatically ",
370 "preserved across restarts."],
373 ["tags", {}, "'script' 'noscript'"],
375 ["spec", {}, "'script'"],
376 ["type", {}, "boolean"],
377 ["default", {}, "noscript"],
380 "When on, all sites are allowed to execute scripts and ",
381 "load plugins. When off, only specifically allowed sites ",
385 ["tags", {}, "'nsf' 'noscript-forbid'"],
386 ["spec", {}, "'noscript-forbid'"],
387 ["type", {}, "stringlist"],
391 "The set of permissions forbidden to untrusted sites."],
392 prefs.descs("forbid"),
394 "See also ", ["o", {}, "noscript-objects"], "."]]],
397 ["tags", {}, "'nsl' 'noscript-list'"],
398 ["spec", {}, "'noscript-list'"],
399 ["type", {}, "stringlist"],
403 "The set of items to show in the main completion list and ",
405 prefs.descs("list")]],
408 ["tags", {}, "'nso' 'noscript-objects'"],
409 ["spec", {}, "'noscript-objects'"],
410 ["type", {}, "stringlist"],
414 "The list of objects which allowed to display. See also ",
415 ["o", {}, "noscript-forbid"], "."],
417 ["ex", {}, ":map ", ["k", { name: "A-c", link: "false" }]], " ",
418 ["ex", {}, ":set nso!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
421 ["tags", {}, "'nss' 'noscript-sites'"],
422 ["spec", {}, "'noscript-sites'"],
423 ["type", {}, "stringlist"],
427 "The list of sites which are permanently allowed to execute ",
430 ["ex", {}, ":map ", ["k", { name: "A-s", link: "false" }]], " ",
431 ["ex", {}, ":set nss!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
434 ["tags", {}, "'nst' 'noscript-tempsites'"],
435 ["spec", {}, "'noscript-tempsites'"],
436 ["type", {}, "stringlist"],
440 "The list of sites which are temporarily allowed to execute ",
441 "scripts. The value is not preserved across application ",
444 ["ex", {}, ":map ", ["k", { name: "A-S-s", link: "false" }]], " ",
445 ["ex", {}, ":set nst!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
448 ["tags", {}, "'nsu' 'noscript-untrusted'"],
449 ["spec", {}, "'noscript-untrusted'"],
450 ["type", {}, "stringlist"],
454 "The list of untrusted sites which are not allowed to activate, ",
455 "nor are listed in the main completion lists or NoScript menu."],
457 ["ex", {}, ":map ", ["k", { name: "A-C-s", link: "false" }]], " ",
458 ["ex", {}, ":set nsu!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]]];
460 /* vim:se sts=4 sw=4 et: */