[tor-commits] [pluggable-transports/snowflake-webext] 05/08: improvement: revoke 'background' permission when "Enabled" is off

gitolite role git at cupani.torproject.org
Wed Oct 12 14:28:54 UTC 2022


This is an automated email from the git hooks/post-receive script.

shelikhoo pushed a commit to branch main
in repository pluggable-transports/snowflake-webext.

commit 18a95215421d1d912cf945d97239a90083a765ae
Author: WofWca <wofwca at protonmail.com>
AuthorDate: Tue Jun 21 22:46:45 2022 +0300

    improvement: revoke 'background' permission when "Enabled" is off
---
 init-webext.js  | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 make.js         |  9 ++++---
 static/popup.js | 42 ++++++++++++++++++---------------
 webext/embed.js | 11 ++++++++-
 4 files changed, 104 insertions(+), 31 deletions(-)

diff --git a/init-webext.js b/init-webext.js
index cde7d5f..003fb7f 100644
--- a/init-webext.js
+++ b/init-webext.js
@@ -5,6 +5,40 @@
 UI
 */
 
+
+/**
+ * Decide whether we need to request or revoke the 'background' permission, and
+ * set the `runInBackground` storage value appropriately.
+ * @param {boolean | undefined} enabledSetting
+ * @param {boolean | undefined} runInBackgroundSetting
+ */
+function maybeChangeBackgroundPermission(enabledSetting, runInBackgroundSetting) {
+  const needBackgroundPermission =
+    runInBackgroundSetting
+    // When the extension is disabled, we need the permission to be revoked because
+    // otherwise it'll keep the browser process running for no reason.
+    && enabledSetting;
+  // Yes, this is called even if the permission is already in the state we need
+  // it to be in (granted/removed).
+  new Promise(r => {
+    chrome.permissions[needBackgroundPermission ? "request" : "remove"](
+      { permissions: ['background'] },
+      r
+    );
+  })
+  .then(success => {
+    // Currently the resolve value is `true` even when the permission was alrady granted
+    // before it was requested (already removed before it was revoked). TODO Need to make
+    // sure it's the desired behavior and if it needs to change.
+    // https://developer.chrome.com/docs/extensions/reference/permissions/#method-remove
+    // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/permissions/remove#return_value
+    // https://github.com/mdn/content/pull/17516
+    if (success) {
+      chrome.storage.local.set({ runInBackground: runInBackgroundSetting });
+    }
+  });
+}
+
 class WebExtUI extends UI {
 
   constructor() {
@@ -94,15 +128,38 @@ class WebExtUI extends UI {
     if (m.retry) {
       // FIXME: Can set a retrying state here
       this.tryProbe();
-      return;
+    } else if (m.enabled != undefined) {
+      (new Promise((resolve) => {
+        chrome.storage.local.set({ "snowflake-enabled": m.enabled }, resolve);
+      }))
+      .then(() => {
+        log("Stored toggle state");
+        this.initToggle();
+      });
+      if (
+        typeof SUPPORTS_WEBEXT_OPTIONAL_BACKGROUND_PERMISSION !== 'undefined'
+        // eslint-disable-next-line no-undef
+        && SUPPORTS_WEBEXT_OPTIONAL_BACKGROUND_PERMISSION
+      ) {
+        new Promise(r => chrome.storage.local.get({ runInBackground: false }, r))
+        .then(storage => {
+          maybeChangeBackgroundPermission(m.enabled, storage.runInBackground);
+        });
+      }
+    } else if (m.runInBackground != undefined) {
+      if (
+        typeof SUPPORTS_WEBEXT_OPTIONAL_BACKGROUND_PERMISSION !== 'undefined'
+        // eslint-disable-next-line no-undef
+        && SUPPORTS_WEBEXT_OPTIONAL_BACKGROUND_PERMISSION
+      ) {
+        new Promise(r => chrome.storage.local.get({ "snowflake-enabled": false }, r))
+        .then(storage => {
+          maybeChangeBackgroundPermission(storage["snowflake-enabled"], m.runInBackground);
+        });
+      }
+    } else {
+      log("Unrecognized message");
     }
-    (new Promise((resolve) => {
-      chrome.storage.local.set({ "snowflake-enabled": m.enabled }, resolve);
-    }))
-    .then(() => {
-      log("Stored toggle state");
-      this.initToggle();
-    });
   }
 
   onDisconnect() {
diff --git a/make.js b/make.js
index 63e4cb6..6116257 100755
--- a/make.js
+++ b/make.js
@@ -174,9 +174,6 @@ function buildWebext(browserEngine) {
   execSync(`rm -rf ${outDir} && mkdir ${outDir}`);
   execSync(`cp -r webext/. ${outDir}/`);
   execSync(`cp -r ${STATIC}/{${SHARED_FILES.join(',')}} ${outDir}/`, { shell: '/bin/bash' });
-  for (const [key, value] of Object.entries(definitions)) {
-    execSync(`sed -i "s/${key}/${value}/g" ${outDir}/popup.js`);
-  }
   {
     const manfestBasePath = `${outDir}/manifest_base.json`;
     const manifest = JSON.parse(readFileSync(manfestBasePath, 'utf-8'));
@@ -192,6 +189,12 @@ function buildWebext(browserEngine) {
   }
   copyTranslations(outDir);
   concatJS(outDir, 'webext', 'snowflake.js', '');
+  for (const [key, value] of Object.entries(definitions)) {
+    const commandStart = `sed -i "s/${key}/${value}/g" ${outDir}`;
+    execSync(`${commandStart}/popup.js`);
+    execSync(`${commandStart}/embed.js`);
+    execSync(`${commandStart}/snowflake.js`);
+  }
   console.log('Webextension prepared.');
 }
 task('webext', 'build the webextension', function() {
diff --git a/static/popup.js b/static/popup.js
index fc4c0e7..fa7b8ed 100644
--- a/static/popup.js
+++ b/static/popup.js
@@ -11,7 +11,10 @@ function setClass(elem, className, cond) {
 }
 
 class Popup {
-  constructor(getMsgFunc, changeFunc, retryFunc) {
+  /**
+   * @param {() => void} [onRunInBackgroundChange]
+   */
+  constructor(getMsgFunc, changeFunc, retryFunc, onRunInBackgroundChange) {
     this.getMsgFunc = getMsgFunc;
     this.enabled = document.getElementById('enabled');
     this.enabled.addEventListener('change', changeFunc);
@@ -34,26 +37,27 @@ class Popup {
       /** @type {HTMLInputElement} */
       const runInBackgroundInput = document.getElementById('run-in-background');
       document.getElementById('run-in-background-wrapper').classList.remove('display-none');
-      {
-        // Two-way bind the input to the permission.
-        new Promise(r => chrome.permissions.contains({ permissions: ['background'] }, r))
-        .then(contains => runInBackgroundInput.checked = contains);
-        chrome.permissions.onAdded.addListener(({ permissions }) => {
-          if (permissions.includes('background')) {
-            runInBackgroundInput.checked = true;
-          }
+      { // Two-way bind the input to the permission.
+        runInBackgroundInput.addEventListener('change', ({ target }) => {
+          onRunInBackgroundChange(target.checked);
+          // The permission request may be rejected, so only update the checkbox value inside
+          // the event listeners below. TODO Don't know if it's ok in terms of accessibility.
+          // Also maybe it's better looking in general to toggle the checkbox and toggle it back
+          // if the request is rejected.
+          target.checked = !target.checked;
         });
-        chrome.permissions.onRemoved.addListener(({ permissions }) => {
-          if (permissions.includes('background')) {
-            runInBackgroundInput.checked = false;
-          }
+
+        // The storage is the source of truth for `runInBackground`, not
+        // `chrome.permissions.contains({ permissions: ['background'] }`, because when the "Enabled"
+        // checkbox is off, we (may) revoke that permission.
+        new Promise(r => chrome.storage.local.get({ runInBackground: false }, r))
+        .then(({ runInBackground }) => {
+          runInBackgroundInput.checked = runInBackground;
         });
-        runInBackgroundInput.addEventListener('change', event => {
-          if (event.target.checked) {
-            new Promise(r => chrome.permissions.request({ permissions: ['background'] }, r))
-            .then(granted => event.target.checked = granted);
-          } else {
-            chrome.permissions.remove({ permissions: ['background'] });
+        chrome.storage.local.onChanged.addListener(changes => {
+          const runInBackgroundChange = changes.runInBackground;
+          if (runInBackgroundChange) {
+            runInBackgroundInput.checked = runInBackgroundChange.newValue;
           }
         });
       }
diff --git a/webext/embed.js b/webext/embed.js
index b41d266..90dbe46 100644
--- a/webext/embed.js
+++ b/webext/embed.js
@@ -13,7 +13,16 @@ window.onload = () => {
   const popup = new Popup(
     (...args) => chrome.i18n.getMessage(...args),
     (event) => port.postMessage({ enabled: event.target.checked }),
-    () => port.postMessage({ retry: true })
+    () => port.postMessage({ retry: true }),
+    (
+      (
+        typeof SUPPORTS_WEBEXT_OPTIONAL_BACKGROUND_PERMISSION !== 'undefined'
+        // eslint-disable-next-line no-undef
+        && SUPPORTS_WEBEXT_OPTIONAL_BACKGROUND_PERMISSION
+      )
+        ? (newValue) => port.postMessage({ runInBackground: newValue })
+        : undefined
+    )
   );
 
   port.onMessage.addListener((m) => {

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the tor-commits mailing list