mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-19 06:10:18 +01:00
768 lines
32 KiB
JavaScript
768 lines
32 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) date == null ||
|
|
(this.min == null || date >= this.min) && (this.max == null || date <= this.max),
|
|
|
|
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 () this.name }),
|
|
"1": Class.Property({ get: function () 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) (!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 () 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)) {
|
|
services.permissions.remove(util.createURI(p.host), p.type);
|
|
services.permissions.add(util.createURI(p.host), 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 [
|
|
item for (item of values(self.itemMap))
|
|
if (!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"], function () {
|
|
self.sanitizing = true;
|
|
sanitize.superapply(this, arguments);
|
|
sanitizer.sanitizeItems([item.name for (item of values(self.itemMap))
|
|
if (item.shouldSanitize(false))],
|
|
Range.fromArray(this.range || []));
|
|
}, this);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
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) {
|
|
if (!Ci.nsILoadContext)
|
|
return null;
|
|
|
|
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)
|
|
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)
|
|
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) Sanitizer.argPrefMap[arg] || arg,
|
|
prefToArg: function (pref) 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.host, "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;"],
|
|
([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]
|
|
for (c of Sanitizer.iterCookies(host)))));
|
|
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 = 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.contains(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" || hasOwnProperty(sanitizer.itemMap, val.replace(/^!/, ""))));
|
|
}
|
|
});
|
|
|
|
options.add(["sanitizeshutdown", "ss"],
|
|
"The items to sanitize automatically at shutdown",
|
|
"stringlist", "",
|
|
{
|
|
initialValue: true,
|
|
get values() {
|
|
return [i
|
|
for (i of values(sanitizer.itemMap))
|
|
if (i.persistent || i.builtin)];
|
|
},
|
|
getter: function () !sanitizer.runAtShutdown ? [] : [
|
|
item.name for (item of values(sanitizer.itemMap))
|
|
if (item.shouldSanitize(true))
|
|
],
|
|
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:
|