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(); typesMap.clear();
let policySites = UI.policy.sites; let policySites = UI.policy.sites;
let domains = new Map(); let domains = new Map();
let protocols = new Set();
function urlToLabel(url) { function urlToLabel(url) {
let origin = Sites.origin(url); let origin = Sites.origin(url);
let match = policySites.match(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 (domains.has(origin)) {
if (justDomains) return domains.get(origin); if (justDomains) return domains.get(origin);
} else { } else {
@ -207,6 +213,7 @@ addEventListener("unload", e => {
if (!justDomains) { if (!justDomains) {
for (let domain of domains.values()) sitesSet.add(domain); for (let domain of domains.values()) sitesSet.add(domain);
} }
for (let protocol of protocols) sitesSet.add(protocol);
let sites = [...sitesSet]; let sites = [...sitesSet];
for (let parsed of parsedSeen) { for (let parsed of parsedSeen) {
sites.filter(s => parsed.label === s || domains.get(Sites.origin(parsed.url)) === s).forEach(m => { 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; display: none;
} }
.preset label.preset.override {
color: #555;
}
[data-preset="UNTRUSTED"] .https-only, [data-preset="DEFAULT"] .https-only { [data-preset="UNTRUSTED"] .https-only, [data-preset="DEFAULT"] .https-only {
visibility: hidden; visibility: hidden;
} }

View File

@ -174,6 +174,13 @@ var UI = (() => {
function compareBy(prop, a, b) { function compareBy(prop, a, b) {
let x = a[prop], y = b[prop]; 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; return x > y ? 1 : x < y ? -1 : 0;
} }
@ -542,10 +549,10 @@ var UI = (() => {
} else if (y === md) { } else if (y === md) {
return 1; 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) { if (this.mainSite) {
let mainLabel = "." + this.mainDomain; let mainLabel = "." + this.mainDomain;
let topIdx = rows.findIndex(r => r._label === mainLabel); let topIdx = rows.findIndex(r => r._label === mainLabel);
@ -563,7 +570,8 @@ var UI = (() => {
} }
sorter(a, b) { 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() { async tempTrustAll() {
@ -583,28 +591,36 @@ var UI = (() => {
createSiteRow(site, siteMatch, perms, contextMatch = null, sitesCount = this.sitesCount++) { createSiteRow(site, siteMatch, perms, contextMatch = null, sitesCount = this.sitesCount++) {
debug("Creating row for site: %s, matching %s / %s, %o", site, siteMatch, contextMatch, perms); debug("Creating row for site: %s, matching %s / %s, %o", site, siteMatch, contextMatch, perms);
let policy = UI.policy;
let row = this.rowTemplate.cloneNode(true); let row = this.rowTemplate.cloneNode(true);
row.sitesCount = sitesCount; row.sitesCount = sitesCount;
let url; let url;
try { try {
url = new URL(site); url = new URL(site);
if (siteMatch !== site && siteMatch === url.protocol) {
perms = policy.DEFAULT;
}
} catch (e) { } catch (e) {
if (/^(\w+:)\/*$/.test(site)) { if (/^(\w+:)\/*$/.test(site)) {
url = {protocol: RegExp.$1, hostname: "", origin: site, pathname:""}; let hostname = "";
let hostname = Sites.toExternal(url.hostname); url = {protocol: RegExp.$1, hostname, origin: site, pathname:""};
debug("Lonely %o", url, Sites.isSecureDomainKey(siteMatch) || !hostname && url.protocol === "https:"); debug("Lonely %o", url);
} else { } else {
debug("Domain %s (%s)", site, siteMatch);
let protocol = Sites.isSecureDomainKey(site) ? "https:" : "http:"; let protocol = Sites.isSecureDomainKey(site) ? "https:" : "http:";
let hostname = Sites.toggleSecureDomainKey(site, false); 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 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; siteMatch = site;
} }
let secure = Sites.isSecureDomainKey(siteMatch); let secure = Sites.isSecureDomainKey(siteMatch);
@ -654,8 +670,8 @@ var UI = (() => {
label.setAttribute("for", temp.id); label.setAttribute("for", temp.id);
} }
} }
let policy = UI.policy;
let getPresetName = perms => {
let presetName = "CUSTOM"; let presetName = "CUSTOM";
for (let p of ["TRUSTED", "UNTRUSTED", "DEFAULT"]) { for (let p of ["TRUSTED", "UNTRUSTED", "DEFAULT"]) {
let preset = policy[p]; let preset = policy[p];
@ -671,6 +687,28 @@ var UI = (() => {
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 tempFirst = true; // TODO: make it a preference
let unsafeMatch = keyStyle !== "secure" && keyStyle !== "full"; let unsafeMatch = keyStyle !== "secure" && keyStyle !== "full";
if (presetName === "DEFAULT" && (tempFirst || unsafeMatch)) { if (presetName === "DEFAULT" && (tempFirst || unsafeMatch)) {