]> git.donarmstrong.com Git - x_full.git/blob - .pentadactyl/plugins/noscript-dev.js
remove sa_x_full
[x_full.git] / .pentadactyl / plugins / noscript-dev.js
1 /*
2  * Copyright ©2010 Kris Maglione <maglione.k at Gmail>
3  * Distributable under the terms of the MIT license.
4  *
5  * Documentation is at the tail of this file.
6  */
7 "use strict";
8
9 dactyl.assert("noscriptOverlay" in window,
10               "This plugin requires the NoScript add-on.");
11
12 /*
13  *  this.globalJS ? !this.alwaysBlockUntrustedContent || !this.untrustedSites.matches(s)
14  *                : this.jsPolicySites.matches(s) && !this.untrustedSites.matches(s) && !this.isForbiddenByHttpsStatus(s));
15  */
16
17 function getSites() {
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();
24
25     const blockUntrusted = global && ns.alwaysBlockUntrustedContent;
26
27     let res = [];
28     for (let site in array.iterValues(Array.concat(sites.topSite, sites))) {
29         let ary = [];
30
31         let untrusted    = groups.untrusted.matches(site);
32         let matchingSite = null;
33         if (!untrusted)
34             matchingSite = groups.allowed.matches(site) || blockUntrusted && site;
35
36         let enabled = Boolean(matchingSite);
37         if (site == sites.topSite && !ns.dom.getDocShellForWindow(content).allowJavascript)
38             enabled = false;
39
40         let hasPort = /:\d+$/.test(site);
41
42         if (enabled && !global || untrusted) {
43             if (!enabled || global)
44                 matchingSite = untrusted;
45
46             if (hasPort && ns.ignorePorts)
47                 if (site = groups.allowed.matches(site.replace(/:\d+$/, "")))
48                     matchingSite = site;
49             ary.push(matchingSite);
50         }
51         else {
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)
57                         ary = ary.slice(1);
58                     if (!show.full)
59                         ary = ary.slice(0, 1);
60                 }
61             }
62
63             if (show.address || ary.length == 0) {
64                 ary.push(site);
65
66                 if (hasPort && ns.ignorePorts) {
67                     site = site.replace(/:\d+$/, "");
68                     if (!groups.allowed.matches(site))
69                         ary.push(site);
70                 }
71             }
72         }
73         res = res.concat(ary);
74     }
75
76     let seen = {};
77     return res.filter(function (h) !Set.add(seen, h));
78 }
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))
85                 continue;
86             specific.push(obj.mime + "@" + obj.url);
87             general.push("*@" + obj.url);
88             general.push("*@" + obj.site);
89         }
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);
95     }
96     let seen = {};
97     return specific.concat(general).filter(function (site) !Set.add(seen, site));
98 }
99
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);
106
107         if (!commandline.command || !util.isDactyl(Components.stack.caller))
108             return load();
109
110         try {
111             for (let [cmd, args] in commands.parseCommands(commandline.command))
112                 var origURL = args.literalArg;
113
114             let isJS = function isJS(url) /^(?:data|javascript):/i.test(url);
115             let allowJS = prefs.get("noscript.allowURLBarJS", true);
116
117             if (isJS(origURL) && allowJS) {
118                 if (services.noscript.executeJSURL(origURL, load))
119                     return;
120             }
121             else if (url != origURL && isJS(url)) {
122                 if(services.noscript.handleBookmark(url, load))
123                     return;
124             }
125         }
126         catch (e) {
127             util.reportError(e);
128         }
129         return load();
130     }
131 });
132
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;
138 */));
139
140 let groupProto = {};
141 ["temp", "jsPolicy", "untrusted"].forEach(function (group)
142     memoize(groupProto, group, function () services.noscript[group + "Sites"].matches(this.site)));
143 let groupDesc = {
144     NoScriptTemp:       "Temporarily allowed",
145     NoScriptAllowed:    "Allowed permanently",
146     NoScriptUntrusted:  "Untrusted",
147     NoScriptBlocked:    "Blocked"
148 };
149
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);
155     }
156 }
157
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;
163     context.keys = {
164         text: util.identity,
165         description: function (key) Set.has(whitelist, key) ? "Allowed" : "Forbidden"
166     };
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)]]);
170 };
171 completion.noscriptSites = function (context) {
172     context.compare = CompletionContext.Sort.unsorted;
173     context.generate = getSites;
174     context.keys = {
175         text: util.identity,
176         description: function (site) groupDesc[this.highlight] +
177             (this.groups.untrusted && this.highlight != "NoScriptUntrusted" ? " (untrusted)" : ""),
178
179         highlight: function (site) this.groups.temp      ? "NoScriptTemp" :
180                                    this.groups.jsPolicy  ? "NoScriptAllowed" :
181                                    this.groups.untrusted ? "NoScriptUntrusted" :
182                                                            "NoScriptBlocked",
183         groups: function (site) ({ site: site, __proto__: groupProto })
184     };
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;
189 }
190
191 services.add("noscript", "@maone.net/noscript-service;1");
192
193 var PrefBase = "noscript.";
194 var Pref = Struct("text", "pref", "description");
195 let prefs = {
196     forbid: [
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"]
212     ],
213     list: [
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)"]
217     ]
218 };
219 for (let [k, v] in Iterator(prefs))
220     prefs[k] = array(v).map(function (v) [v[0], Pref.fromArray(v.map(UTF8))]).toObject();
221
222 function getPref(pref)      modules.prefs.get(PrefBase + pref);
223 function setPref(pref, val) modules.prefs.set(PrefBase + pref, val);
224
225 prefs.complete = function prefsComplete(group) function (context) {
226     context.keys = { text: "text", description: "description" };
227     context.completions = values(prefs[group]);
228 }
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);
233     return val;
234 }
235 prefs.descs = function prefDescs(group) ["dl", {},
236     template.map(values(this[group]), function (pref)
237         [["dt", {}, pref.text], ["dd", {}, pref.description]])];
238
239 function groupParams(group) ( {
240     getter: function () prefs.get(group),
241     completer: prefs.complete(group),
242     setter: function (val) prefs.set(group, val),
243     initialValue: true,
244     persist: false
245 });
246 group.options.add(["noscript-forbid", "nsf"],
247     "The set of permissions forbidden to untrusted sites",
248     "stringlist", "",
249     groupParams("forbid"));
250 group.options.add(["noscript-list", "nsl"],
251     "The set of domains to show in the menu and completion list",
252     "stringlist", "",
253     groupParams("list"));
254
255 group.options.add(["script"],
256     "Whether NoScript is enabled",
257     "boolean", false,
258     {
259         getter: function () services.noscript.jsEnabled,
260         setter: function (val) services.noscript.jsEnabled = val,
261         initialValue: true,
262         persist: false
263     });
264
265 [
266     {
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)
276     }, {
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
282     }, {
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
288     }, {
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);
297                 if (add)
298                     services.noscript.allowObject(site, mime);
299                 else {
300                     let list = services.noscript.objectWhitelist[site];
301                     if (list) {
302                         if (list == "*") {
303                             delete services.noscript.objectWhitelist[site];
304                             services.noscript.objectWhitelistLen--;
305                         }
306                         else {
307                             let types = list.filter(function (type) type != mime);
308                             services.noscript.objectWhitelistLen -= list.length - types.length;
309                             services.noscript.objectWhitelist[site] = types;
310                             if (!types.length)
311                                 delete services.noscript.objectWhitelist[site];
312                         }
313                     }
314                 }
315             }
316             if (add)
317                 services.noscript.reloadAllowedObjects(config.browser.selectedBrowser);
318         },
319         completer: function (context) completion.noscriptObjects(context)
320     }
321 ].forEach(function (params)
322     group.options.add(params.names, params.description,
323         "stringlist", "",
324         {
325             completer: function (context) {
326                 context.anchored = false;
327                 if (params.completer)
328                     params.completer(context)
329             },
330             domains: params.domains || function (values) values,
331             has: params.has || function (val) Set.has(params.set, val),
332             initialValue: true,
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)));
340                 return this.value;
341             },
342             persist: false,
343             privateData: true,
344             validator: params.validator || function () true
345         }));
346
347 var INFO =
348 ["plugin", { name: "noscript",
349              version: "0.8",
350              href: "http://dactyl.sf.net/pentadactyl/plugins#noscript-plugin",
351              summary: "NoScript integration",
352              xmlns: "dactyl" },
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" }],
356
357     ["p", {},
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 ",
365         "data."],
366
367     ["note", {},
368         "As most options provided by this script directly alter NoScript ",
369         "preferences, which are persistent, their values are automatically ",
370         "preserved across restarts."],
371
372     ["item", {},
373         ["tags", {}, "'script' 'noscript'"],
374         ["strut", {}],
375         ["spec", {}, "'script'"],
376         ["type", {}, "boolean"],
377         ["default", {}, "noscript"],
378         ["description", {},
379             ["p", {},
380                 "When on, all sites are allowed to execute scripts and ",
381                 "load plugins. When off, only specifically allowed sites ",
382                 "may do so."]]],
383
384     ["item", {},
385         ["tags", {}, "'nsf' 'noscript-forbid'"],
386         ["spec", {}, "'noscript-forbid'"],
387         ["type", {}, "stringlist"],
388         ["default", {}, ""],
389         ["description", {},
390             ["p", {},
391                 "The set of permissions forbidden to untrusted sites."],
392             prefs.descs("forbid"),
393             ["p", {},
394                 "See also ", ["o", {}, "noscript-objects"], "."]]],
395
396     ["item", {},
397         ["tags", {}, "'nsl' 'noscript-list'"],
398         ["spec", {}, "'noscript-list'"],
399         ["type", {}, "stringlist"],
400         ["default", {}, ""],
401         ["description", {},
402             ["p", {},
403                 "The set of items to show in the main completion list and ",
404                 "NoScript menu."],
405             prefs.descs("list")]],
406
407     ["item", {},
408         ["tags", {}, "'nso' 'noscript-objects'"],
409         ["spec", {}, "'noscript-objects'"],
410         ["type", {}, "stringlist"],
411         ["default", {}, ""],
412         ["description", {},
413             ["p", {},
414                 "The list of objects which allowed to display. See also ",
415                 ["o", {}, "noscript-forbid"], "."],
416             ["example", {},
417                 ["ex", {}, ":map ", ["k", { name: "A-c",  link: "false" }]], " ",
418                 ["ex", {}, ":set nso!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
419
420     ["item", {},
421         ["tags", {}, "'nss' 'noscript-sites'"],
422         ["spec", {}, "'noscript-sites'"],
423         ["type", {}, "stringlist"],
424         ["default", {}, ""],
425         ["description", {},
426             ["p", {},
427                 "The list of sites which are permanently allowed to execute ",
428                 "scripts."],
429             ["example", {},
430                 ["ex", {}, ":map ", ["k", { name: "A-s", link: "false" }]], " ",
431                 ["ex", {}, ":set nss!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
432
433     ["item", {},
434         ["tags", {}, "'nst' 'noscript-tempsites'"],
435         ["spec", {}, "'noscript-tempsites'"],
436         ["type", {}, "stringlist"],
437         ["default", {}, ""],
438         ["description", {},
439             ["p", {},
440                 "The list of sites which are temporarily allowed to execute ",
441                 "scripts. The value is not preserved across application ",
442                 "restarts."],
443             ["example", {},
444                 ["ex", {}, ":map ", ["k", { name: "A-S-s", link: "false" }]], " ",
445                 ["ex", {}, ":set nst!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
446
447     ["item", {},
448         ["tags", {}, "'nsu' 'noscript-untrusted'"],
449         ["spec", {}, "'noscript-untrusted'"],
450         ["type", {}, "stringlist"],
451         ["default", {}, ""],
452         ["description", {},
453             ["p", {},
454                 "The list of untrusted sites which are not allowed to activate, ",
455                 "nor are listed in the main completion lists or NoScript menu."],
456             ["example", {},
457                 ["ex", {}, ":map ", ["k", { name: "A-C-s", link: "false" }]], " ",
458                 ["ex", {}, ":set nsu!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]]];
459
460 /* vim:se sts=4 sw=4 et: */