Better UX for overriding protocol-level permissions.

This commit is contained in:
hackademix 2018-10-06 01:16:25 +02:00
parent ddbd70416c
commit 55ccd14dfe
3 changed files with 74 additions and 25 deletions

View File

@ -175,11 +175,17 @@ addEventListener("unload", e => {
typesMap.clear();
let policySites = UI.policy.sites;
let domains = new Map();
let protocols = new Set();
function urlToLabel(url) {
let origin = Sites.origin(url);
let match = policySites.match(url);
if (match) return match;
if (match) {
if (match === url.protocol) {
protocols.add(match);
} else {
return match;
}
}
if (domains.has(origin)) {
if (justDomains) return domains.get(origin);
} else {
@ -207,6 +213,7 @@ addEventListener("unload", e => {
if (!justDomains) {
for (let domain of domains.values()) sitesSet.add(domain);
}
for (let protocol of protocols) sitesSet.add(protocol);
let sites = [...sitesSet];
for (let parsed of parsedSeen) {
sites.filter(s => parsed.label === s || domains.get(Sites.origin(parsed.url)) === s).forEach(m => {

View File

@ -155,6 +155,10 @@ label.https-only {
display: none;
}
.preset label.preset.override {
color: #555;
}
[data-preset="UNTRUSTED"] .https-only, [data-preset="DEFAULT"] .https-only {
visibility: hidden;
}

View File

@ -174,6 +174,13 @@ var UI = (() => {
function compareBy(prop, a, b) {
let x = a[prop], y = b[prop];
if (x.endsWith(":")) {
if (!y.endsWith(":")) {
return this.mainDomain ? 1 : -1;
}
} else if (y.endsWith(":")) {
return this.mainDomain ? -1 : 1;
}
return x > y ? 1 : x < y ? -1 : 0;
}
@ -542,10 +549,10 @@ var UI = (() => {
} else if (y === md) {
return 1;
}
return wrappedCompare(a, b);
return wrappedCompare.call(this, a, b);
}
}
let rows = [...this.allSiteRows()].sort(sorter);
let rows = [...this.allSiteRows()].sort(sorter.bind(this));
if (this.mainSite) {
let mainLabel = "." + this.mainDomain;
let topIdx = rows.findIndex(r => r._label === mainLabel);
@ -563,7 +570,8 @@ var UI = (() => {
}
sorter(a, b) {
return compareBy("domain", a, b) || compareBy("_label", a, b);
let cb = compareBy.bind(this);
return cb("domain", a, b) || cb("_label", a, b);
}
async tempTrustAll() {
@ -583,28 +591,36 @@ var UI = (() => {
createSiteRow(site, siteMatch, perms, contextMatch = null, sitesCount = this.sitesCount++) {
debug("Creating row for site: %s, matching %s / %s, %o", site, siteMatch, contextMatch, perms);
let policy = UI.policy;
let row = this.rowTemplate.cloneNode(true);
row.sitesCount = sitesCount;
let url;
try {
url = new URL(site);
if (siteMatch !== site && siteMatch === url.protocol) {
perms = policy.DEFAULT;
}
} catch (e) {
if (/^(\w+:)\/*$/.test(site)) {
url = {protocol: RegExp.$1, hostname: "", origin: site, pathname:""};
let hostname = Sites.toExternal(url.hostname);
debug("Lonely %o", url, Sites.isSecureDomainKey(siteMatch) || !hostname && url.protocol === "https:");
let hostname = "";
url = {protocol: RegExp.$1, hostname, origin: site, pathname:""};
debug("Lonely %o", url);
} else {
debug("Domain %s (%s)", site, siteMatch);
let protocol = Sites.isSecureDomainKey(site) ? "https:" : "http:";
let hostname = Sites.toggleSecureDomainKey(site, false);
url = {protocol, hostname, origin: `${protocol}://${site}`, pathname: "/"};
url = {protocol, hostname, origin: `${protocol}//${site}`, pathname: "/"};
}
}
let hostname = Sites.toExternal(url.hostname);
let domain = tld.getDomain(hostname);
let overrideDefault = url.protocol && site !== url.protocol ?
policy.get(url.protocol, contextMatch) : null;
if (overrideDefault && !overrideDefault.siteMatch) overrideDefault = null;
if (!siteMatch) {
let domain = tld.getDomain(hostname);
let disableDefault = false;
if (!siteMatch || siteMatch === url.protocol && site !== siteMatch) {
siteMatch = site;
}
let secure = Sites.isSecureDomainKey(siteMatch);
@ -654,23 +670,45 @@ var UI = (() => {
label.setAttribute("for", temp.id);
}
}
let policy = UI.policy;
let presetName = "CUSTOM";
for (let p of ["TRUSTED", "UNTRUSTED", "DEFAULT"]) {
let preset = policy[p];
switch (perms) {
case preset:
presetName = p;
break;
case preset.tempTwin:
presetName = `T_${p}`;
if (!presetName in UI.presets) {
let getPresetName = perms => {
let presetName = "CUSTOM";
for (let p of ["TRUSTED", "UNTRUSTED", "DEFAULT"]) {
let preset = policy[p];
switch (perms) {
case preset:
presetName = p;
break;
case preset.tempTwin:
presetName = `T_${p}`;
if (!presetName in UI.presets) {
presetName = p;
}
break;
}
break;
}
}
return presetName;
}
let presetName = getPresetName(perms);
if (overrideDefault) {
let overrideName = getPresetName(overrideDefault.perms);
if (overrideName) {
let override = row.querySelector(`.presets input[value="${overrideName}"]`);
if (override) {
let def = row.querySelector(`.presets input[value="DEFAULT"]`);
if (def && def !== override) {
let label = def.nextElementSibling;
label.title = def.title = `${override.title} (${overrideDefault.siteMatch})`;
label.textContent = override.nextElementSibling.textContent + "*";
label.classList.toggle("override", true);
def.dataset.override = overrideName;
def.style.backgroundImage = window.getComputedStyle(override, null).backgroundImage;
}
}
}
}
let tempFirst = true; // TODO: make it a preference
let unsafeMatch = keyStyle !== "secure" && keyStyle !== "full";
if (presetName === "DEFAULT" && (tempFirst || unsafeMatch)) {