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@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-r... + // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/p... + // 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) => {