From 09d9b05a93776a4cec06ba0b14146cdec2bfd1a8 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Sat, 27 Nov 2021 12:05:25 -0600 Subject: [PATCH 01/23] Make nativeMessaging and proxy permissions optional --- src/manifest.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/manifest.json b/src/manifest.json index c236a9ab..ba11b450 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -18,16 +18,16 @@ "history", "idle", "management", - "nativeMessaging", "storage", "unlimitedStorage", "tabs", "webRequestBlocking", - "webRequest", - "proxy" + "webRequest" ], "optional_permissions": [ - "bookmarks" + "bookmarks", + "nativeMessaging", + "proxy" ], "browser_specific_settings": { "gecko": { From 66359941bfe19a8843ee7d6b4d84ebd423d1f15f Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Sat, 27 Nov 2021 12:05:59 -0600 Subject: [PATCH 02/23] Start updates to to options.html --- src/css/options.css | 49 ++++++++++++++++++++++++---- src/js/options.js | 49 +++++++++++++++++----------- src/options.html | 78 ++++++++++++++++++++++++++++++--------------- 3 files changed, 126 insertions(+), 50 deletions(-) diff --git a/src/css/options.css b/src/css/options.css index 9346afeb..bc7ed0e0 100644 --- a/src/css/options.css +++ b/src/css/options.css @@ -3,27 +3,62 @@ body { color: #202023; } -h3 { +h3:first-of-type { margin-block-start: 2.5rem; } -h3:first-of-type { - margin-block-start: 1rem; +label { + font-weight: bold; + display: flex; + align-items: flex-start; } -p, -label { +label > span { + padding-block-start: 3px; +} + +.settings-group { + margin-block-end: 16px; +} + +form { + display: flex; + flex-direction: column; +} + +p { color: rgb(74, 74, 79); } +.settings-group p { + margin-inline-start: 24px; + margin-block: 4px 8px; +} + +input[type="checkbox"] { + margin-inline: 0 8px; + inline-size: 16px; + block-size: 16px; +} + +button { + margin-inline: 0 auto; +} + +.keyboard-shortcut { + display: flex; + flex-direction: row; + justify-content: space-between; + max-width: 70%; +} + @media (prefers-color-scheme: dark) { body { background: #202023; color: #fff; } - p, - label { + p { color: rgb(177, 177, 179); } } diff --git a/src/js/options.js b/src/js/options.js index 025ae996..cd784000 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -1,18 +1,36 @@ const NUMBER_OF_KEYBOARD_SHORTCUTS = 10; -async function requestPermissions() { - const checkbox = document.querySelector("#bookmarksPermissions"); - if (checkbox.checked) { - const granted = await browser.permissions.request({permissions: ["bookmarks"]}); - if (!granted) { - checkbox.checked = false; - return; +document.querySelectorAll("[data-permission-id]").forEach( async(el) => { + const permissionId = el.dataset.permissionId; + const permissionEnabled = await browser.permissions.contains({ permissions: [permissionId] }); + el.checked = !!permissionEnabled; + el.addEventListener("change", async() => { + if (el.checked) { + const granted = await browser.permissions.request({ permissions: [permissionId] }); + if (!granted) { + el.checked = false; + return; + } + } else { + await browser.permissions.remove({ permissions: [permissionId] }); } - } else { - await browser.permissions.remove({permissions: ["bookmarks"]}); - } - browser.runtime.sendMessage({ method: "resetBookmarksContext" }); -} + + switch (permissionId) { + case "bookmarks": + browser.runtime.sendMessage({ method: "resetBookmarksContext" }); + break; + + case "nativeMessaging": + console.log("do native messaging things"); + console.log("if disabled - remove mozilla vpn proxy configurations"); + break; + + case "proxy": + console.log("do proxy things..."); + console.log("if disabled - remove proxy configurations"); + } + }); +}); async function enableDisableSync() { const checkbox = document.querySelector("#syncCheck"); @@ -26,12 +44,8 @@ async function enableDisableReplaceTab() { } async function setupOptions() { - const hasPermission = await browser.permissions.contains({permissions: ["bookmarks"]}); const { syncEnabled } = await browser.storage.local.get("syncEnabled"); const { replaceTabEnabled } = await browser.storage.local.get("replaceTabEnabled"); - if (hasPermission) { - document.querySelector("#bookmarksPermissions").checked = true; - } document.querySelector("#syncCheck").checked = !!syncEnabled; document.querySelector("#replaceTabCheck").checked = !!replaceTabEnabled; setupContainerShortcutSelects(); @@ -79,7 +93,6 @@ function resetOnboarding() { } document.addEventListener("DOMContentLoaded", setupOptions); -document.querySelector("#bookmarksPermissions").addEventListener( "change", requestPermissions); document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync); document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab); document.querySelector("button").addEventListener("click", resetOnboarding); @@ -87,4 +100,4 @@ document.querySelector("button").addEventListener("click", resetOnboarding); for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) { document.querySelector("#open_container_"+i) .addEventListener("change", storeShortcutChoice); -} \ No newline at end of file +} diff --git a/src/options.html b/src/options.html index 3f9b66c4..3a7ceee4 100644 --- a/src/options.html +++ b/src/options.html @@ -10,72 +10,100 @@

- -

+
+ +

+
+
+ +

+

+
+ +
+ +

+

+
+

- -

+
+ +

+
+

- -

+ +
+ +

+
+

-

-

-

-

-

-

-

-

-

-

+
+

This feature requires that Proxy permissions. This permission can be revoked at any time in Settings.

+ +
From 5a2e631ed377d11a364703ed47856fd5eeba9f1e Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Mon, 29 Nov 2021 13:13:58 -0600 Subject: [PATCH 04/23] Gate MozillaVPN tout on enabled permissions in edit container panels --- src/js/mozillaVpn.js | 6 +++ src/js/popup.js | 107 ++++++++++++++++++++++++------------------- 2 files changed, 67 insertions(+), 46 deletions(-) diff --git a/src/js/mozillaVpn.js b/src/js/mozillaVpn.js index feedd328..767f5848 100644 --- a/src/js/mozillaVpn.js +++ b/src/js/mozillaVpn.js @@ -156,6 +156,12 @@ const MozillaVPN = { }; }, + async requiredPermissionsEnabled() { + const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] }); + const nativeMessagingPermissionEnabled = await browser.permissions.contains({ permissions: ["nativeMessaging"] }); + return (proxyPermissionEnabled && nativeMessagingPermissionEnabled); + }, + async getProxyWarnings(proxyObj) { if (!proxyObj) { diff --git a/src/js/popup.js b/src/js/popup.js index 76673318..e28dc525 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -1438,6 +1438,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { async connectedCallback() { const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList"); const mozillaVpnCollapseEditContainerTout = mozillaVpnHiddenToutsList && mozillaVpnHiddenToutsList.find(tout => tout.name === this.toutName); + this.requiredPermissionsEnabled = await MozillaVPN.requiredPermissionsEnabled(); this.hideShowButton.addEventListener("click", this); @@ -1448,8 +1449,12 @@ Logic.registerPanel(P_CONTAINER_EDIT, { // Add listeners if (!this.classList.contains("has-attached-listeners")) { - this.primaryCta.addEventListener("click", () => { - MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn"); + this.primaryCta.addEventListener("click", async() => { + if (!this.requiredPermissionsEnabled) { + await browser.permissions.request({ permissions: ["proxy", "nativeMessaging"] }); + } else { + MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn"); + } }); this.switch.addEventListener("click", async() => { @@ -1519,11 +1524,18 @@ Logic.registerPanel(P_CONTAINER_EDIT, { const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" }); if (!mozillaVpnInstalled) { - this.hideEls(this.switch, this.switchLabel, this.currentServerButton); - this.subtitle.textContent = browser.i18n.getMessage("protectThisContainer"); - this.primaryCta.addEventListener("click", this); + if (!this.requiredPermissionsEnabled) { + this.subtitle.textContent = "This feature requires Native Messaging and Proxy permissions"; + this.subtitle.style.flex = "1 1 100%"; + this.subtitle.style.textAlign = "center"; + this.primaryCta.style.marginBlockStart = "8px"; + this.primaryCta.textContent = "Enable now"; // TODO + return this.expandUi(); + } else { + this.subtitle.textContent = browser.i18n.getMessage("protectThisContainer"); + } } else { // Mozilla VPN installed... @@ -1835,61 +1847,30 @@ Logic.registerPanel(P_CONTAINER_EDIT, { return; } - const proxyData = await proxifiedContainers.retrieve(identity.cookieStoreId); - if (proxyData) { - if (proxyData.proxy && proxyData.proxy.mozProxyEnabled && !mozillaVpnConnected) { + mozillaVpnUi.updateProxyDependentUi({}); + const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] }); + if (proxyPermissionEnabled) { + const proxyData = await proxifiedContainers.retrieve(identity.cookieStoreId); + if (proxyData) { + if (proxyData.proxy && proxyData.proxy.mozProxyEnabled && !mozillaVpnConnected) { + return; + } + mozillaVpnUi.updateProxyDependentUi(proxyData.proxy); return; } - mozillaVpnUi.updateProxyDependentUi(proxyData.proxy); - return; } - - mozillaVpnUi.updateProxyDependentUi({}); }, }); Logic.registerPanel(P_ADVANCED_PROXY_SETTINGS, { panelSelector: "#advanced-proxy-settings-panel", - async initialize(){ + async initialize() { this._proxyForm = document.querySelector(".advanced-proxy-panel-content"); this._advancedProxyInput = this._proxyForm.querySelector("#edit-advanced-proxy-input"); const clearAdvancedProxyInput = this._proxyForm.querySelector("#clear-advanced-proxy-input"); this._submitadvancedProxy = this._proxyForm.querySelector("#submit-advanced-proxy"); - const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] }); - if (!proxyPermissionEnabled) { - - // Restrict tabbing inside advanced proxy panel to proxy permissions ui - const panel = document.getElementById("advanced-proxy-settings-panel"); - const clickableEls = panel.querySelectorAll("button, a, input"); - clickableEls.forEach(el => { - if (!el.dataset.tabGroup && el.id !== "advanced-proxy-settings-return") { - el.tabindex = "-1"; - el.disabled = true; - } - }); - - // Show proxy permission overlay - const permissionsOverlay = document.getElementById("permissions-overlay"); - permissionsOverlay.style.display = "flex"; - - // Add "enable" button handling - const enableProxyPermissionsButton = document.getElementById("enable-proxy-permissions"); - enableProxyPermissionsButton.focus(); - enableProxyPermissionsButton.addEventListener("click", async() => { - const granted = await browser.permissions.request({ permissions: ["proxy"] }); - if (granted) { - permissionsOverlay.style.display = "none"; - // restore normal panel tabbing - clickableEls.forEach(el => { - el.tabindex = "0"; - el.disabled = false; - }); - } - }); - } - this._advancedProxyInput.addEventListener("keydown", (e) => { if (e.key !== "Enter") { this.hideInvalidEntryWarning(); @@ -1964,6 +1945,40 @@ Logic.registerPanel(P_ADVANCED_PROXY_SETTINGS, { const identity = Logic.currentIdentity(); const advancedProxyInput = document.getElementById("edit-advanced-proxy-input"); + const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] }); + if (!proxyPermissionEnabled) { + + // Restrict tabbing inside advanced proxy panel to proxy permissions ui + const panel = document.getElementById("advanced-proxy-settings-panel"); + const clickableEls = panel.querySelectorAll("button, a, input"); + clickableEls.forEach(el => { + if (!el.dataset.tabGroup && el.id !== "advanced-proxy-settings-return") { + el.setAttribute("tabindex", "-1"); + el.disabled = true; + } + }); + + // Show proxy permission overlay + const permissionsOverlay = document.getElementById("permissions-overlay"); + permissionsOverlay.style.display = "flex"; + + // Add "enable" button handling + const enableProxyPermissionsButton = document.getElementById("enable-proxy-permissions"); + + enableProxyPermissionsButton.addEventListener("click", async() => { + const granted = await browser.permissions.request({ permissions: ["proxy"] }); + if (granted) { + permissionsOverlay.style.display = "none"; + // restore normal panel tabbing + clickableEls.forEach(el => { + el.tabindex = "0"; + el.disabled = false; + }); + } + }); + } + + // reset input const resetProxyInput = () => { if (!advancedProxyInput) { From ed63f18cf1e81b9fc35b6cf5ec78bf63578e4bcc Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Mon, 29 Nov 2021 16:13:54 -0600 Subject: [PATCH 05/23] Lint roll --- src/css/options.css | 2 +- src/css/popup.css | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/css/options.css b/src/css/options.css index bc7ed0e0..9f314cdf 100644 --- a/src/css/options.css +++ b/src/css/options.css @@ -49,7 +49,7 @@ button { display: flex; flex-direction: row; justify-content: space-between; - max-width: 70%; + max-inline-size: 70%; } @media (prefers-color-scheme: dark) { diff --git a/src/css/popup.css b/src/css/popup.css index c7060b19..7c40de1e 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -2047,7 +2047,8 @@ tr:hover > td > .trash-button { align-content: center; flex-direction: column; background-color: white; - padding: 2.25rem; + padding-block: 2.25rem; + padding-inline: 2.25rem; display: none; } From 1b165aebb546dd6924ac220af3743f764b24c84a Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Mon, 29 Nov 2021 16:16:46 -0600 Subject: [PATCH 06/23] Handle proxy and nativeMessaging permission disabling + enabling --- src/js/background/assignManager.js | 9 ++++++++- src/js/background/messageHandler.js | 3 +++ src/js/mozillaVpn.js | 13 +++++++++++++ src/js/options.js | 14 ++++---------- src/options.html | 2 ++ 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index fd2ff5ce..e699fb3d 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -382,6 +382,13 @@ window.assignManager = { return currentContainerState && currentContainerState.isIsolated; }, + maybeAddProxyListeners() { + if (browser.proxy) { + browser.proxy.onRequest.addListener(this.handleProxifiedRequest, {urls: [""]}); + } + return; + }, + init() { browser.contextMenus.onClicked.addListener((info, tab) => { info.bookmarkId ? @@ -390,7 +397,7 @@ window.assignManager = { }); // Before anything happens we decide if the request should be proxified - browser.proxy.onRequest.addListener(this.handleProxifiedRequest, {urls: [""]}); + this.maybeAddProxyListeners(); // Before a request is handled by the browser we decide if we should // route through a different container diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index 37182bb0..883186a6 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -91,6 +91,9 @@ const messageHandler = { true ); break; + case "maybeAddProxyListeners": + response = await assignManager.maybeAddProxyListeners(); + break; case "assignAndReloadInContainer": tab = await assignManager.reloadPageInContainer( m.url, diff --git a/src/js/mozillaVpn.js b/src/js/mozillaVpn.js index 767f5848..0cb4a375 100644 --- a/src/js/mozillaVpn.js +++ b/src/js/mozillaVpn.js @@ -251,6 +251,19 @@ const MozillaVPN = { randomInteger = (randomInteger - server.weight); } return nextServer; + }, + + async removeMozillaVpnProxies() { + const proxies = await proxifiedContainers.retrieveAll(); + if (!proxies) { + return; + } + for (const proxyObj of proxies) { + const { proxy } = proxyObj; + if (proxy.countryCode !== undefined) { + await proxifiedContainers.delete(proxyObj.cookieStoreId); + } + } } }; diff --git a/src/js/options.js b/src/js/options.js index cd784000..c0c89ddd 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -14,20 +14,14 @@ document.querySelectorAll("[data-permission-id]").forEach( async(el) => { } else { await browser.permissions.remove({ permissions: [permissionId] }); } - switch (permissionId) { case "bookmarks": - browser.runtime.sendMessage({ method: "resetBookmarksContext" }); - break; - + return await browser.runtime.sendMessage({ method: "resetBookmarksContext" }); case "nativeMessaging": - console.log("do native messaging things"); - console.log("if disabled - remove mozilla vpn proxy configurations"); - break; - + await MozillaVPN.removeMozillaVpnProxies(); + return await browser.runtime.reload(); case "proxy": - console.log("do proxy things..."); - console.log("if disabled - remove proxy configurations"); + return await browser.runtime.sendMessage({ method: "maybeAddProxyListeners" }); } }); }); diff --git a/src/options.html b/src/options.html index 3a7ceee4..62f3f579 100644 --- a/src/options.html +++ b/src/options.html @@ -4,6 +4,8 @@ + + From c146a0bd1185096ce5fdc5c2a9ecf4aaec3bf2d6 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 30 Nov 2021 20:13:48 +0100 Subject: [PATCH 07/23] Move the permission observers in the background scripts --- src/js/background/assignManager.js | 1 - src/js/background/backgroundLogic.js | 34 +++++++++++++++++++++++ src/js/background/messageHandler.js | 6 ---- src/js/background/mozillaVpnBackground.js | 13 +++++++++ src/js/mozillaVpn.js | 13 --------- src/js/options.js | 9 ------ 6 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index e699fb3d..a7681222 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -386,7 +386,6 @@ window.assignManager = { if (browser.proxy) { browser.proxy.onRequest.addListener(this.handleProxifiedRequest, {urls: [""]}); } - return; }, init() { diff --git a/src/js/background/backgroundLogic.js b/src/js/background/backgroundLogic.js index 05cad399..0b414f95 100644 --- a/src/js/background/backgroundLogic.js +++ b/src/js/background/backgroundLogic.js @@ -19,6 +19,40 @@ const backgroundLogic = { } } }); + + browser.permissions.onAdded.addListener(permissions => { + permissions.permissions.forEach(permission => { + switch (permission) { + case "bookmarks": + break; + + case "nativeMessaging": + break; + + case "proxy": + assignManager.maybeAddProxyListeners(); + break; + } + }); + }); + browser.permissions.onRemoved.addListener(permissions => { + permissions.permissions.forEach(async permission => { + switch (permission) { + case "bookmarks": + assignManager.resetBookmarksMenuItem(); + break; + + case "nativeMessaging": + await MozillaVPN_Background.removeMozillaVpnProxies(); + await browser.runtime.reload(); + break; + + case "proxy": + break; + } + }); + }); + }, async getExtensionInfo() { diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index 883186a6..5d644b60 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -20,9 +20,6 @@ const messageHandler = { case "resetSync": response = sync.resetSync(); break; - case "resetBookmarksContext": - response = assignManager.resetBookmarksMenuItem(); - break; case "deleteContainer": response = backgroundLogic.deleteContainer(m.message.userContextId); break; @@ -91,9 +88,6 @@ const messageHandler = { true ); break; - case "maybeAddProxyListeners": - response = await assignManager.maybeAddProxyListeners(); - break; case "assignAndReloadInContainer": tab = await assignManager.reloadPageInContainer( m.url, diff --git a/src/js/background/mozillaVpnBackground.js b/src/js/background/mozillaVpnBackground.js index 8a127304..2711302d 100644 --- a/src/js/background/mozillaVpnBackground.js +++ b/src/js/background/mozillaVpnBackground.js @@ -100,6 +100,19 @@ const MozillaVPN_Background = { get isolationKey() { return this._isolationKey; }, + + async removeMozillaVpnProxies() { + const proxies = await proxifiedContainers.retrieveAll(); + if (!proxies) { + return; + } + for (const proxyObj of proxies) { + const { proxy } = proxyObj; + if (proxy.countryCode !== undefined) { + await proxifiedContainers.delete(proxyObj.cookieStoreId); + } + } + }, }; MozillaVPN_Background.init(); diff --git a/src/js/mozillaVpn.js b/src/js/mozillaVpn.js index 0cb4a375..d7f03b09 100644 --- a/src/js/mozillaVpn.js +++ b/src/js/mozillaVpn.js @@ -252,19 +252,6 @@ const MozillaVPN = { } return nextServer; }, - - async removeMozillaVpnProxies() { - const proxies = await proxifiedContainers.retrieveAll(); - if (!proxies) { - return; - } - for (const proxyObj of proxies) { - const { proxy } = proxyObj; - if (proxy.countryCode !== undefined) { - await proxifiedContainers.delete(proxyObj.cookieStoreId); - } - } - } }; window.MozillaVPN = MozillaVPN; diff --git a/src/js/options.js b/src/js/options.js index c0c89ddd..c8eba448 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -14,15 +14,6 @@ document.querySelectorAll("[data-permission-id]").forEach( async(el) => { } else { await browser.permissions.remove({ permissions: [permissionId] }); } - switch (permissionId) { - case "bookmarks": - return await browser.runtime.sendMessage({ method: "resetBookmarksContext" }); - case "nativeMessaging": - await MozillaVPN.removeMozillaVpnProxies(); - return await browser.runtime.reload(); - case "proxy": - return await browser.runtime.sendMessage({ method: "maybeAddProxyListeners" }); - } }); }); From ca861e2727e5b5b579d9cc3e523334adb2c04e3d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 3 Dec 2021 08:14:23 +0100 Subject: [PATCH 08/23] Permission handlers triggered on add and on remove --- src/js/background/backgroundLogic.js | 52 +++++++++++----------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/src/js/background/backgroundLogic.js b/src/js/background/backgroundLogic.js index 0b414f95..e682bba6 100644 --- a/src/js/background/backgroundLogic.js +++ b/src/js/background/backgroundLogic.js @@ -20,39 +20,27 @@ const backgroundLogic = { } }); - browser.permissions.onAdded.addListener(permissions => { - permissions.permissions.forEach(permission => { - switch (permission) { - case "bookmarks": - break; - - case "nativeMessaging": - break; - - case "proxy": - assignManager.maybeAddProxyListeners(); - break; - } - }); - }); - browser.permissions.onRemoved.addListener(permissions => { - permissions.permissions.forEach(async permission => { - switch (permission) { - case "bookmarks": - assignManager.resetBookmarksMenuItem(); - break; - - case "nativeMessaging": - await MozillaVPN_Background.removeMozillaVpnProxies(); - await browser.runtime.reload(); - break; - - case "proxy": - break; - } - }); - }); + browser.permissions.onAdded.addListener(permissions => this.resetPermissions(permissions)); + browser.permissions.onRemoved.addListener(permissions => this.resetPermissions(permissions)); + }, + resetPermissions(permissions) { + permissions.permissions.forEach(async permission => { + switch (permission) { + case "bookmarks": + assignManager.resetBookmarksMenuItem(); + break; + + case "nativeMessaging": + await MozillaVPN_Background.removeMozillaVpnProxies(); + await browser.runtime.reload(); + break; + + case "proxy": + assignManager.maybeAddProxyListeners(); + break; + } + }); }, async getExtensionInfo() { From 07d7b0cad4c04492d40a00fff987dc74a5836b48 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 3 Dec 2021 11:37:48 +0100 Subject: [PATCH 09/23] Make the linter happy again --- bin/build-addon.sh | 2 +- package.json | 8 ++++---- src/js/background/backgroundLogic.js | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/bin/build-addon.sh b/bin/build-addon.sh index 0669b134..6c744c67 100755 --- a/bin/build-addon.sh +++ b/bin/build-addon.sh @@ -11,7 +11,7 @@ git submodule init || die git submodule update --remote --depth 1 src/_locales || die print Y "Installing dependencies..." -npm install || die +npm install --legacy-peer-deps || die print Y "Running tests..." npm test diff --git a/package.json b/package.json index 14143d37..7d5775f1 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,12 @@ }, "dependencies": {}, "devDependencies": { - "addons-linter": "^1.3.2", + "addons-linter": "^3.23.0", "ajv": "^6.6.3", "chai": "^4.2.0", - "eslint": "^6.6.0", - "eslint-plugin-no-unsanitized": "^2.0.0", - "eslint-plugin-promise": "^3.4.0", + "eslint": "^7.32.0", + "eslint-plugin-no-unsanitized": "^4.0.0", + "eslint-plugin-promise": "^5.2.0", "htmllint-cli": "0.0.7", "json": ">=10.0.0", "mocha": "^6.2.2", diff --git a/src/js/background/backgroundLogic.js b/src/js/background/backgroundLogic.js index e682bba6..7cf52161 100644 --- a/src/js/background/backgroundLogic.js +++ b/src/js/background/backgroundLogic.js @@ -27,18 +27,18 @@ const backgroundLogic = { resetPermissions(permissions) { permissions.permissions.forEach(async permission => { switch (permission) { - case "bookmarks": - assignManager.resetBookmarksMenuItem(); - break; - - case "nativeMessaging": - await MozillaVPN_Background.removeMozillaVpnProxies(); - await browser.runtime.reload(); - break; - - case "proxy": - assignManager.maybeAddProxyListeners(); - break; + case "bookmarks": + assignManager.resetBookmarksMenuItem(); + break; + + case "nativeMessaging": + await MozillaVPN_Background.removeMozillaVpnProxies(); + await browser.runtime.reload(); + break; + + case "proxy": + assignManager.maybeAddProxyListeners(); + break; } }); }, From 3c3b5ae705392f4e7fa2f98cd61fd9fcd45dad7f Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Sat, 4 Dec 2021 16:32:00 -0600 Subject: [PATCH 10/23] Add Mozilla VPN & Proxy permissions block to options.html --- src/css/options.css | 57 ++++++++++++++++++++++++++++++++++++++------- src/img/warning.svg | 17 ++++++++++++++ src/js/options.js | 12 +++++++++- src/options.html | 45 ++++++++++++++++++----------------- 4 files changed, 99 insertions(+), 32 deletions(-) create mode 100644 src/img/warning.svg diff --git a/src/css/options.css b/src/css/options.css index 9f314cdf..b2a72e26 100644 --- a/src/css/options.css +++ b/src/css/options.css @@ -1,6 +1,11 @@ body { + --grey10: #e7e7e7; + + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; background: #fff; - color: #202023; + color: rgb(74, 74, 79); + font-size: 13px; + overflow: hidden; } h3:first-of-type { @@ -8,13 +13,13 @@ h3:first-of-type { } label { - font-weight: bold; display: flex; - align-items: flex-start; + align-items: center; + font-size: 14px; } label > span { - padding-block-start: 3px; + padding-inline-end: 4px; } .settings-group { @@ -26,10 +31,6 @@ form { flex-direction: column; } -p { - color: rgb(74, 74, 79); -} - .settings-group p { margin-inline-start: 24px; margin-block: 4px 8px; @@ -37,6 +38,7 @@ p { input[type="checkbox"] { margin-inline: 0 8px; + margin-block: 1px auto; inline-size: 16px; block-size: 16px; } @@ -50,14 +52,51 @@ button { flex-direction: row; justify-content: space-between; max-inline-size: 70%; + align-items: center; +} + +.bold { + font-weight: 600; +} + +.moz-vpn-proxy-permissions { + border-radius: 1rem; + padding-inline: 4rem; + padding-block: 2rem 1rem; + margin-block: 0 2rem; + border: 1px solid var(--grey10); +} + +h3.moz-vpn-proxy-permissions-title { + margin-block: 0 1rem; + margin-inline: 0; + position: relative; +} + +.moz-vpn-proxy-permissions-title.show-warning::before { + background-image: url("/img/warning.svg"); + background-size: 24px; + background-repeat: no-repeat; + background-position: center; + position: absolute; + inset-inline-start: -2.5rem; + content: ""; + display: block; + block-size: 24px; + inline-size: 24px; } @media (prefers-color-scheme: dark) { body { - background: #202023; + background: #23212a; color: #fff; } + .moz-vpn-proxy-permissions { + border-color: transparent; + background-color: rgba(255, 255, 255, 0.05); + } + p { color: rgb(177, 177, 179); } diff --git a/src/img/warning.svg b/src/img/warning.svg new file mode 100644 index 00000000..89c275b3 --- /dev/null +++ b/src/img/warning.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/js/options.js b/src/js/options.js index c8eba448..78220aed 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -17,6 +17,16 @@ document.querySelectorAll("[data-permission-id]").forEach( async(el) => { }); }); +async function maybeShowPermissionsWarningIcon() { + const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled(); + if (!bothMozillaVpnPermissionsEnabled) { + const permissionsWarningEl = document.querySelector(".moz-vpn-proxy-permissions-title"); + if (permissionsWarningEl) { + permissionsWarningEl.classList.add("show-warning"); + } + } +} + async function enableDisableSync() { const checkbox = document.querySelector("#syncCheck"); await browser.storage.local.set({syncEnabled: !!checkbox.checked}); @@ -81,7 +91,7 @@ document.addEventListener("DOMContentLoaded", setupOptions); document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync); document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab); document.querySelector("button").addEventListener("click", resetOnboarding); - +maybeShowPermissionsWarningIcon(); for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) { document.querySelector("#open_container_"+i) .addEventListener("change", storeShortcutChoice); diff --git a/src/options.html b/src/options.html index 62f3f579..6ff3ad82 100644 --- a/src/options.html +++ b/src/options.html @@ -13,36 +13,37 @@

-
- -

+
+

+
+
+ +

+
+
+ +

+
+
-

-

-
- -
- -

-

+

-

@@ -52,7 +53,7 @@

From 396411f8b3d7449973f9464c6f49e27229b390d7 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Sun, 5 Dec 2021 16:48:42 -0600 Subject: [PATCH 11/23] Update panel - Badge the Options icon when proxy and/or nativeMessaging permissions are disabled. Remove on click, don't show again. - Use localized strings - Refactors + cleanup --- src/css/popup.css | 66 ++++++++++----------- src/js/mozillaVpn.js | 2 +- src/js/popup.js | 137 +++++++++++++++++++++++-------------------- src/popup.html | 26 ++++---- 4 files changed, 119 insertions(+), 112 deletions(-) diff --git a/src/css/popup.css b/src/css/popup.css index 7c40de1e..f063fdda 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -445,6 +445,7 @@ input:checked + .slider::before { /* Primary CTA Buttons */ .primary-cta { + block-size: 32px; background-color: var(--primaryCtaDefault); border: transparent; border-radius: 4px; @@ -481,10 +482,6 @@ input:checked + .slider::before { transition: opacity 0.1s ease-in-out, max-height 0.3s ease-in-out; } -#moz-vpn-tout.disappear { - animation: hideTout 0.2s ease-in forwards; -} - @keyframes appear { 0% { opacity: 0; @@ -497,22 +494,6 @@ input:checked + .slider::before { } } -@keyframes hideTout { - 0% { - transform: translateY(0%); - opacity: 1; - } - - 50% { - opacity: 1; - } - - 100% { - transform: translateY(20%); - opacity: 0; - } -} - /* Mozilla VPN Controller UI in Container Management Panel */ .moz-vpn-content, @@ -522,9 +503,6 @@ input:checked + .slider::before { flex-direction: column; padding-block: 16px; transition: max-height 0.3s ease-in-out, padding-block-end 0.2s ease-in-out; - - /* max-block-size: 56px; */ - min-block-size: 56px; box-shadow: 0 0 0 1px var(--hr-grey); } @@ -610,7 +588,8 @@ input.proxies { .moz-vpn-cta { block-size: 32px; - margin-block: 16px; + margin-block-start: 16px; + margin-block-end: 4px; margin-inline: var(--marginInline); text-align: center; } @@ -685,6 +664,7 @@ input.proxies { max-block-size: 0; opacity: 0; visibility: hidden; + display: none; background-color: var(--bgColor); transition: max-height 0.2s ease-in-out, opacity 0.2s ease-in-out, visibility 0.2s ease-in-out; } @@ -713,6 +693,7 @@ input.proxies { } .expanded .collapsible-content { + display: flex; max-block-size: 500px; opacity: 1; visibility: visible; @@ -1518,9 +1499,7 @@ manage things like container crud */ /* Panel footer */ .panel-footer { align-items: center; - background: #efefef; block-size: var(--footerHeight); - border-block-end: 1px solid #d8d8d8; color: #000; display: flex; font-size: 13px; @@ -1994,6 +1973,24 @@ input { text-decoration: none; } +.info-icon-alert::after { + block-size: 12px; + inline-size: 12px; + background-color: var(--alertColor); + content: "1"; + border-radius: 50%; + position: absolute; + inset-block: -5px; + inset-inline-end: -6px; + box-shadow: 0 0 1px #00000075; + font-size: 8px; + color: white; + display: flex; + align-items: center; + justify-content: center; + font-weight: bolder; +} + .delete-warning { padding-block-end: 8px; padding-block-start: 8px; @@ -2035,7 +2032,9 @@ tr:hover > td > .trash-button { #advanced-proxy-settings-panel, .advanced-proxy-panel-content { - block-size: 100%; + position: absolute; + inset-block: 0; + inset-inline: 0; } .permissions-overlay { @@ -2053,17 +2052,12 @@ tr:hover > td > .trash-button { } #enable-proxy-permissions { - block-size: var(--rowHeight); text-align: center; font-family: var(--fontMetropolis); font-size: 14px; margin-block-start: 1rem; } -.permissions-overlay-copy { - text-align: center; -} - @media (prefers-color-scheme: dark) { :root { --iconCloseX: url("/img/close-light.svg"); @@ -2094,6 +2088,10 @@ tr:hover > td > .trash-button { --text-grey: #fefffe; } + .permissions-overlay { + background-color: #494755; + } + .tooltip { background-color: var(--controllerActive); } @@ -2185,10 +2183,6 @@ tr:hover > td > .trash-button { background-color: #676767; } - .panel-footer { - border-block-end: solid 1px #4a4a4a; - } - input[type="text"]:focus { box-shadow: 0 0 0 3px var(--blue50); border-color: var(--blue30); diff --git a/src/js/mozillaVpn.js b/src/js/mozillaVpn.js index d7f03b09..9fc337a9 100644 --- a/src/js/mozillaVpn.js +++ b/src/js/mozillaVpn.js @@ -156,7 +156,7 @@ const MozillaVPN = { }; }, - async requiredPermissionsEnabled() { + async bothPermissionsEnabled() { const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] }); const nativeMessagingPermissionEnabled = await browser.permissions.contains({ permissions: ["nativeMessaging"] }); return (proxyPermissionEnabled && nativeMessagingPermissionEnabled); diff --git a/src/js/popup.js b/src/js/popup.js index e28dc525..51d34b04 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -662,24 +662,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, { // This method is called when the object is registered. async initialize() { - const mozillaVpnToutName = "moz-tout-main-panel"; - await browser.runtime.sendMessage({ method: "MozillaVPN_queryStatus" }); - Utils.addEnterHandler(document.querySelector("#moz-vpn-learn-more"), () => { - MozillaVPN.handleMozillaCtaClick("mac-main-panel-btn"); - window.close(); - }); - Utils.addEnterHandler(document.querySelector(".dismiss-moz-vpn-tout"), async() => { - const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList"); - if (typeof(mozillaVpnHiddenToutsList) === "undefined") { - await browser.storage.local.set({ "mozillaVpnHiddenToutsList": [] }); - } - document.querySelector("#moz-vpn-tout").classList.add("disappear"); - mozillaVpnHiddenToutsList.push({ - name: mozillaVpnToutName - }); - await browser.storage.local.set({ mozillaVpnHiddenToutsList }); - }); Utils.addEnterHandler(document.querySelector("#manage-containers-link"), (e) => { if (!e.target.classList.contains("disable-edit-containers")) { Logic.showPanel(MANAGE_CONTAINERS_PICKER); @@ -694,9 +677,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, { Utils.addEnterHandler(document.querySelector("#always-open-in"), () => { Logic.showPanel(ALWAYS_OPEN_IN_PICKER); }); - Utils.addEnterHandler(document.querySelector("#info-icon"), () => { - browser.runtime.openOptionsPage(); - }); Utils.addEnterHandler(document.querySelector("#sort-containers-link"), async () => { try { await browser.runtime.sendMessage({ @@ -708,16 +688,58 @@ Logic.registerPanel(P_CONTAINERS_LIST, { } }); + const mozillaVpnToutName = "moz-tout-main-panel"; + const mozillaVpnPermissionsWarningDotName = "moz-permissions-warning-dot"; + + let { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList"); + if (typeof(mozillaVpnHiddenToutsList) === "undefined") { + await browser.storage.local.set({ "mozillaVpnHiddenToutsList": [] }); + mozillaVpnHiddenToutsList = []; + } + + // Decide whether to show Mozilla VPN tout const mozVpnTout = document.getElementById("moz-vpn-tout"); const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" }); - if (mozillaVpnInstalled) { - return mozVpnTout.remove(); + const mozillaVpnToutShouldBeHidden = mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnToutName); + if (mozillaVpnInstalled || mozillaVpnToutShouldBeHidden) { + mozVpnTout.remove(); + } + + // Add handlers if tout is visible + const mozVpnDismissTout = document.querySelector(".dismiss-moz-vpn-tout"); + if (mozVpnDismissTout) { + Utils.addEnterHandler((mozVpnDismissTout), async() => { + mozVpnTout.remove(); + mozillaVpnHiddenToutsList.push({ + name: mozillaVpnToutName + }); + await browser.storage.local.set({ mozillaVpnHiddenToutsList }); + }); + + Utils.addEnterHandler(document.querySelector("#moz-vpn-learn-more"), () => { + MozillaVPN.handleMozillaCtaClick("mac-main-panel-btn"); + window.close(); + }); } - const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList"); - const mozillaVpnToutShouldBeHidden = mozillaVpnHiddenToutsList && mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnToutName); - if (mozillaVpnToutShouldBeHidden) { - return mozVpnTout.remove(); + + // Badge Options icon if both nativeMessaging and/or proxy permissions are disabled + const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled(); + const warningDotShouldBeHidden = mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnPermissionsWarningDotName); + const optionsIcon = document.getElementById("info-icon"); + if (optionsIcon && !bothMozillaVpnPermissionsEnabled && !warningDotShouldBeHidden) { + optionsIcon.classList.add("info-icon-alert"); } + + Utils.addEnterHandler((document.querySelector("#info-icon")), async() => { + browser.runtime.openOptionsPage(); + if (!mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnPermissionsWarningDotName)) { + optionsIcon.classList.remove("info-icon-alert"); + mozillaVpnHiddenToutsList.push({ + name: mozillaVpnPermissionsWarningDotName + }); + } + await browser.storage.local.set({ mozillaVpnHiddenToutsList }); + }); }, unregister() { @@ -799,7 +821,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, { Utils.addEnterHandler(showPanelButton, () => { Logic.showPanel(P_CONTAINER_INFO, identity); }); - } const list = document.querySelector("#identities-list"); @@ -1438,23 +1459,23 @@ Logic.registerPanel(P_CONTAINER_EDIT, { async connectedCallback() { const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList"); const mozillaVpnCollapseEditContainerTout = mozillaVpnHiddenToutsList && mozillaVpnHiddenToutsList.find(tout => tout.name === this.toutName); - this.requiredPermissionsEnabled = await MozillaVPN.requiredPermissionsEnabled(); + const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" }); this.hideShowButton.addEventListener("click", this); - if (mozillaVpnCollapseEditContainerTout) { + if (mozillaVpnCollapseEditContainerTout && !mozillaVpnInstalled) { this.collapseUi(); } // Add listeners if (!this.classList.contains("has-attached-listeners")) { + const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled(); this.primaryCta.addEventListener("click", async() => { - if (!this.requiredPermissionsEnabled) { - await browser.permissions.request({ permissions: ["proxy", "nativeMessaging"] }); - } else { - MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn"); + if (!bothMozillaVpnPermissionsEnabled && mozillaVpnInstalled) { + return await browser.permissions.request({ permissions: ["proxy", "nativeMessaging"] }); } + MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn"); }); this.switch.addEventListener("click", async() => { @@ -1507,7 +1528,6 @@ Logic.registerPanel(P_CONTAINER_EDIT, { await proxifiedContainers.set(id.cookieStoreId, proxy); this.switch.checked = true; this.updateProxyDependentUi(proxy); - } else { this.switch.checked = false; return; @@ -1523,23 +1543,19 @@ Logic.registerPanel(P_CONTAINER_EDIT, { const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" }); const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" }); - if (!mozillaVpnInstalled) { - this.hideEls(this.switch, this.switchLabel, this.currentServerButton); + this.subtitle.textContent = browser.i18n.getMessage("protectThisContainer"); - if (!this.requiredPermissionsEnabled) { - this.subtitle.textContent = "This feature requires Native Messaging and Proxy permissions"; - this.subtitle.style.flex = "1 1 100%"; - this.subtitle.style.textAlign = "center"; - this.primaryCta.style.marginBlockStart = "8px"; - this.primaryCta.textContent = "Enable now"; // TODO - return this.expandUi(); - } else { - this.subtitle.textContent = browser.i18n.getMessage("protectThisContainer"); - } - } else { + const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled(); - // Mozilla VPN installed... + if (mozillaVpnInstalled && !bothMozillaVpnPermissionsEnabled) { + this.subtitle.style.flex = "1 1 100%"; + this.subtitle.textContent = browser.i18n.getMessage("additionalPermissionNeeded"); + this.hideEls(this.hideShowButton, this.switch, this.switchLabel); + this.primaryCta.textContent = "Enable"; + return; + } + if (mozillaVpnInstalled) { // Hide cta and hide/show button this.hideEls(this.primaryCta, this.hideShowButton); @@ -1547,7 +1563,11 @@ Logic.registerPanel(P_CONTAINER_EDIT, { this.subtitle.textContent = mozillaVpnConnected ? browser.i18n.getMessage("useCustomLocation") : browser.i18n.getMessage("mozillaVpnMustBeOn"); } - if (!mozillaVpnConnected) { + if (mozillaVpnConnected) { + [this.switchLabel, this.switch].forEach(el => { + el.style.display = "inline-block"; + }); + } else { this.hideEls(this.switch, this.switchLabel, this.currentServerButton); this.switch.checked = false; } @@ -1601,10 +1621,8 @@ Logic.registerPanel(P_CONTAINER_EDIT, { } async updateProxyDependentUi(proxyInfo) { - const containerHasProxy = typeof(proxyInfo) !== "undefined"; - const mozillaVpnProxyLocationAvailable = (proxy) => { - return typeof(proxy.countryCode) !== "undefined" && typeof(proxyInfo.cityName) !== "undefined"; + return typeof(proxy) !== "undefined" && typeof(proxy.countryCode) !== "undefined" && typeof(proxy.cityName) !== "undefined"; }; const mozillaVpnProxyIsEnabled = (proxy) => { @@ -1617,7 +1635,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" }); if ( - !containerHasProxy || + !proxyInfo || !mozillaVpnProxyLocationAvailable(proxyInfo) || !mozillaVpnConnected ) { @@ -1632,7 +1650,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { } // Populate inputs and server button with current or previously stored mozilla vpn proxy - if(containerHasProxy && mozillaVpnProxyLocationAvailable(proxyInfo)) { + if(proxyInfo && mozillaVpnProxyLocationAvailable(proxyInfo)) { this.currentCountryFlag.style.backgroundImage = `url("./img/flags/${proxyInfo.countryCode.toUpperCase()}.png")`; this.currentCountryFlag.style.backgroundImage = proxyInfo.countryCode + ".png"; this.currentCityName.textContent = proxyInfo.cityName; @@ -1643,12 +1661,10 @@ Logic.registerPanel(P_CONTAINER_EDIT, { expandUi() { this.classList.add("expanded"); - this.style.maxHeight = 500 + "px"; } collapseUi() { this.classList.remove("expanded"); - this.style.maxHeight = 56 + "px"; } hideEls(...els) { @@ -1847,17 +1863,14 @@ Logic.registerPanel(P_CONTAINER_EDIT, { return; } - mozillaVpnUi.updateProxyDependentUi({}); const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] }); if (proxyPermissionEnabled) { const proxyData = await proxifiedContainers.retrieve(identity.cookieStoreId); - if (proxyData) { - if (proxyData.proxy && proxyData.proxy.mozProxyEnabled && !mozillaVpnConnected) { - return; - } - mozillaVpnUi.updateProxyDependentUi(proxyData.proxy); + if (proxyData && proxyData.proxy.mozProxyEnabled && !mozillaVpnConnected) { return; } + const proxy = proxyData ? proxyData.proxy : {}; + mozillaVpnUi.updateProxyDependentUi(proxy); } }, }); diff --git a/src/popup.html b/src/popup.html index 2e55e577..586d0e5b 100644 --- a/src/popup.html +++ b/src/popup.html @@ -98,7 +98,7 @@

-
- - -
-
-
- -
- +
+ + +
+
+
+
+
- +
+
@@ -324,7 +324,7 @@

Mozilla VPN

- +
From 2fbb3e0087298948fd62c17c10ed8e397980adeb Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Sun, 5 Dec 2021 16:49:20 -0600 Subject: [PATCH 12/23] Hide Mozilla VPN proxy flags when proxy permission is disabled --- src/js/mozillaVpn.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/js/mozillaVpn.js b/src/js/mozillaVpn.js index 9fc337a9..08ec4d65 100644 --- a/src/js/mozillaVpn.js +++ b/src/js/mozillaVpn.js @@ -5,6 +5,11 @@ const MozillaVPN = { const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" }); this.handleStatusIndicatorsInContainerLists(mozillaVpnInstalled); + const permissionsEnabled = await this.bothPermissionsEnabled(); + if (!permissionsEnabled) { + return; + } + const proxies = await this.getProxies(identities); if (Object.keys(proxies).length === 0) { return; From 567a284196cd6ea07da3a971aa591e138d0e5449 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Mon, 6 Dec 2021 22:15:31 -0600 Subject: [PATCH 13/23] Update options page to latest UX --- src/css/options.css | 46 +++++++++++++++++++++++++++++++-------------- src/img/warning.svg | 16 +--------------- src/js/options.js | 2 +- src/options.html | 19 ++++++++++--------- 4 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/css/options.css b/src/css/options.css index b2a72e26..3ac77c0b 100644 --- a/src/css/options.css +++ b/src/css/options.css @@ -60,30 +60,53 @@ button { } .moz-vpn-proxy-permissions { - border-radius: 1rem; - padding-inline: 4rem; - padding-block: 2rem 1rem; margin-block: 0 2rem; - border: 1px solid var(--grey10); + padding-block-end: 1rem; + border-block-end: 1px solid var(--grey10); + display: flex; + flex-direction: column; } h3.moz-vpn-proxy-permissions-title { - margin-block: 0 1rem; - margin-inline: 0; + margin-block-start: 0; position: relative; + display: flex; + align-items: center; } -.moz-vpn-proxy-permissions-title.show-warning::before { +.warning-icon { + display: flex; + align-items: center; +} + +.warning-icon.show-warning::before { background-image: url("/img/warning.svg"); background-size: 24px; background-repeat: no-repeat; background-position: center; - position: absolute; - inset-inline-start: -2.5rem; content: ""; display: block; block-size: 24px; inline-size: 24px; + margin-inline-end: 0.5rem; +} + +.moz-vpn-proxy-permissions-title::before, +.moz-vpn-proxy-permissions-title::after { + background-color: var(--grey10); + content: ""; + height: 1px; + flex: 1 1 0%; +} + +h3.moz-vpn-proxy-permissions-title::before { + margin-inline-end: 2rem; + margin-inline-start: -50%; +} + +h3.moz-vpn-proxy-permissions-title::after { + margin-inline-start: 2rem; + margin-inline-end: -50%; } @media (prefers-color-scheme: dark) { @@ -92,11 +115,6 @@ h3.moz-vpn-proxy-permissions-title { color: #fff; } - .moz-vpn-proxy-permissions { - border-color: transparent; - background-color: rgba(255, 255, 255, 0.05); - } - p { color: rgb(177, 177, 179); } diff --git a/src/img/warning.svg b/src/img/warning.svg index 89c275b3..31b54308 100644 --- a/src/img/warning.svg +++ b/src/img/warning.svg @@ -1,17 +1,3 @@ - - - - - - - - - - - - - - - + diff --git a/src/js/options.js b/src/js/options.js index 78220aed..8bb8ccff 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -20,7 +20,7 @@ document.querySelectorAll("[data-permission-id]").forEach( async(el) => { async function maybeShowPermissionsWarningIcon() { const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled(); if (!bothMozillaVpnPermissionsEnabled) { - const permissionsWarningEl = document.querySelector(".moz-vpn-proxy-permissions-title"); + const permissionsWarningEl = document.querySelector(".warning-icon"); if (permissionsWarningEl) { permissionsWarningEl.classList.add("show-warning"); } diff --git a/src/options.html b/src/options.html index 6ff3ad82..45414784 100644 --- a/src/options.html +++ b/src/options.html @@ -12,9 +12,17 @@

- +
+ +

+
-

+

+ +

- -

-

-
- +
+ +

+

+
+
+ +
+
+
+ +
+
+ + +
@@ -176,7 +187,7 @@
- +
From 1f5245b0bc81ad2555a6047fe36817b07af068f7 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 8 Dec 2021 15:49:13 -0600 Subject: [PATCH 15/23] Update options page when permissions change (Jira 682, 686, 680) --- src/js/options.js | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/js/options.js b/src/js/options.js index 8bb8ccff..2d98a9b7 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -1,30 +1,31 @@ const NUMBER_OF_KEYBOARD_SHORTCUTS = 10; -document.querySelectorAll("[data-permission-id]").forEach( async(el) => { +async function setUpCheckBoxes() { + document.querySelectorAll("[data-permission-id]").forEach(async(el) => { + const permissionId = el.dataset.permissionId; + const permissionEnabled = await browser.permissions.contains({ permissions: [permissionId] }); + el.checked = !!permissionEnabled; + }); +} + +document.querySelectorAll("[data-permission-id").forEach(async(el) => { const permissionId = el.dataset.permissionId; - const permissionEnabled = await browser.permissions.contains({ permissions: [permissionId] }); - el.checked = !!permissionEnabled; el.addEventListener("change", async() => { if (el.checked) { const granted = await browser.permissions.request({ permissions: [permissionId] }); if (!granted) { el.checked = false; - return; } - } else { - await browser.permissions.remove({ permissions: [permissionId] }); + return; } + await browser.permissions.remove({ permissions: [permissionId] }); }); }); async function maybeShowPermissionsWarningIcon() { const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled(); - if (!bothMozillaVpnPermissionsEnabled) { - const permissionsWarningEl = document.querySelector(".warning-icon"); - if (permissionsWarningEl) { - permissionsWarningEl.classList.add("show-warning"); - } - } + const permissionsWarningEl = document.querySelector(".warning-icon"); + permissionsWarningEl.classList.toggle("show-warning", !bothMozillaVpnPermissionsEnabled); } async function enableDisableSync() { @@ -87,6 +88,14 @@ function resetOnboarding() { browser.storage.local.set({"onboarding-stage": 0}); } +async function resetPermissionsUi() { + await maybeShowPermissionsWarningIcon(); + await setUpCheckBoxes(); +} + +browser.permissions.onAdded.addListener(resetPermissionsUi); +browser.permissions.onRemoved.addListener(resetPermissionsUi); + document.addEventListener("DOMContentLoaded", setupOptions); document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync); document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab); @@ -96,3 +105,4 @@ for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) { document.querySelector("#open_container_"+i) .addEventListener("change", storeShortcutChoice); } +resetPermissionsUi(); From dc7b5ca396cce9f8b20cbf077787733a39b0a628 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 8 Dec 2021 15:58:30 -0600 Subject: [PATCH 16/23] Add sumo link to options page --- src/css/options.css | 1 + src/js/options.js | 16 +++++++++++++++- src/options.html | 4 +++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/css/options.css b/src/css/options.css index 3ac77c0b..5a6baf0f 100644 --- a/src/css/options.css +++ b/src/css/options.css @@ -29,6 +29,7 @@ label > span { form { display: flex; flex-direction: column; + padding-block-end: 1rem; } .settings-group p { diff --git a/src/js/options.js b/src/js/options.js index 2d98a9b7..311807a8 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -99,10 +99,24 @@ browser.permissions.onRemoved.addListener(resetPermissionsUi); document.addEventListener("DOMContentLoaded", setupOptions); document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync); document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab); -document.querySelector("button").addEventListener("click", resetOnboarding); maybeShowPermissionsWarningIcon(); for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) { document.querySelector("#open_container_"+i) .addEventListener("change", storeShortcutChoice); } + +document.querySelectorAll("[data-btn-id]").forEach(btn => { + btn.addEventListener("click", () => { + switch (btn.dataset.btnId) { + case "reset-onboarding": + resetOnboarding(); + break; + case "moz-vpn-learn-more": + browser.tabs.create({ + url: MozillaVPN.attachUtmParameters("https://support.mozilla.org/kb/protect-your-container-tabs-mozilla-vpn", "options-learn-more") + }); + break; + } + }); +}); resetPermissionsUi(); diff --git a/src/options.html b/src/options.html index 45414784..607c10a9 100644 --- a/src/options.html +++ b/src/options.html @@ -113,8 +113,10 @@

- +

+

Mozilla VPN

+ From 2361fc789932310d229a7fe53cae001ce66957b3 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 8 Dec 2021 14:59:04 -0800 Subject: [PATCH 17/23] Fix Windows UI edge cases (Jira - 683) --- src/js/popup.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/js/popup.js b/src/js/popup.js index 5842be22..11de2fc1 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -1488,9 +1488,11 @@ Logic.registerPanel(P_CONTAINER_EDIT, { const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled(); this.primaryCta.addEventListener("click", async() => { if (!bothMozillaVpnPermissionsEnabled && mozillaVpnInstalled) { - return await browser.permissions.request({ permissions: ["proxy", "nativeMessaging"] }); + await browser.permissions.request({ permissions: ["proxy", "nativeMessaging"] }); + } else { + MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn"); } - MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn"); + }); this.switch.addEventListener("click", async() => { @@ -1564,8 +1566,10 @@ Logic.registerPanel(P_CONTAINER_EDIT, { if (mozillaVpnInstalled && !bothMozillaVpnPermissionsEnabled) { this.subtitle.style.flex = "1 1 100%"; + this.classList.remove("show-server-button"); this.subtitle.textContent = browser.i18n.getMessage("additionalPermissionNeeded"); - this.hideEls(this.hideShowButton, this.switch, this.switchLabel); + this.hideEls(this.hideShowButton, this.switch, this.switchLabel, this.currentServerButton); + this.primaryCta.style.display = "block"; this.primaryCta.textContent = "Enable"; return; } @@ -1576,6 +1580,8 @@ Logic.registerPanel(P_CONTAINER_EDIT, { // Update subtitle this.subtitle.textContent = mozillaVpnConnected ? browser.i18n.getMessage("useCustomLocation") : browser.i18n.getMessage("mozillaVpnMustBeOn"); + this.subtitle.style.flex = "1 1 80%"; + this.currentServerButton.style.display = "flex"; } if (mozillaVpnConnected) { @@ -1716,6 +1722,10 @@ Logic.registerPanel(P_CONTAINER_EDIT, { customElements.define("moz-vpn-container-ui", MozVpnContainerUi); const mozillaVpnUi = document.querySelector("moz-vpn-container-ui"); mozillaVpnUi.updateMozVpnStatusDependentUi(); + + browser.permissions.onAdded.addListener(() => { mozillaVpnUi.updateMozVpnStatusDependentUi(); }); + browser.permissions.onRemoved.addListener(() => { mozillaVpnUi.updateMozVpnStatusDependentUi(); }); + const advancedProxySettingsButton = document.querySelector(".advanced-proxy-settings-btn"); Utils.addEnterHandler(advancedProxySettingsButton, () => { Logic.showPanel(P_ADVANCED_PROXY_SETTINGS, this.getEditInProgressIdentity(), false, false); From c91409646a6c0a333f831692822cb559f58676e1 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 8 Dec 2021 17:52:26 -0600 Subject: [PATCH 18/23] Use localized string --- src/js/popup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/popup.js b/src/js/popup.js index 11de2fc1..f7f62f20 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -1570,7 +1570,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { this.subtitle.textContent = browser.i18n.getMessage("additionalPermissionNeeded"); this.hideEls(this.hideShowButton, this.switch, this.switchLabel, this.currentServerButton); this.primaryCta.style.display = "block"; - this.primaryCta.textContent = "Enable"; + this.primaryCta.textContent = browser.i18n.getMessage("enable"); return; } From 29d586353c7a4c2b698be4e4b41c949637ee875e Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 8 Dec 2021 17:57:55 -0600 Subject: [PATCH 19/23] Fix onboarding panel buttons on Windows --- src/css/popup.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/css/popup.css b/src/css/popup.css index 414af8d0..c275a256 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -1338,6 +1338,7 @@ input[type=text] { .optional-permissions-disabled .moz-vpn-permissions { display: block; + width: 100%; } .moz-vpn-onboarding-content { From cbcae353a3c368397a340b541354c65493c596e3 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 8 Dec 2021 18:07:08 -0600 Subject: [PATCH 20/23] Use 'inline-size' instead of 'width' --- src/css/popup.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/popup.css b/src/css/popup.css index c275a256..0aaf85b2 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -1338,7 +1338,7 @@ input[type=text] { .optional-permissions-disabled .moz-vpn-permissions { display: block; - width: 100%; + inline-size: 100%; } .moz-vpn-onboarding-content { From e87be3df2ad51f57399b3c4e77674dea30ca9175 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Fri, 10 Dec 2021 11:49:31 -0600 Subject: [PATCH 21/23] Fix MAC-689 This prevents permission prompts from getting lost when multiple permission checkboxes are checked before their corresponding prompts are accepted or declined and one of the permissions requires a reboot when enabled (Jira ticket MAC-689) --- src/js/options.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/js/options.js b/src/js/options.js index 311807a8..726827b5 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -8,13 +8,27 @@ async function setUpCheckBoxes() { }); } +function disablePermissionsInputs() { + document.querySelectorAll("[data-permission-id").forEach(el => { + el.disabled = true; + }); +} + +function enablePermissionsInputs() { + document.querySelectorAll("[data-permission-id").forEach(el => { + el.disabled = false; + }); +} + document.querySelectorAll("[data-permission-id").forEach(async(el) => { const permissionId = el.dataset.permissionId; el.addEventListener("change", async() => { if (el.checked) { + disablePermissionsInputs(); const granted = await browser.permissions.request({ permissions: [permissionId] }); if (!granted) { el.checked = false; + enablePermissionsInputs(); } return; } @@ -91,6 +105,7 @@ function resetOnboarding() { async function resetPermissionsUi() { await maybeShowPermissionsWarningIcon(); await setUpCheckBoxes(); + enablePermissionsInputs(); } browser.permissions.onAdded.addListener(resetPermissionsUi); From 478a6dbdc56e2f408f7fd31ce43e31321900c1cc Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Tue, 14 Dec 2021 11:46:44 -0600 Subject: [PATCH 22/23] Address review comment --- src/js/mozillaVpn.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/js/mozillaVpn.js b/src/js/mozillaVpn.js index 08ec4d65..941e148a 100644 --- a/src/js/mozillaVpn.js +++ b/src/js/mozillaVpn.js @@ -162,9 +162,7 @@ const MozillaVPN = { }, async bothPermissionsEnabled() { - const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] }); - const nativeMessagingPermissionEnabled = await browser.permissions.contains({ permissions: ["nativeMessaging"] }); - return (proxyPermissionEnabled && nativeMessagingPermissionEnabled); + return await browser.permissions.contains({ permissions: ["proxy", "nativeMessaging"] }); }, From f544f4114580e21a18981f40a758604c23bee89a Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 14 Dec 2021 19:03:23 +0100 Subject: [PATCH 23/23] Fix travis builds --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 26424443..77ca72dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,6 @@ node_js: notifications: irc: - "ircs://irc.mozilla.org:6697/#testpilot-containers-bots" + +install: + - npm install --legacy-peer-deps