From f490c3a2dc089b419f1f5dea6f837174aa0bf472 Mon Sep 17 00:00:00 2001 From: erosman Date: Fri, 22 Dec 2023 10:53:53 +0330 Subject: [PATCH] v8.8 sync --- src/content/about.html | 1 + src/content/app.js | 1 + src/content/help.html | 18 ++++++++++-- src/content/migrate.js | 10 ++++++- src/content/on-request.js | 3 -- src/content/options.html | 2 +- src/content/options.js | 59 +++++++++++++++++++++------------------ src/content/sync.js | 30 ++++++-------------- 8 files changed, 68 insertions(+), 56 deletions(-) diff --git a/src/content/about.html b/src/content/about.html index 313e08c..deecad7 100644 --- a/src/content/about.html +++ b/src/content/about.html @@ -19,6 +19,7 @@

Changelog

8.8
Added Show hidden feature
Updated code to process duplicate hostname:port (#33, #76)
+
Updated sync process (#99)
Updated user interface to hide patterns on FoxyProxy Basic
8.7
diff --git a/src/content/app.js b/src/content/app.js index 326291e..c1bf08d 100644 --- a/src/content/app.js +++ b/src/content/app.js @@ -31,6 +31,7 @@ export class App { // ---------- User Preferences --------------------------- static defaultPref = JSON.stringify(pref); + static syncProperties = Object.keys(pref).filter(i => !['mode', 'sync', 'data'].includes(i)); static getDefaultPref() { return JSON.parse(this.defaultPref); diff --git a/src/content/help.html b/src/content/help.html index 48f8050..a56a54d 100644 --- a/src/content/help.html +++ b/src/content/help.html @@ -480,8 +480,14 @@

Storage quotas for sync data

  • Maximum number of items 512
  • -

    There is a discussion to increase the storage sync quota to 1MB.
    - See also: Discuss limits applied to storage.local and storage.sync API

    +
    +

    There is a discussion to increase the storage sync quota to 1MB.

    +

    See also:

    + +

    Auto Backup

    Automatically backup settings to the browser configured Downloads folder on save

    @@ -763,6 +769,14 @@

    Individual Proxy

    Proxy DNS (Firefox only)
    Option to pass DNS to the SOCKS proxy when using SOCKS
    +
    See also: + +
    PAC URL (not available on Android)
    Required for PAC type
    diff --git a/src/content/migrate.js b/src/content/migrate.js index 0dc6a84..1d18a6e 100644 --- a/src/content/migrate.js +++ b/src/content/migrate.js @@ -40,6 +40,14 @@ import {CryptoJS} from '../lib/aes.3.1.2.js'; export class Migrate { static async init(pref) { + // --- 8.8 + // tidy up left-over obj from 8.0 Sync typo mistake + if (Object.hasOwn(pref, 'obj')) { + delete pref.obj; + await browser.storage.local.remove('obj'); + await browser.storage.sync.remove('obj'); + } + // --- 8.7 // change global proxyDNS to per-proxy if (Object.hasOwn(pref, 'proxyDNS') && pref.data) { @@ -53,7 +61,7 @@ export class Migrate { if (Object.hasOwn(pref, 'globalExcludeWildcard')) { delete pref.globalExcludeWildcard; // from 8.0, removed in 8.1 delete pref.globalExcludeRegex; // from 8.0, removed in 8.1 - delete pref.obj; // 8.0 Sync typo error + delete pref.obj; // 8.0 Sync typo mistake await browser.storage.local.remove(['globalExcludeWildcard', 'globalExcludeRegex', 'obj']); } diff --git a/src/content/on-request.js b/src/content/on-request.js index c83eb10..0c6c24a 100644 --- a/src/content/on-request.js +++ b/src/content/on-request.js @@ -21,7 +21,6 @@ export class OnRequest { this.passthrough = []; // RegExp string this.net = []; // [start, end] strings this.showPatternProxy = false; - // this.proxyDNS = true; this.tabProxy = {}; // tab proxy, may be lost in MV3 if bg is unloaded this.container = {}; // incognito/container proxy @@ -41,9 +40,7 @@ export class OnRequest { const [passthrough, , net] = Pattern.getPassthrough(pref.passthrough); this.passthrough = passthrough; this.net = net; - this.showPatternProxy = pref.showPatternProxy; - // this.proxyDNS = pref.proxyDNS; // used in mode pattern or single proxy const data = pref.data.filter(i => i.active && i.type !== 'pac' && i.hostname); // filter data diff --git a/src/content/options.html b/src/content/options.html index 2ac8e5d..4f6ba62 100644 --- a/src/content/options.html +++ b/src/content/options.html @@ -587,7 +587,7 @@ - + diff --git a/src/content/options.js b/src/content/options.js index af4e000..61a9724 100644 --- a/src/content/options.js +++ b/src/content/options.js @@ -65,9 +65,6 @@ class Toggle { class Options { static { - this.sync = document.getElementById('sync'); - // this.proxyDNS = document.getElementById('proxyDNS'); - // --- container this.container = document.querySelectorAll('.options .container select'); @@ -80,8 +77,7 @@ class Options { // --- buttons document.querySelector('.options button[data-i18n="restoreDefaults"]').addEventListener('click', () => this.restoreDefaults()); - // this.init(['sync', 'proxyDNS', 'passthrough']); - this.init(['sync', 'showPatternProxy', 'autoBackup', 'passthrough']); + this.init(['sync', 'autoBackup', 'showPatternProxy', 'passthrough']); } static init(keys = Object.keys(pref)) { @@ -128,7 +124,6 @@ class Options { const id = pxy.type === 'pac' ? pxy.pac : `${pxy.hostname}:${pxy.port}`; cache[id] = pxy; } - const dataChanged = !App.equal(pref.data, data); // check if proxies & patterns have changed // no errors, update pref.data pref.data = data; @@ -145,7 +140,6 @@ class Options { checkSelect(i); container[i.name] = i.value; }); - // const containerChanged = Object.keys(container).some(i => container[i] !== pref.container[i]); pref.container = container; // set to pref // --- keyboard shortcut proxy @@ -154,28 +148,8 @@ class Options { checkSelect(i); commands[i.name] = i.value; }); - // const commandsChanged = Object.keys(commands).some(i => commands[i] !== pref.commands[i]); pref.commands = commands; // set to pref - // --- check sync - if (this.sync.checked) { - // convert array to object {...data} to avoid sync maximum item size limit - const obj = dataChanged ? {...data} : {}; - - pref.passthrough !== this.passthrough.value && (obj.passthrough = this.passthrough.value); - // pref.proxyDNS !== this.proxyDNS.checked && (obj.proxyDNS = this.proxyDNS.checked); - - // containerChanged && (obj.container = pref.container); - // commandsChanged && (obj.commands = pref.commands); - - // save changes to sync - Object.keys(obj)[0] && browser.storage.sync.set(obj) - .catch(error => { - App.notify(browser.i18n.getMessage('syncError') + '\n\n' + error.message); - this.sync.checked = false; // disabling sync option to avoid repeated errors - }); - } - // --- check mode // get from storage in case it was changed while options page has been open let {mode} = await browser.storage.local.get({mode: 'disable'}); @@ -196,6 +170,37 @@ class Options { // --- Auto Backup pref.autoBackup && ImportExport.export(pref, false); + + // --- Sync + this.sync(pref); + } + + static sync(pref) { + if (!pref.sync) { return; } + + // convert array to object {...data} to avoid sync maximum item size limit + const obj = {...pref.data}; + + // add other sync properties + App.syncProperties.forEach(i => obj[i] = pref[i]); + + // save changes to sync + browser.storage.sync.set(obj) + .then(() => { + // delete left-over proxies + browser.storage.sync.get() + .then(syncObj => { + // get & delete numerical keys that are equal or larger than data length, the rest are overwritten + const del = Object.keys(syncObj).filter(i => /^\d+$/.test(i) && i*1 >= pref.data.length); + del[0] && browser.storage.sync.remove(del); + }); + }) + .catch(error => { + App.notify(browser.i18n.getMessage('syncError') + '\n\n' + error.message); + // disabling sync option to avoid repeated errors + document.getElementById('sync').checked = false; + browser.storage.local.set({sync: false}); + }); } static async getProxyDetails(elem) { diff --git a/src/content/sync.js b/src/content/sync.js index 18d8abe..917bea2 100644 --- a/src/content/sync.js +++ b/src/content/sync.js @@ -3,34 +3,20 @@ import {App} from './app.js'; // ---------- Storage Sync --------------------------------- export class Sync { - static props = ['proxyDNS', 'passthrough']; - static init(pref) { if (pref.managed) { return; } // not for storage.managed - browser.storage.sync.onChanged.addListener(e => this.onChanged(e)); + // Chrome 73, Firefox 101 + // browser.storage.sync.onChanged.addListener(e => this.onChanged(e)); + // Firefox 45 + browser.storage.onChanged.addListener((...e) => this.onChanged(...e)); } - static async onChanged(changes) { - // no newValue on storage.local.clear() - if (!Object.hasOwn(Object.values(changes)[0] || {}, 'newValue')) { return; } + static async onChanged(changes, area) { + if (area !== 'sync') { return; } const pref = await browser.storage.local.get(); - if (!pref.sync) { return; } - - // convert object to array + filter null newValue (deleted) + map to newValue - const data = Object.values(changes) - .filter(i => Object.hasOwn(i.newValue || {}, 'hostname')) - .map(i => i.newValue); - - const obj = {}; - data[0] && !App.equal(pref.data, data) && (obj.data = data); - - this.props.forEach(item => { - Object.hasOwn(changes, item) && (obj[item] = changes[item].newValue); - }); - - Object.keys(obj)[0] && browser.storage.local.set(obj); // update local storage + this.getSync(pref); } static async get(pref) { @@ -87,7 +73,7 @@ export class Sync { pref.data = data; } - this.props.forEach(item => { + App.syncProperties.forEach(item => { if (Object.hasOwn(syncPref, item)) { obj[item] = syncPref[item]; pref[item] = syncPref[item];