mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-25 11:52:25 +01:00
I'm assuming that the change to the completion module, in 916ea41, no
longer handling bare objects is deliberate and this appears consistent
with other cases.
795 lines
33 KiB
JavaScript
795 lines
33 KiB
JavaScript
// Copyright (c) 2009 by Doug Kearns <dougkearns@gmail.com>
|
|
// Copyright (c) 2009-2015 Kris Maglione <maglione.k at Gmail>
|
|
//
|
|
// This work is licensed for reuse under an MIT license. Details are
|
|
// given in the LICENSE.txt file included with this file.
|
|
"use strict";
|
|
|
|
// TODO:
|
|
// - fix Sanitize autocommand
|
|
// - add warning for TIMESPAN_EVERYTHING?
|
|
|
|
// FIXME:
|
|
// - finish 1.9.0 support if we're going to support sanitizing in Melodactyl
|
|
|
|
defineModule("sanitizer", {
|
|
exports: ["Range", "Sanitizer", "sanitizer"],
|
|
require: ["config", "prefs", "services", "util"]
|
|
});
|
|
|
|
lazyRequire("messages", ["_"]);
|
|
lazyRequire("overlay", ["overlay"]);
|
|
lazyRequire("storage", ["storage"]);
|
|
lazyRequire("template", ["template"]);
|
|
|
|
let tmp = Object.create(this);
|
|
JSMLoader.loadSubScript("chrome://browser/content/sanitize.js", tmp);
|
|
tmp.Sanitizer.prototype.__proto__ = Class.prototype;
|
|
|
|
var Range = Struct("min", "max");
|
|
update(Range.prototype, {
|
|
contains: function (date) {
|
|
if (date != null)
|
|
return ((this.min == null || date >= this.min) &&
|
|
(this.max == null || date <= this.max));
|
|
|
|
return false;
|
|
},
|
|
|
|
get isEternity() {
|
|
return this.max == null && this.min == null;
|
|
},
|
|
get isSession() {
|
|
return this.max == null && this.min == sanitizer.sessionStart;
|
|
},
|
|
|
|
get native() {
|
|
return this.isEternity ? null
|
|
: [this.min || 0, this.max == null ? Number.MAX_VALUE
|
|
: this.max];
|
|
}
|
|
});
|
|
|
|
var Item = Class("SanitizeItem", {
|
|
init: function (name, params) {
|
|
this.name = name;
|
|
this.description = params.description;
|
|
},
|
|
|
|
// Hack for completion:
|
|
"0": Class.Property({ get: function () { return this.name; } }),
|
|
"1": Class.Property({ get: function () { return this.description; } }),
|
|
|
|
description: Messages.Localized(""),
|
|
|
|
get cpdPref() {
|
|
return (this.builtin ? "" : Item.PREFIX) + Item.BRANCH + Sanitizer.argToPref(this.name);
|
|
},
|
|
get shutdownPref() {
|
|
return (this.builtin ? "" : Item.PREFIX) + Item.SHUTDOWN_BRANCH + Sanitizer.argToPref(this.name);
|
|
},
|
|
get cpd() { return prefs.get(this.cpdPref); },
|
|
get shutdown() { return prefs.get(this.shutdownPref); },
|
|
|
|
shouldSanitize: function (shutdown) {
|
|
return (!shutdown || this.builtin || this.persistent) &&
|
|
prefs.get(shutdown ? this.shutdownPref : this.pref);
|
|
}
|
|
}, {
|
|
PREFIX: config.prefs.branch.root,
|
|
BRANCH: "privacy.cpd.",
|
|
SHUTDOWN_BRANCH: "privacy.clearOnShutdown."
|
|
});
|
|
|
|
var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference], tmp.Sanitizer), {
|
|
sessionStart: Date.now() * 1000,
|
|
|
|
init: function () {
|
|
const self = this;
|
|
|
|
util.addObserver(this);
|
|
|
|
services.add("cookies", "@mozilla.org/cookiemanager;1", [Ci.nsICookieManager, Ci.nsICookieManager2,
|
|
Ci.nsICookieService]);
|
|
services.add("loginManager", "@mozilla.org/login-manager;1", Ci.nsILoginManager);
|
|
services.add("permissions", "@mozilla.org/permissionmanager;1", Ci.nsIPermissionManager);
|
|
|
|
this.itemMap = {};
|
|
|
|
this.addItem("all", {
|
|
description: "Sanitize all items",
|
|
shouldSanitize: function () { return false; }
|
|
});
|
|
// Builtin items
|
|
this.addItem("cache", { builtin: true, description: "Cache" });
|
|
this.addItem("downloads", { builtin: true, description: "Download history" });
|
|
this.addItem("formdata", { builtin: true, description: "Saved form and search history" });
|
|
this.addItem("offlineapps", { builtin: true, description: "Offline website data" });
|
|
this.addItem("passwords", { builtin: true, description: "Saved passwords" });
|
|
this.addItem("sessions", { builtin: true, description: "Authenticated sessions" });
|
|
|
|
// These builtin methods don't support hosts or otherwise have
|
|
// insufficient granularity
|
|
this.addItem("cookies", {
|
|
builtin: true,
|
|
description: "Cookies",
|
|
persistent: true,
|
|
action: function (range, host) {
|
|
for (let c of Sanitizer.iterCookies(host))
|
|
if (range.contains(c.creationTime) || timespan.isSession && c.isSession)
|
|
services.cookies.remove(c.host, c.name, c.path, false);
|
|
},
|
|
override: true
|
|
});
|
|
this.addItem("history", {
|
|
builtin: true,
|
|
description: "Browsing history",
|
|
persistent: true,
|
|
sessionHistory: true,
|
|
action: function (range, host) {
|
|
if (host)
|
|
services.history.removePagesFromHost(host, true);
|
|
else {
|
|
if (range.isEternity)
|
|
services.history.removeAllPages();
|
|
else
|
|
services.history.removeVisitsByTimeframe(range.native[0], Math.min(Date.now() * 1000, range.native[1])); // XXX
|
|
services.observer.notifyObservers(null, "browser:purge-session-history", "");
|
|
}
|
|
|
|
if (!host || util.isDomainURL(prefs.get("general.open_location.last_url"), host))
|
|
prefs.reset("general.open_location.last_url");
|
|
},
|
|
override: true
|
|
});
|
|
try {
|
|
var { ForgetAboutSite } = Cu.import("resource://gre/modules/ForgetAboutSite.jsm", {});
|
|
}
|
|
catch (e) {}
|
|
if (ForgetAboutSite)
|
|
this.addItem("host", {
|
|
description: "All data from the given host",
|
|
action: function (range, host) {
|
|
if (host)
|
|
ForgetAboutSite.removeDataFromDomain(host);
|
|
}
|
|
});
|
|
this.addItem("sitesettings", {
|
|
builtin: true,
|
|
description: "Site preferences",
|
|
persistent: true,
|
|
action: function (range, host) {
|
|
if (range.isSession)
|
|
return;
|
|
if (host) {
|
|
for (let p of Sanitizer.iterPermissions(host)) {
|
|
let uri = util.createURI(p);
|
|
services.permissions.remove(uri, p.type);
|
|
services.permissions.add(uri, p.type, 0);
|
|
}
|
|
for (let p of iter(services.contentPrefs.getPrefs(util.createURI(host))))
|
|
services.contentPrefs.removePref(util.createURI(host), p.QueryInterface(Ci.nsIProperty).name);
|
|
}
|
|
else {
|
|
// "Allow this site to open popups" ...
|
|
services.permissions.removeAll();
|
|
// Zoom level, ...
|
|
services.contentPrefs.removeAllDomains(null);
|
|
}
|
|
|
|
// "Never remember passwords" ...
|
|
for (let domain of services.loginManager.getAllDisabledHosts())
|
|
if (!host || util.isSubdomain(domain, host))
|
|
services.loginManager.setLoginSavingEnabled(host, true);
|
|
},
|
|
override: true
|
|
});
|
|
|
|
function ourItems(persistent) {
|
|
return Object.values(self.itemMap)
|
|
.filter(item => (!item.builtin &&
|
|
(!persistent || item.persistent) &&
|
|
item.name !== "all"));
|
|
}
|
|
|
|
function prefOverlay(branch, persistent, local) {
|
|
return update(Object.create(local),
|
|
{
|
|
before: [
|
|
["preferences", { id: branch.substr(Item.PREFIX.length) + "history",
|
|
xmlns: "xul" },
|
|
template.map(ourItems(persistent), item =>
|
|
["preference", { type: "bool", id: branch + item.name, name: branch + item.name }])]
|
|
],
|
|
init: function init(win) {
|
|
let pane = win.document.getElementById("SanitizeDialogPane");
|
|
for (let pref of pane.preferences)
|
|
pref.updateElements();
|
|
init.superapply(this, arguments);
|
|
}
|
|
});
|
|
}
|
|
|
|
util.timeout(function () { // Load order issue...
|
|
|
|
{
|
|
let branch = Item.PREFIX + Item.SHUTDOWN_BRANCH;
|
|
|
|
overlay.overlayWindow("chrome://browser/content/preferences/sanitize.xul",
|
|
win => {
|
|
let items = ourItems(true);
|
|
|
|
return prefOverlay(branch, true, {
|
|
append: {
|
|
SanitizeDialogPane:
|
|
["groupbox", { orient: "horizontal", xmlns: "xul" },
|
|
["caption", { label: config.appName + /*L*/" (see :help privacy)" }],
|
|
["grid", { flex: "1" },
|
|
["columns", {},
|
|
["column", { flex: "1" }],
|
|
["column", { flex: "1" }]],
|
|
["rows", {},
|
|
template.map(util.range(0, Math.ceil(items.length / 2)),
|
|
i =>
|
|
["row", {},
|
|
template.map(items.slice(i * 2, i * 2 + 2),
|
|
item =>
|
|
["checkbox", { xmlns: XUL, label: item.description, preference: branch + item.name }])])]]]
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
{
|
|
let branch = Item.PREFIX + Item.BRANCH;
|
|
|
|
overlay.overlayWindow("chrome://browser/content/sanitize.xul",
|
|
function (win) {
|
|
return prefOverlay(branch, false, {
|
|
append: {
|
|
itemList: [
|
|
["listitem", { xmlns: "xul", label: /*L*/"See :help privacy for the following:",
|
|
disabled: "true", style: "font-style: italic; font-weight: bold;" }],
|
|
template.map(ourItems(), ([item, desc]) =>
|
|
["listitem", { xmlns: "xul", preference: branch + item,
|
|
type: "checkbox", label: config.appName + ", " + desc,
|
|
onsyncfrompreference: "return gSanitizePromptDialog.onReadGeneric();" }])
|
|
]
|
|
},
|
|
ready: function ready(win) {
|
|
let elem = win.document.getElementById("itemList");
|
|
elem.setAttribute("rows", elem.itemCount);
|
|
win.Sanitizer = Class("Sanitizer", win.Sanitizer, {
|
|
sanitize: function sanitize() {
|
|
self.withSavedValues(["sanitizing"], () => {
|
|
self.sanitizing = true;
|
|
sanitize.superapply(this, arguments);
|
|
sanitizer.sanitizeItems(
|
|
Object.values(self.itemMap)
|
|
.filter(item => item.shouldSanitize(false))
|
|
.map(item => item.name),
|
|
Range.fromArray(this.range || []));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
firstRun: 0,
|
|
|
|
addItem: function addItem(name, params) {
|
|
let item = this.itemMap[name] || Item(name, params);
|
|
this.itemMap[name] = item;
|
|
|
|
for (let [k, prop] of iterOwnProperties(params))
|
|
if (!("value" in prop) || !callable(prop.value) && !(k in item))
|
|
Object.defineProperty(item, k, prop);
|
|
|
|
function getWindow(obj) {
|
|
obj = Class.objectGlobal(obj);
|
|
return obj.window || obj;
|
|
}
|
|
|
|
let names = new RealSet([name].concat(params.contains || []).map(e => "clear-" + e));
|
|
if (params.action)
|
|
storage.addObserver("sanitizer",
|
|
function (key, event, arg) {
|
|
if (names.has(event))
|
|
apply(params, "action", arg);
|
|
},
|
|
getWindow(params.action));
|
|
},
|
|
|
|
observers: {
|
|
"browser:purge-domain-data": function (subject, host) {
|
|
storage.fireEvent("sanitize", "domain", host);
|
|
// If we're sanitizing, our own sanitization functions will already
|
|
// be called, and with much greater granularity. Only process this
|
|
// event if it's triggered externally.
|
|
if (!this.sanitizing)
|
|
this.sanitizeItems(null, Range(), data);
|
|
},
|
|
"browser:purge-session-history": function (subject, data) {
|
|
// See above.
|
|
if (!this.sanitizing)
|
|
this.sanitizeItems(null, Range(this.sessionStart), null, "sessionHistory");
|
|
},
|
|
"quit-application-granted": function (subject, data) {
|
|
if (this.runAtShutdown && !this.sanitizeItems(null, Range(), null, "shutdown"))
|
|
this.ranAtShutdown = true;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Returns a load context for the given thing, to be used with
|
|
* interfaces needing one for per-window private browsing support.
|
|
*
|
|
* @param {Window|Document|Node} thing The thing for which to return
|
|
* a load context.
|
|
*/
|
|
getContext: function getContext(thing, global = null) {
|
|
if (!Ci.nsILoadContext)
|
|
return null;
|
|
|
|
if (Cu.isCrossProcessWrapper(thing) && global)
|
|
thing = global;
|
|
|
|
if (thing instanceof Ci.nsIDOMNode && thing.ownerDocument)
|
|
thing = thing.ownerDocument;
|
|
if (thing instanceof Ci.nsIDOMDocument)
|
|
thing = thing.defaultView;
|
|
if (thing instanceof Ci.nsIInterfaceRequestor)
|
|
thing = thing.getInterface(Ci.nsIWebNavigation);
|
|
return thing.QueryInterface(Ci.nsILoadContext);
|
|
},
|
|
|
|
get ranAtShutdown() {
|
|
return config.prefs.get("didSanitizeOnShutdown");
|
|
},
|
|
set ranAtShutdown(val) {
|
|
config.prefs.set("didSanitizeOnShutdown", Boolean(val));
|
|
},
|
|
get runAtShutdown() {
|
|
return prefs.get("privacy.sanitize.sanitizeOnShutdown");
|
|
},
|
|
set runAtShutdown(val) {
|
|
prefs.set("privacy.sanitize.sanitizeOnShutdown", Boolean(val));
|
|
},
|
|
|
|
sanitize: function sanitize(items, range) {
|
|
return this.withSavedValues(["sanitizing"], function () {
|
|
this.sanitizing = true;
|
|
let errors = this.sanitizeItems(items, range, null);
|
|
|
|
for (let itemName of values(items)) {
|
|
try {
|
|
let item = this.items[Sanitizer.argToPref(itemName)];
|
|
if (item && !this.itemMap[itemName].override) {
|
|
item.range = range.native;
|
|
if ("clear" in item && item.canClear)
|
|
item.clear();
|
|
}
|
|
}
|
|
catch (e) {
|
|
errors = errors || {};
|
|
errors[itemName] = e;
|
|
util.dump("Error sanitizing " + itemName);
|
|
util.reportError(e);
|
|
}
|
|
}
|
|
return errors;
|
|
});
|
|
},
|
|
|
|
sanitizeItems: function sanitizeItems(items, range, host, key) {
|
|
return this.withSavedValues(["sanitizing"], function () {
|
|
this.sanitizing = true;
|
|
if (items == null)
|
|
items = Object.keys(this.itemMap);
|
|
|
|
let errors;
|
|
for (let itemName of values(items))
|
|
try {
|
|
if (!key || this.itemMap[itemName][key])
|
|
storage.fireEvent("sanitizer", "clear-" + itemName, [range, host]);
|
|
}
|
|
catch (e) {
|
|
errors = errors || {};
|
|
errors[itemName] = e;
|
|
util.dump("Error sanitizing " + itemName);
|
|
util.reportError(e);
|
|
}
|
|
return errors;
|
|
});
|
|
}
|
|
}, {
|
|
PERMS: {
|
|
unset: 0,
|
|
allow: 1,
|
|
deny: 2,
|
|
session: 8
|
|
},
|
|
|
|
UNPERMS: Class.Memoize(function () {
|
|
return iter(this.PERMS).map(Array.reverse).toObject();
|
|
}),
|
|
|
|
COMMANDS: {
|
|
"unset": /*L*/"Unset",
|
|
"allow": /*L*/"Allowed",
|
|
"deny": /*L*/"Denied",
|
|
"session": /*L*/"Allowed for the current session",
|
|
"list": /*L*/"List all cookies for domain",
|
|
"clear": /*L*/"Clear all cookies for domain",
|
|
"clear-persistent": /*L*/"Clear all persistent cookies for domain",
|
|
"clear-session": /*L*/"Clear all session cookies for domain"
|
|
},
|
|
|
|
argPrefMap: {
|
|
offlineapps: "offlineApps",
|
|
sitesettings: "siteSettings"
|
|
},
|
|
argToPref: function (arg) {
|
|
return Sanitizer.argPrefMap[arg] || arg;
|
|
},
|
|
prefToArg: function (pref) {
|
|
return pref.replace(/.*\./, "").toLowerCase();
|
|
},
|
|
|
|
iterCookies: function* iterCookies(host) {
|
|
for (let c of iter(services.cookies, Ci.nsICookie2))
|
|
if (!host || util.isSubdomain(c.rawHost, host) ||
|
|
c.host[0] == "." && c.host.length < host.length
|
|
&& host.endsWith(c.host))
|
|
yield c;
|
|
|
|
},
|
|
iterPermissions: function* iterPermissions(host) {
|
|
for (let p of iter(services.permissions, Ci.nsIPermission))
|
|
if (!host || util.isSubdomain(p.host, host))
|
|
yield p;
|
|
}
|
|
}, {
|
|
load: function initLoad(dactyl, modules, window) {
|
|
if (!sanitizer.firstRun++ && sanitizer.runAtShutdown && !sanitizer.ranAtShutdown)
|
|
sanitizer.sanitizeItems(null, Range(), null, "shutdown");
|
|
sanitizer.ranAtShutdown = false;
|
|
},
|
|
autocommands: function initAutocommands(dactyl, modules, window) {
|
|
const { autocommands } = modules;
|
|
|
|
storage.addObserver("sanitizer",
|
|
function (key, event, value) {
|
|
if (event == "domain")
|
|
autocommands.trigger("SanitizeDomain", { domain: value });
|
|
else if (!value[1])
|
|
autocommands.trigger("Sanitize", { name: event.substr("clear-".length), domain: value[1] });
|
|
}, window);
|
|
},
|
|
commands: function initCommands(dactyl, modules, window) {
|
|
const { commands } = modules;
|
|
commands.add(["sa[nitize]"],
|
|
"Clear private data",
|
|
function (args) {
|
|
if (args["-host"] && !args.length && !args.bang)
|
|
args[0] = "all";
|
|
|
|
let timespan = args["-timespan"] || modules.options["sanitizetimespan"];
|
|
|
|
let range = Range();
|
|
let [match, num, unit] = /^(\d+)([mhdw])$/.exec(timespan) || [];
|
|
range[args["-older"] ? "max" : "min"] =
|
|
match ? 1000 * (Date.now() - 1000 * parseInt(num, 10) * { m: 60, h: 3600, d: 3600 * 24, w: 3600 * 24 * 7 }[unit])
|
|
: (timespan[0] == "s" ? sanitizer.sessionStart : null);
|
|
|
|
let opt = modules.options.get("sanitizeitems");
|
|
if (args.bang)
|
|
dactyl.assert(args.length == 0, _("error.trailingCharacters"));
|
|
else {
|
|
dactyl.assert(args.length, _("error.argumentRequired"));
|
|
dactyl.assert(opt.validator(args), _("error.invalidArgument"));
|
|
opt = { __proto__: opt, value: args.slice() };
|
|
}
|
|
|
|
let items = Object.keys(sanitizer.itemMap)
|
|
.slice(1)
|
|
.filter(opt.has, opt);
|
|
|
|
function sanitize(items) {
|
|
sanitizer.range = range.native;
|
|
sanitizer.ignoreTimespan = range.min == null;
|
|
sanitizer.sanitizing = true;
|
|
if (args["-host"]) {
|
|
args["-host"].forEach(function (host) {
|
|
sanitizer.sanitizing = true;
|
|
sanitizer.sanitizeItems(items, range, host);
|
|
});
|
|
}
|
|
else
|
|
sanitizer.sanitize(items, range);
|
|
}
|
|
|
|
if ("all" == opt.value.find(i => (i == "all" ||
|
|
/^!/.test(i)))
|
|
&& !args["-host"])
|
|
|
|
modules.commandline.input(_("sanitize.prompt.deleteAll") + " ",
|
|
resp => {
|
|
if (resp.match(/^y(es)?$/i)) {
|
|
sanitize(items);
|
|
dactyl.echomsg(_("command.sanitize.allDeleted"));
|
|
}
|
|
else
|
|
dactyl.echo(_("command.sanitize.noneDeleted"));
|
|
});
|
|
else
|
|
sanitize(items);
|
|
|
|
}, {
|
|
argCount: "*", // FIXME: should be + and 0
|
|
bang: true,
|
|
completer: function (context) {
|
|
context.title = ["Privacy Item", "Description"];
|
|
context.completions = modules.options.get("sanitizeitems").values;
|
|
},
|
|
domains: function (args) { return args["-host"] || []; },
|
|
options: [
|
|
{
|
|
names: ["-host", "-h"],
|
|
description: "Only sanitize items referring to listed host or hosts",
|
|
completer: function (context, args) {
|
|
context.filters.push(item =>
|
|
!args["-host"].some(host => util.isSubdomain(item.text, host)));
|
|
modules.completion.domain(context);
|
|
},
|
|
type: modules.CommandOption.LIST
|
|
}, {
|
|
names: ["-older", "-o"],
|
|
description: "Sanitize items older than timespan",
|
|
type: modules.CommandOption.NOARG
|
|
}, {
|
|
names: ["-timespan", "-t"],
|
|
description: "Timespan for which to sanitize items",
|
|
completer: function (context) {
|
|
modules.options.get("sanitizetimespan").completer(context);
|
|
},
|
|
type: modules.CommandOption.STRING,
|
|
validator: function (arg) {
|
|
return modules.options.get("sanitizetimespan").validator(arg);
|
|
}
|
|
}
|
|
],
|
|
privateData: true
|
|
});
|
|
|
|
function getPerms(host) {
|
|
let uri = util.createURI(host);
|
|
if (uri)
|
|
return Sanitizer.UNPERMS[services.permissions.testPermission(uri, "cookie")];
|
|
return "unset";
|
|
}
|
|
function setPerms(host, perm) {
|
|
let uri = util.createURI(host);
|
|
services.permissions.remove(uri, "cookie");
|
|
services.permissions.add(uri, "cookie", Sanitizer.PERMS[perm]);
|
|
}
|
|
commands.add(["cookies", "ck"],
|
|
"Change cookie permissions for sites",
|
|
function (args) {
|
|
let host = args.shift();
|
|
let session = true;
|
|
if (!args.length)
|
|
args = modules.options["cookies"];
|
|
|
|
for (let cmd of args)
|
|
switch (cmd) {
|
|
case "clear":
|
|
for (let c of Sanitizer.iterCookies(host))
|
|
services.cookies.remove(c.host, c.name, c.path, false);
|
|
break;
|
|
case "clear-persistent":
|
|
session = false;
|
|
case "clear-session":
|
|
for (let c of Sanitizer.iterCookies(host))
|
|
if (c.isSession == session)
|
|
services.cookies.remove(c.host, c.name, c.path, false);
|
|
return;
|
|
|
|
case "list":
|
|
modules.commandline.commandOutput(template.tabular(
|
|
["Host", "Expiry (UTC)", "Path", "Name", "Value"],
|
|
["padding-right: 1em", "padding-right: 1em", "padding-right: 1em", "max-width: 12em; overflow: hidden;", "padding-left: 1ex;"],
|
|
Array.from(Sanitizer.iterCookies(host),
|
|
c => [
|
|
c.host,
|
|
c.isSession ? ["span", { highlight: "Enabled" }, "session"]
|
|
: (new Date(c.expiry * 1000).toJSON() || "Never").replace(/:\d\d\.000Z/, "").replace("T", " ").replace(/-/g, "/"),
|
|
c.path,
|
|
c.name,
|
|
c.value,
|
|
])));
|
|
return;
|
|
default:
|
|
util.assert(cmd in Sanitizer.PERMS, _("error.invalidArgument"));
|
|
setPerms(host, cmd);
|
|
}
|
|
}, {
|
|
argCount: "+",
|
|
completer: function (context, args) {
|
|
switch (args.completeArg) {
|
|
case 0:
|
|
modules.completion.visibleHosts(context);
|
|
context.title[1] = "Current Permissions";
|
|
context.keys.description = function desc(host) {
|
|
let count = [0, 0];
|
|
for (let c of Sanitizer.iterCookies(host))
|
|
count[c.isSession + 0]++;
|
|
return [Sanitizer.COMMANDS[getPerms(host)], " (session: ", count[1], " persistent: ", count[0], ")"].join("");
|
|
};
|
|
break;
|
|
case 1:
|
|
context.completions = iter(Sanitizer.COMMANDS);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
completion: function initCompletion(dactyl, modules, window) {
|
|
modules.completion.visibleHosts = function completeHosts(context) {
|
|
let res = util.visibleHosts(window.content);
|
|
if (context.filter && !res.some(host => host.includes(context.filter)))
|
|
res.push(context.filter);
|
|
|
|
context.title = ["Domain"];
|
|
context.anchored = false;
|
|
context.compare = modules.CompletionContext.Sort.unsorted;
|
|
context.keys = { text: identity, description: identity };
|
|
context.completions = res;
|
|
};
|
|
},
|
|
options: function initOptions(dactyl, modules) {
|
|
const options = modules.options;
|
|
|
|
options.add(["sanitizeitems", "si"],
|
|
"The default list of private items to sanitize",
|
|
"stringlist", "all",
|
|
{
|
|
get values() { return values(sanitizer.itemMap).toArray(); },
|
|
|
|
completer: function completer(context, extra) {
|
|
if (context.filter[0] == "!")
|
|
context.advance(1);
|
|
return completer.superapply(this, arguments);
|
|
},
|
|
|
|
has: function has(val) {
|
|
let res = this.value.find(v => (v == "all" || v.replace(/^!/, "") == val));
|
|
|
|
return res && !/^!/.test(res);
|
|
},
|
|
|
|
validator: function (values) {
|
|
return values.length &&
|
|
values.every(val => (val === "all" || hasOwnProp(sanitizer.itemMap, val.replace(/^!/, ""))));
|
|
}
|
|
});
|
|
|
|
options.add(["sanitizeshutdown", "ss"],
|
|
"The items to sanitize automatically at shutdown",
|
|
"stringlist", "",
|
|
{
|
|
initialValue: true,
|
|
get values() {
|
|
return Object.values(sanitizer.itemMap)
|
|
.filter(i => i.persistent || i.builtin);
|
|
},
|
|
getter: function () {
|
|
if (!sanitizer.runAtShutdown)
|
|
return [];
|
|
else
|
|
return Object.values(sanitizer.itemMap)
|
|
.filter(item => item.shouldSanitize(true))
|
|
.map(item => item.name);
|
|
},
|
|
setter: function (value) {
|
|
if (value.length === 0)
|
|
sanitizer.runAtShutdown = false;
|
|
else {
|
|
sanitizer.runAtShutdown = true;
|
|
let have = new RealSet(value);
|
|
for (let item of values(sanitizer.itemMap))
|
|
prefs.set(item.shutdownPref,
|
|
Boolean(have.has(item.name) ^ have.has("all")));
|
|
}
|
|
return value;
|
|
}
|
|
});
|
|
|
|
options.add(["sanitizetimespan", "sts"],
|
|
"The default sanitizer time span",
|
|
"string", "all",
|
|
{
|
|
completer: function (context) {
|
|
context.compare = context.constructor.Sort.Unsorted;
|
|
context.completions = this.values;
|
|
},
|
|
values: {
|
|
"all": "Everything",
|
|
"session": "The current session",
|
|
"10m": "Last ten minutes",
|
|
"1h": "Past hour",
|
|
"1d": "Past day",
|
|
"1w": "Past week"
|
|
},
|
|
validator: bind("test", /^(a(ll)?|s(ession)|\d+[mhdw])$/)
|
|
});
|
|
|
|
options.add(["cookies", "ck"],
|
|
"The default mode for newly added cookie permissions",
|
|
"stringlist", "session",
|
|
{ get values() { return Sanitizer.COMMANDS; }});
|
|
|
|
options.add(["cookieaccept", "ca"],
|
|
"When to accept cookies",
|
|
"string", "all",
|
|
{
|
|
PREF: "network.cookie.cookieBehavior",
|
|
values: [
|
|
["all", "Accept all cookies"],
|
|
["samesite", "Accept all non-third-party cookies"],
|
|
["none", "Accept no cookies"],
|
|
["visited", "Accept cookies from visited sites"]
|
|
],
|
|
getter: function () {
|
|
return (this.values[prefs.get(this.PREF)] || ["all"])[0];
|
|
},
|
|
setter: function (val) {
|
|
prefs.set(this.PREF, this.values.map(i => i[0]).indexOf(val));
|
|
return val;
|
|
},
|
|
initialValue: true,
|
|
persist: false
|
|
});
|
|
|
|
options.add(["cookielifetime", "cl"],
|
|
"The lifetime for which to accept cookies",
|
|
"string", "default", {
|
|
PREF: "network.cookie.lifetimePolicy",
|
|
PREF_DAYS: "network.cookie.lifetime.days",
|
|
values: [
|
|
["default", "The lifetime requested by the setter"],
|
|
["prompt", "Always prompt for a lifetime"],
|
|
["session", "The current session"]
|
|
],
|
|
getter: function () {
|
|
return (this.values[prefs.get(this.PREF)] || [prefs.get(this.PREF_DAYS)])[0];
|
|
},
|
|
setter: function (value) {
|
|
let val = this.values.map(i => i[0]).indexOf(value);
|
|
if (val > -1)
|
|
prefs.set(this.PREF, val);
|
|
else {
|
|
prefs.set(this.PREF, 3);
|
|
prefs.set(this.PREF_DAYS, parseInt(value));
|
|
}
|
|
},
|
|
initialValue: true,
|
|
persist: false,
|
|
validator: function validator(val) {
|
|
return parseInt(val) == val ||
|
|
validator.superapply(this, arguments);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
endModule();
|
|
|
|
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
|
|
|
|
// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript:
|