From 24c960bed0058a6c57025d8bcf562cf2bebc1f2b Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 11 Dec 2019 18:49:55 -0600 Subject: [PATCH 01/60] first pass at container sync --- src/js/background/assignManager.js | 83 ++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index b48db75..eb02abb 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -240,7 +240,12 @@ const assignManager = { delete this.canceledRequests[options.tabId]; } },{urls: [""], types: ["main_frame"]}); + this.resetBookmarksMenuItem(); + + // Run when installed and on startup + browser.runtime.onInstalled.addListener(()=>{this.initSync()}); + browser.runtime.onStartup.addListener(()=>{this.initSync()}); }, async resetBookmarksMenuItem() { @@ -537,6 +542,84 @@ const assignManager = { browser.contextMenus.remove(identity.cookieStoreId); } } + + initSync() { + console.log("initSync"); + browser.storage.onChanged.addListener(runSync); + addContextualIdentityListeners(); + runSync(); + }, }; assignManager.init(); + +async function backup() { + browser.storage.onChanged.removeListener(runSync); + const identities = await browser.contextualIdentities.query({}); + console.log("backup", identities); + await browser.storage.sync.set({ identities: identities }); + const storage = await browser.storage.sync.get(); + console.log("in sync: ", storage); + browser.storage.onChanged.addListener(runSync); +} + +async function restore(inSync) { + removeContextualIdentityListeners(); + const syncIdentities = inSync.identities; + const browserIdentities = await browser.contextualIdentities.query({}); + + for (const syncIdentity of syncIdentities) { + const compareNames = function (browserIdentity) { return (browserIdentity.name == syncIdentity.name); }; + const match = browserIdentities.find(compareNames); + if (!match) { + browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + continue; + } else { + if (syncIdentity.color == match.color && syncIdentity.icon == match.icon) { + console.log("everything is the same:", syncIdentity, match); + continue; + } + console.log("somethings are different:", syncIdentity, match); + browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + } + } + backup(); + addContextualIdentityListeners(); +} + +async function runSync() { + console.log("runSync"); + const inSync = await browser.storage.sync.get(); + if (Object.entries(inSync).length === 0){ + console.log("no sync storage, backing up..."); + backup(); + } else { + console.log("storage found, attempting to restore ..."); + restore(inSync); + } +} + +function addContextualIdentityListeners() { + console.log("adding listeners"); + browser.contextualIdentities.onCreated.addListener(backup); + browser.contextualIdentities.onRemoved.addListener(backup); + browser.contextualIdentities.onUpdated.addListener(backup); +} + +function removeContextualIdentityListeners() { + browser.contextualIdentities.onCreated.removeListener(backup); + browser.contextualIdentities.onRemoved.removeListener(backup); + browser.contextualIdentities.onUpdated.removeListener(backup); +} + +async function runSync() { + console.log("runSync"); + const inSync = await browser.storage.sync.get(); + if (Object.entries(inSync).length === 0){ + console.log("no sync storage, backing up..."); + backup(); + } else { + console.log("storage found, attempting to restore ..."); + restore(inSync); + } +} From f5993add6f68b30383540108484216c509c83dda Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 12 Dec 2019 16:37:29 -0600 Subject: [PATCH 02/60] added uuids to contextualIdentities within MAC for comparison with other browsers --- src/js/background/assignManager.js | 101 ++++++++++++++++++++++++----- src/js/background/identityState.js | 32 ++++++++- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index eb02abb..c24dde6 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -1,3 +1,4 @@ +/* jshint esversion: 8*/ const assignManager = { MENU_ASSIGN_ID: "open-in-this-container", MENU_REMOVE_ID: "remove-open-in-this-container", @@ -9,6 +10,16 @@ const assignManager = { area: browser.storage.local, exemptedTabs: {}, + getSynced() { + const beenSynced = this.area.get("beenSynced"); + if (Object.entries(beenSynced).length === 0) return false; + return true; + }, + + setSynced() { + this.area.set({beenSynced: true}); + }, + getSiteStoreKey(pageUrl) { const url = new window.URL(pageUrl); const storagePrefix = "siteContainerMap@@_"; @@ -92,7 +103,20 @@ const assignManager = { } }); return sites; + }, + + async getAllAssignedSites() { + const sites = {}; + const siteConfigs = await this.area.get(); + for(const key of Object.keys(siteConfigs)) { + if (key.includes("siteContainerMap@@_")) { + const site = siteConfigs[key]; + sites[key] = site; + } + } + return sites; } + }, _neverAsk(m) { @@ -541,13 +565,18 @@ const assignManager = { for (const identity of identities) { browser.contextMenus.remove(identity.cookieStoreId); } - } + }, - initSync() { + async initSync() { console.log("initSync"); - browser.storage.onChanged.addListener(runSync); - addContextualIdentityListeners(); - runSync(); + // browser.storage.onChanged.addListener(runSync); + // addContextualIdentityListeners(); + const beenSynced = await assignManager.storageArea.getSynced(); + if (beenSynced){ + runSync(); + } else { + runFirstSync(); + } }, }; @@ -558,11 +587,42 @@ async function backup() { const identities = await browser.contextualIdentities.query({}); console.log("backup", identities); await browser.storage.sync.set({ identities: identities }); + const cookieStoreIDmap = await identityState.getCookieStoreIDuuidMap(); + await browser.storage.sync.set({ cookieStoreIDmap: cookieStoreIDmap }); + const assignedSites = await assignManager.storageArea.getAllAssignedSites(); + await browser.storage.sync.set({ assignedSites: assignedSites}); const storage = await browser.storage.sync.get(); console.log("in sync: ", storage); browser.storage.onChanged.addListener(runSync); } +browser.resetMAC = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.storage.onChanged.removeListener(runSync); + + // sync state on install: no sync data + // await browser.storage.sync.clear(); + + // FF1: no sync, Only default containers and 1 extra + // browser.storage.local.clear(); + // const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; + // browser.storage.local.set(localData); + + // sync state after FF1 (default + 1) + await browser.storage.sync.clear(); + const syncData = {"cookieStoreIDmap":{"firefox-container-1":"38eb85cc-0793-47c3-b51f-a4f1edf8908c","firefox-container-2":"19fcfbe5-c9ae-4445-8c8b-a7853e3d4462","firefox-container-3":"ac97270e-ccf6-4121-8d7f-74b764c5c78f","firefox-container-4":"595ae5cf-669c-4461-a738-05d3321d923e","firefox-container-6":"b39de7b4-b169-4128-bca3-e73f0376d9ed"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"userContextUUID":"38eb85cc-0793-47c3-b51f-a4f1edf8908c"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"userContextUUID":"19fcfbe5-c9ae-4445-8c8b-a7853e3d4462"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"userContextUUID":"595ae5cf-669c-4461-a738-05d3321d923e"}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; + browser.storage.sync.set(syncData); + + // FF2 (intial sync w/ default 4 + 1 with some changes) + removeContextualIdentityListeners(); + browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); + browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); + browser.storage.local.clear(); + const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + +}; + async function restore(inSync) { removeContextualIdentityListeners(); const syncIdentities = inSync.identities; @@ -600,7 +660,6 @@ async function runSync() { } function addContextualIdentityListeners() { - console.log("adding listeners"); browser.contextualIdentities.onCreated.addListener(backup); browser.contextualIdentities.onRemoved.addListener(backup); browser.contextualIdentities.onUpdated.addListener(backup); @@ -612,14 +671,26 @@ function removeContextualIdentityListeners() { browser.contextualIdentities.onUpdated.removeListener(backup); } -async function runSync() { - console.log("runSync"); - const inSync = await browser.storage.sync.get(); - if (Object.entries(inSync).length === 0){ - console.log("no sync storage, backing up..."); - backup(); - } else { - console.log("storage found, attempting to restore ..."); - restore(inSync); +async function runFirstSync() { + console.log("runFirstSync"); + const browserIdentities = await browser.contextualIdentities.query({}); + addUUIDsToContainers(browserIdentities); + connectUUIDsToAssignedSites(browserIdentities); + runSync(); + assignManager.storageArea.setSynced(); +} + +async function addUUIDsToContainers(browserIdentities) { + for (const identity of browserIdentities) { + identityState.addUUID(identity.cookieStoreId); } } + +async function connectUUIDsToAssignedSites(browserIdentities) { + const assignedSites = await assignManager.storageArea.getAllAssignedSites(); + for (const siteKey of Object.keys(assignedSites)) { + const identity = await identityState.storageArea.get("firefox-container-" + assignedSites[siteKey].userContextId); + assignedSites[siteKey].userContextUUID = identity.macUUID; + assignManager.storageArea.area.set({ [siteKey]: assignedSites[siteKey] }); + } +} \ No newline at end of file diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index fbb0020..9dd1cbb 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -1,3 +1,4 @@ +/* jshint esversion: 8*/ const identityState = { storageArea: { area: browser.storage.local, @@ -36,6 +37,19 @@ const identityState = { return Object.assign({}, tab); }, + async getCookieStoreIDuuidMap() { + const containers = {}; + const containerInfo = await identityState.storageArea.area.get(); + for(const key of Object.keys(containerInfo)) { + if (key.includes("identitiesState@@_")) { + const container = containerInfo[key]; + const cookieStoreId = key.replace(/^identitiesState@@_/, ""); + containers[cookieStoreId] = container.macUUID; + } + } + return containers; + }, + async storeHidden(cookieStoreId, windowId) { const containerState = await this.storageArea.get(cookieStoreId); const tabsByContainer = await browser.tabs.query({cookieStoreId, windowId}); @@ -53,10 +67,26 @@ const identityState = { return this.storageArea.set(cookieStoreId, containerState); }, + async updateUUID(cookieStoreId, uuid) { + const containerState = await this.storageArea.get(cookieStoreId); + containerState.macUUID = uuid; + return this.storageArea.set(cookieStoreId, containerState); + }, + async addUUID(cookieStoreId) { + return this.updateUUID(cookieStoreId, uuidv4()); + }, _createIdentityState() { return { - hiddenTabs: [] + hiddenTabs: [], + macUUID: uuidv4() }; }, }; + +function uuidv4() { + // https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript + return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => + (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) + ); +} \ No newline at end of file From efb83255fd99a27f79ebdac5bd6f745741643c53 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 16 Dec 2019 14:51:38 -0600 Subject: [PATCH 03/60] syncs on first run --- src/js/background/assignManager.js | 104 +++++++++++++++++++++++------ src/js/background/identityState.js | 14 ++++ 2 files changed, 99 insertions(+), 19 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index c24dde6..e3ceec5 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -569,8 +569,6 @@ const assignManager = { async initSync() { console.log("initSync"); - // browser.storage.onChanged.addListener(runSync); - // addContextualIdentityListeners(); const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ runSync(); @@ -596,21 +594,26 @@ async function backup() { browser.storage.onChanged.addListener(runSync); } -browser.resetMAC = async function () { +browser.resetMAC1 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created browser.storage.onChanged.removeListener(runSync); // sync state on install: no sync data - // await browser.storage.sync.clear(); + await browser.storage.sync.clear(); // FF1: no sync, Only default containers and 1 extra - // browser.storage.local.clear(); - // const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; - // browser.storage.local.set(localData); + browser.storage.local.clear(); + const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; + browser.storage.local.set(localData); +}; + +browser.resetMAC2 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.storage.onChanged.removeListener(runSync); // sync state after FF1 (default + 1) await browser.storage.sync.clear(); - const syncData = {"cookieStoreIDmap":{"firefox-container-1":"38eb85cc-0793-47c3-b51f-a4f1edf8908c","firefox-container-2":"19fcfbe5-c9ae-4445-8c8b-a7853e3d4462","firefox-container-3":"ac97270e-ccf6-4121-8d7f-74b764c5c78f","firefox-container-4":"595ae5cf-669c-4461-a738-05d3321d923e","firefox-container-6":"b39de7b4-b169-4128-bca3-e73f0376d9ed"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"userContextUUID":"38eb85cc-0793-47c3-b51f-a4f1edf8908c"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"userContextUUID":"19fcfbe5-c9ae-4445-8c8b-a7853e3d4462"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"userContextUUID":"595ae5cf-669c-4461-a738-05d3321d923e"}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; + const syncData = {"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; browser.storage.sync.set(syncData); // FF2 (intial sync w/ default 4 + 1 with some changes) @@ -618,7 +621,7 @@ browser.resetMAC = async function () { browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); browser.storage.local.clear(); - const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; browser.storage.local.set(localData); }; @@ -647,6 +650,62 @@ async function restore(inSync) { addContextualIdentityListeners(); } +async function restoreFirstRun(inSync) { + removeContextualIdentityListeners(); + const browserIdentities = await browser.contextualIdentities.query({}); + const syncIdentities = inSync.identities; + for (const syncIdentity of inSync.identities) { + const compareNames = function (browserIdentity) { return (browserIdentity.name == syncIdentity.name); }; + const match = browserIdentities.find(compareNames); + if (!match) { + newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macUUID); + continue; + } else { + if (syncIdentity.color == match.color && syncIdentity.icon == match.icon) { + console.log("everything is the same:", syncIdentity, match); + continue; + } + console.log("somethings are different:", syncIdentity, match); + browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + } + } + const assignedSitesBrowser = await assignManager.storageArea.getAllAssignedSites(); + console.log(assignedSitesBrowser); + const syncAssignedSites = inSync.assignedSites; + console.log(syncAssignedSites); + for(const key of Object.keys(syncAssignedSites)) { + if (assignedSitesBrowser.hasOwnProperty(key)) { + const syncCookieStoreId = "firefox-container-" + syncAssignedSites[key].userContextId; + const browserCookieStoreId = "firefox-container-" + assignedSitesBrowser[key].userContextId; + if (inSync.cookieStoreIDmap[syncCookieStoreId] == identityState.storageArea.get(browserCookieStoreId).macUUID) { + continue; + } else { + // ask user + } + } else { + const data = syncAssignedSites[key]; + console.log("data", data); + const newUUID = inSync.cookieStoreIDmap["firefox-container-" + data.userContextId]; + console.log("newUUID", newUUID); + data.userContextId = identityState.lookupCookieStoreId(newUUID); + console.log(data.userContextId); + assignManager.storageArea.set( + key.replace(/^siteContainerMap@@_/, "https://"), + data + ); + } + + + // if (String(syncAssignedSites[key].userContextId) === String(syncIdentity.userContextId)) { + // // const site = siteConfigs[key]; + // // sites[key] = site; + // } + } + backup(); + addContextualIdentityListeners(); +} + async function runSync() { console.log("runSync"); const inSync = await browser.storage.sync.get(); @@ -675,8 +734,15 @@ async function runFirstSync() { console.log("runFirstSync"); const browserIdentities = await browser.contextualIdentities.query({}); addUUIDsToContainers(browserIdentities); - connectUUIDsToAssignedSites(browserIdentities); - runSync(); + // connectUUIDsToAssignedSites(browserIdentities); + const inSync = await browser.storage.sync.get(); + if (Object.entries(inSync).length === 0){ + console.log("no sync storage, backing up..."); + backup(); + } else { + console.log("storage found, attempting to restore ..."); + restoreFirstRun(inSync); + } assignManager.storageArea.setSynced(); } @@ -686,11 +752,11 @@ async function addUUIDsToContainers(browserIdentities) { } } -async function connectUUIDsToAssignedSites(browserIdentities) { - const assignedSites = await assignManager.storageArea.getAllAssignedSites(); - for (const siteKey of Object.keys(assignedSites)) { - const identity = await identityState.storageArea.get("firefox-container-" + assignedSites[siteKey].userContextId); - assignedSites[siteKey].userContextUUID = identity.macUUID; - assignManager.storageArea.area.set({ [siteKey]: assignedSites[siteKey] }); - } -} \ No newline at end of file +// async function connectUUIDsToAssignedSites(browserIdentities) { +// const assignedSites = await assignManager.storageArea.getAllAssignedSites(); +// for (const siteKey of Object.keys(assignedSites)) { +// const identity = await identityState.storageArea.get("firefox-container-" + assignedSites[siteKey].userContextId); +// assignedSites[siteKey].userContextUUID = identity.macUUID; +// assignManager.storageArea.area.set({ [siteKey]: assignedSites[siteKey] }); +// } +// } \ No newline at end of file diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 9dd1cbb..ef29bc3 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -76,6 +76,20 @@ const identityState = { return this.updateUUID(cookieStoreId, uuidv4()); }, + async lookupCookieStoreId(macUUID) { + console.log("luCSI"); + const macConfigs = await this.storageArea.area.get(); + for(const key of Object.keys(macConfigs)) { + if (key.includes("identitiesState@@_")) { + if(macConfigs[key].macUUID === macUUID) { + console.log(key); + return key.replace(/^firefox-container-@@_/, ""); + } + } + } + return false; + }, + _createIdentityState() { return { hiddenTabs: [], From d98d0f16974f4310b479fc17eae99a1b8745f550 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 16 Dec 2019 14:59:11 -0600 Subject: [PATCH 04/60] a little linting, but not all the linting --- src/js/background/assignManager.js | 10 +++++----- src/js/background/identityState.js | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index e3ceec5..a654c1d 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -632,13 +632,13 @@ async function restore(inSync) { const browserIdentities = await browser.contextualIdentities.query({}); for (const syncIdentity of syncIdentities) { - const compareNames = function (browserIdentity) { return (browserIdentity.name == syncIdentity.name); }; + const compareNames = function (browserIdentity) { return (browserIdentity.name === syncIdentity.name); }; const match = browserIdentities.find(compareNames); if (!match) { browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); continue; } else { - if (syncIdentity.color == match.color && syncIdentity.icon == match.icon) { + if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { console.log("everything is the same:", syncIdentity, match); continue; } @@ -655,14 +655,14 @@ async function restoreFirstRun(inSync) { const browserIdentities = await browser.contextualIdentities.query({}); const syncIdentities = inSync.identities; for (const syncIdentity of inSync.identities) { - const compareNames = function (browserIdentity) { return (browserIdentity.name == syncIdentity.name); }; + const compareNames = function (browserIdentity) { return (browserIdentity.name === syncIdentity.name); }; const match = browserIdentities.find(compareNames); if (!match) { newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macUUID); continue; } else { - if (syncIdentity.color == match.color && syncIdentity.icon == match.icon) { + if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { console.log("everything is the same:", syncIdentity, match); continue; } @@ -678,7 +678,7 @@ async function restoreFirstRun(inSync) { if (assignedSitesBrowser.hasOwnProperty(key)) { const syncCookieStoreId = "firefox-container-" + syncAssignedSites[key].userContextId; const browserCookieStoreId = "firefox-container-" + assignedSitesBrowser[key].userContextId; - if (inSync.cookieStoreIDmap[syncCookieStoreId] == identityState.storageArea.get(browserCookieStoreId).macUUID) { + if (inSync.cookieStoreIDmap[syncCookieStoreId] === identityState.storageArea.get(browserCookieStoreId).macUUID) { continue; } else { // ask user diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index ef29bc3..843564a 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -77,12 +77,10 @@ const identityState = { }, async lookupCookieStoreId(macUUID) { - console.log("luCSI"); const macConfigs = await this.storageArea.area.get(); for(const key of Object.keys(macConfigs)) { if (key.includes("identitiesState@@_")) { if(macConfigs[key].macUUID === macUUID) { - console.log(key); return key.replace(/^firefox-container-@@_/, ""); } } From 9788e159ae12ed31793558579b36c1bf6b75a251 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 17 Dec 2019 14:55:52 -0600 Subject: [PATCH 05/60] cleanup of old code --- src/js/background/assignManager.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index a654c1d..7d0cc40 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -695,12 +695,6 @@ async function restoreFirstRun(inSync) { data ); } - - - // if (String(syncAssignedSites[key].userContextId) === String(syncIdentity.userContextId)) { - // // const site = siteConfigs[key]; - // // sites[key] = site; - // } } backup(); addContextualIdentityListeners(); @@ -734,7 +728,6 @@ async function runFirstSync() { console.log("runFirstSync"); const browserIdentities = await browser.contextualIdentities.query({}); addUUIDsToContainers(browserIdentities); - // connectUUIDsToAssignedSites(browserIdentities); const inSync = await browser.storage.sync.get(); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); @@ -751,12 +744,3 @@ async function addUUIDsToContainers(browserIdentities) { identityState.addUUID(identity.cookieStoreId); } } - -// async function connectUUIDsToAssignedSites(browserIdentities) { -// const assignedSites = await assignManager.storageArea.getAllAssignedSites(); -// for (const siteKey of Object.keys(assignedSites)) { -// const identity = await identityState.storageArea.get("firefox-container-" + assignedSites[siteKey].userContextId); -// assignedSites[siteKey].userContextUUID = identity.macUUID; -// assignManager.storageArea.area.set({ [siteKey]: assignedSites[siteKey] }); -// } -// } \ No newline at end of file From e8f8123c4cb6ed7f5cc098470b3d8bf1a73a03c8 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 17 Dec 2019 16:19:19 -0600 Subject: [PATCH 06/60] combined getByContainer and getAllAssignedSites --- src/js/background/assignManager.js | 43 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 7d0cc40..c517130 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -85,37 +85,42 @@ const assignManager = { }, async deleteContainer(userContextId) { - const sitesByContainer = await this.getByContainer(userContextId); + const sitesByContainer = await this.getAssignedSites(userContextId); this.area.remove(Object.keys(sitesByContainer)); }, - async getByContainer(userContextId) { + async getAssignedSites(userContextId = null) { const sites = {}; const siteConfigs = await this.area.get(); - Object.keys(siteConfigs).forEach((key) => { + for(const key of Object.keys(siteConfigs)) { + if (key.includes("siteContainerMap@@_")) { // For some reason this is stored as string... lets check them both as that - if (String(siteConfigs[key].userContextId) === String(userContextId)) { + if (!!userContextId && String(siteConfigs[key].userContextId) !== String(userContextId)) { + continue; + } const site = siteConfigs[key]; // In hindsight we should have stored this // TODO file a follow up to clean the storage onLoad site.hostname = key.replace(/^siteContainerMap@@_/, ""); sites[key] = site; } - }); + }; return sites; }, - async getAllAssignedSites() { - const sites = {}; - const siteConfigs = await this.area.get(); - for(const key of Object.keys(siteConfigs)) { - if (key.includes("siteContainerMap@@_")) { - const site = siteConfigs[key]; - sites[key] = site; - } - } - return sites; - } + // async getAssignedSites(userContextId = null) { + // const sites = {}; + // const siteConfigs = await this.area.get(); + // for(const key of Object.keys(siteConfigs)) { + // if (key.includes("siteContainerMap@@_")) { + // if(userContextId==null) { + // const site = siteConfigs[key]; + // sites[key] = site; + // } + // } + // } + // return sites; + // } }, @@ -446,7 +451,7 @@ const assignManager = { }, _getByContainer(userContextId) { - return this.storageArea.getByContainer(userContextId); + return this.storageArea.getAssignedSites(userContextId); }, removeContextMenu() { @@ -587,7 +592,7 @@ async function backup() { await browser.storage.sync.set({ identities: identities }); const cookieStoreIDmap = await identityState.getCookieStoreIDuuidMap(); await browser.storage.sync.set({ cookieStoreIDmap: cookieStoreIDmap }); - const assignedSites = await assignManager.storageArea.getAllAssignedSites(); + const assignedSites = await assignManager.storageArea.getAssignedSites(); await browser.storage.sync.set({ assignedSites: assignedSites}); const storage = await browser.storage.sync.get(); console.log("in sync: ", storage); @@ -670,7 +675,7 @@ async function restoreFirstRun(inSync) { browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); } } - const assignedSitesBrowser = await assignManager.storageArea.getAllAssignedSites(); + const assignedSitesBrowser = await assignManager.storageArea.getAssignedSites(); console.log(assignedSitesBrowser); const syncAssignedSites = inSync.assignedSites; console.log(syncAssignedSites); From adc1f5ffe6562ac3a0c71726bd19d0c00350c75b Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 17 Dec 2019 16:30:43 -0600 Subject: [PATCH 07/60] made some requested changes --- src/js/background/assignManager.js | 61 +++++++++++------------------- src/js/background/identityState.js | 10 ++--- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index c517130..1809c08 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -107,21 +107,6 @@ const assignManager = { }; return sites; }, - - // async getAssignedSites(userContextId = null) { - // const sites = {}; - // const siteConfigs = await this.area.get(); - // for(const key of Object.keys(siteConfigs)) { - // if (key.includes("siteContainerMap@@_")) { - // if(userContextId==null) { - // const site = siteConfigs[key]; - // sites[key] = site; - // } - // } - // } - // return sites; - // } - }, _neverAsk(m) { @@ -273,8 +258,8 @@ const assignManager = { this.resetBookmarksMenuItem(); // Run when installed and on startup - browser.runtime.onInstalled.addListener(()=>{this.initSync()}); - browser.runtime.onStartup.addListener(()=>{this.initSync()}); + browser.runtime.onInstalled.addListener(this.initSync); + browser.runtime.onStartup.addListener(this.initSync); }, async resetBookmarksMenuItem() { @@ -577,10 +562,10 @@ const assignManager = { const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ runSync(); - } else { - runFirstSync(); + return; } - }, + runFirstSync(); + }, }; assignManager.init(); @@ -622,7 +607,7 @@ browser.resetMAC2 = async function () { browser.storage.sync.set(syncData); // FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(); + removeContextualIdentityListeners(backup); browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); browser.storage.local.clear(); @@ -632,7 +617,7 @@ browser.resetMAC2 = async function () { }; async function restore(inSync) { - removeContextualIdentityListeners(); + removeContextualIdentityListeners(backup); const syncIdentities = inSync.identities; const browserIdentities = await browser.contextualIdentities.query({}); @@ -652,11 +637,11 @@ async function restore(inSync) { } } backup(); - addContextualIdentityListeners(); + addContextualIdentityListeners(backup); } async function restoreFirstRun(inSync) { - removeContextualIdentityListeners(); + removeContextualIdentityListeners(backup); const browserIdentities = await browser.contextualIdentities.query({}); const syncIdentities = inSync.identities; for (const syncIdentity of inSync.identities) { @@ -664,7 +649,7 @@ async function restoreFirstRun(inSync) { const match = browserIdentities.find(compareNames); if (!match) { newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macUUID); + identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); continue; } else { if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { @@ -683,7 +668,7 @@ async function restoreFirstRun(inSync) { if (assignedSitesBrowser.hasOwnProperty(key)) { const syncCookieStoreId = "firefox-container-" + syncAssignedSites[key].userContextId; const browserCookieStoreId = "firefox-container-" + assignedSitesBrowser[key].userContextId; - if (inSync.cookieStoreIDmap[syncCookieStoreId] === identityState.storageArea.get(browserCookieStoreId).macUUID) { + if (inSync.cookieStoreIDmap[syncCookieStoreId] === identityState.storageArea.get(browserCookieStoreId).macAddonUUID) { continue; } else { // ask user @@ -702,7 +687,7 @@ async function restoreFirstRun(inSync) { } } backup(); - addContextualIdentityListeners(); + addContextualIdentityListeners(backup); } async function runSync() { @@ -711,22 +696,22 @@ async function runSync() { if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); backup(); - } else { - console.log("storage found, attempting to restore ..."); - restore(inSync); + return; } + console.log("storage found, attempting to restore ..."); + restore(inSync); } -function addContextualIdentityListeners() { - browser.contextualIdentities.onCreated.addListener(backup); - browser.contextualIdentities.onRemoved.addListener(backup); - browser.contextualIdentities.onUpdated.addListener(backup); +function addContextualIdentityListeners(listener) { + browser.contextualIdentities.onCreated.addListener(listener); + browser.contextualIdentities.onRemoved.addListener(listener); + browser.contextualIdentities.onUpdated.addListener(listener); } -function removeContextualIdentityListeners() { - browser.contextualIdentities.onCreated.removeListener(backup); - browser.contextualIdentities.onRemoved.removeListener(backup); - browser.contextualIdentities.onUpdated.removeListener(backup); +function removeContextualIdentityListeners(listener) { + browser.contextualIdentities.onCreated.removeListener(listener); + browser.contextualIdentities.onRemoved.removeListener(listener); + browser.contextualIdentities.onUpdated.removeListener(listener); } async function runFirstSync() { diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 843564a..f3251c2 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -44,7 +44,7 @@ const identityState = { if (key.includes("identitiesState@@_")) { const container = containerInfo[key]; const cookieStoreId = key.replace(/^identitiesState@@_/, ""); - containers[cookieStoreId] = container.macUUID; + containers[cookieStoreId] = container.macAddonUUID; } } return containers; @@ -69,18 +69,18 @@ const identityState = { }, async updateUUID(cookieStoreId, uuid) { const containerState = await this.storageArea.get(cookieStoreId); - containerState.macUUID = uuid; + containerState.macAddonUUID = uuid; return this.storageArea.set(cookieStoreId, containerState); }, async addUUID(cookieStoreId) { return this.updateUUID(cookieStoreId, uuidv4()); }, - async lookupCookieStoreId(macUUID) { + async lookupCookieStoreId(macAddonUUID) { const macConfigs = await this.storageArea.area.get(); for(const key of Object.keys(macConfigs)) { if (key.includes("identitiesState@@_")) { - if(macConfigs[key].macUUID === macUUID) { + if(macConfigs[key].macAddonUUID === macAddonUUID) { return key.replace(/^firefox-container-@@_/, ""); } } @@ -91,7 +91,7 @@ const identityState = { _createIdentityState() { return { hiddenTabs: [], - macUUID: uuidv4() + macAddonUUID: uuidv4() }; }, }; From d61ea16db1f5b9b27b2be8ac47c065f3b48abfe3 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 17 Dec 2019 16:56:32 -0600 Subject: [PATCH 08/60] broke up restoreFristRun --- src/js/background/assignManager.js | 59 +++++++++++++++++++----------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 1809c08..7f05e5a 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -642,6 +642,17 @@ async function restore(inSync) { async function restoreFirstRun(inSync) { removeContextualIdentityListeners(backup); + await reconcileIdentitiesByName(inSync); + await reconcileSiteAssignments(inSync); + backup(); + addContextualIdentityListeners(backup); +} + +/* + * Checks for the container name. If it exists, they are assumed to be the same container, + * and the color and icon are overwritten from sync, if different. + */ +async function reconcileIdentitiesByName(inSync){ const browserIdentities = await browser.contextualIdentities.query({}); const syncIdentities = inSync.identities; for (const syncIdentity of inSync.identities) { @@ -651,15 +662,22 @@ async function restoreFirstRun(inSync) { newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); continue; - } else { - if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { - console.log("everything is the same:", syncIdentity, match); - continue; - } - console.log("somethings are different:", syncIdentity, match); - browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); } + if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { + console.log("everything is the same:", syncIdentity, match); + continue; + } + console.log("somethings are different:", syncIdentity, match); + browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); } +} + +/* + * Checks for site previously assigned. If it exists, and has the same container assignment, + * the assignment is kept. If it exists, but has a different assignment, the user is prompted + * (not yet implemented). If it does not exist, it is created. + */ +async function reconcileSiteAssignments(inSync) { const assignedSitesBrowser = await assignManager.storageArea.getAssignedSites(); console.log(assignedSitesBrowser); const syncAssignedSites = inSync.assignedSites; @@ -670,24 +688,21 @@ async function restoreFirstRun(inSync) { const browserCookieStoreId = "firefox-container-" + assignedSitesBrowser[key].userContextId; if (inSync.cookieStoreIDmap[syncCookieStoreId] === identityState.storageArea.get(browserCookieStoreId).macAddonUUID) { continue; - } else { - // ask user } - } else { - const data = syncAssignedSites[key]; - console.log("data", data); - const newUUID = inSync.cookieStoreIDmap["firefox-container-" + data.userContextId]; - console.log("newUUID", newUUID); - data.userContextId = identityState.lookupCookieStoreId(newUUID); - console.log(data.userContextId); - assignManager.storageArea.set( - key.replace(/^siteContainerMap@@_/, "https://"), - data - ); + // TODO: if uuids are not the same, ask user where to assign the site. + continue; } + const data = syncAssignedSites[key]; + console.log("data", data); + const newUUID = inSync.cookieStoreIDmap["firefox-container-" + data.userContextId]; + console.log("newUUID", newUUID); + data.userContextId = identityState.lookupCookieStoreId(newUUID); + console.log(data.userContextId); + assignManager.storageArea.set( + key.replace(/^siteContainerMap@@_/, "https://"), + data + ); } - backup(); - addContextualIdentityListeners(backup); } async function runSync() { From 88e32fc72f633c92a776a2daa253265b4616cec4 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 18 Dec 2019 13:57:19 -0600 Subject: [PATCH 09/60] added second run restore --- src/js/background/assignManager.js | 160 +++++++++++++++++++++-------- src/js/background/identityState.js | 14 ++- 2 files changed, 131 insertions(+), 43 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 7f05e5a..5732b16 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -581,7 +581,7 @@ async function backup() { await browser.storage.sync.set({ assignedSites: assignedSites}); const storage = await browser.storage.sync.get(); console.log("in sync: ", storage); - browser.storage.onChanged.addListener(runSync); + //browser.storage.onChanged.addListener(runSync); } browser.resetMAC1 = async function () { @@ -616,36 +616,80 @@ browser.resetMAC2 = async function () { }; +browser.resetMAC3 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.storage.onChanged.removeListener(runSync); + + // sync state after FF2 synced + await browser.storage.sync.clear(); + const syncData = {"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}],"cookieStoreIDmap":{"firefox-container-1":"021feeaa-fb44-49ce-91fb-673277afbf95","firefox-container-2":"7bc490d6-b711-46b7-b5a0-c48411e787d3","firefox-container-3":"65e15c60-c90a-40c1-ac61-ca95f21c9325","firefox-container-4":"4c0eb718-b43f-4f62-b2dc-d0c5f912fe5d","firefox-container-6":"266d9c04-fdd5-4d27-a44e-73c69b88ce0a"},"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"}}}; + browser.storage.sync.set(syncData); + + // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) + removeContextualIdentityListeners(backup); + browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); + //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); + browser.storage.local.clear(); + const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":10,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"a12c1ecf-52cd-4a2d-99e3-5e479b396f75"},"identitiesState@@_firefox-container-14":{"hiddenTabs":[],"macAddonUUID":"ee62f98b-6ec8-4ac7-9c6f-b76b1c3d91b4"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"d7d9a177-6bd4-4558-9495-03a8fb69443c"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"e04fc120-53cb-4d96-b960-b5ef8d285eca"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"eaff1081-32df-4dcc-aac4-a378655671ae"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"c9069f2f-346f-43c1-a071-8bcb74fa3fc2"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_www.hotjar.com":{"userContextId":"6","neverAsk":!0}}; + browser.storage.local.set(localData); + +}; + async function restore(inSync) { removeContextualIdentityListeners(backup); - const syncIdentities = inSync.identities; - const browserIdentities = await browser.contextualIdentities.query({}); - - for (const syncIdentity of syncIdentities) { - const compareNames = function (browserIdentity) { return (browserIdentity.name === syncIdentity.name); }; - const match = browserIdentities.find(compareNames); - if (!match) { - browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - continue; - } else { - if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { - console.log("everything is the same:", syncIdentity, match); - continue; - } - console.log("somethings are different:", syncIdentity, match); - browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - } - } - backup(); + browser.storage.onChanged.removeListener(runSync); + reconcileIdentitiesByUUID(inSync); + reconcileSiteAssignments(inSync); addContextualIdentityListeners(backup); + //browser.storage.onChanged.addListener(runSync); + backup(); +} + +/* + * Matches uuids in sync to uuids locally, and updates containers accordingly. + * If there is no match, it creates the new container. + */ +async function reconcileIdentitiesByUUID(inSync) { + const syncIdentities = inSync.identities; + const syncCookieStoreIDmap = inSync.cookieStoreIDmap; + + for (const syncCookieStoreID of Object.keys(syncCookieStoreIDmap)) { + const syncUUID = syncCookieStoreIDmap[syncCookieStoreID]; + //find localCookiesStoreID by looking up the syncUUID + const localCookieStoreID = await identityState.lookupCookieStoreId(syncUUID); + console.log("rIBU", localCookieStoreID); + // get correct indentity info from sync + identityInfo = findIdentityFromSync(syncCookieStoreID, syncIdentities); + console.log(identityInfo); + if (localCookieStoreID) { + // update the local container with the sync data + console.log(localCookieStoreID); + browser.contextualIdentities.update(localCookieStoreID, identityInfo); + continue; + } + //not found, create new with same UUID + const newIdentity = browser.contextualIdentities.create(identityInfo); + indentityState.updateUUID(newIdentity.cookieStoreId, syncUUID); + } +} + +function findIdentityFromSync(cookieStoreId, identitiesList){ + console.log(cookieStoreId, identitiesList); + for (const identity of identitiesList) { + const { name, color, icon } = identity; + if (identity.cookieStoreId === cookieStoreId) return { name, color, icon }; + } } async function restoreFirstRun(inSync) { removeContextualIdentityListeners(backup); + browser.storage.onChanged.removeListener(runSync); await reconcileIdentitiesByName(inSync); - await reconcileSiteAssignments(inSync); - backup(); + const firstRun = true; + await reconcileSiteAssignments(inSync, firstRun); addContextualIdentityListeners(backup); + browser.storage.onChanged.addListener(runSync); + backup(); } /* @@ -653,11 +697,13 @@ async function restoreFirstRun(inSync) { * and the color and icon are overwritten from sync, if different. */ async function reconcileIdentitiesByName(inSync){ - const browserIdentities = await browser.contextualIdentities.query({}); + const localIdentities = await browser.contextualIdentities.query({}); const syncIdentities = inSync.identities; + const cookieStoreIDmap = inSync.cookieStoreIDmap; for (const syncIdentity of inSync.identities) { - const compareNames = function (browserIdentity) { return (browserIdentity.name === syncIdentity.name); }; - const match = browserIdentities.find(compareNames); + syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; + const compareNames = function (localIdentity) { return (localIdentity.name === syncIdentity.name); }; + const match = localIdentities.find(compareNames); if (!match) { newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); @@ -665,10 +711,12 @@ async function reconcileIdentitiesByName(inSync){ } if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { console.log("everything is the same:", syncIdentity, match); + identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); continue; } console.log("somethings are different:", syncIdentity, match); browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); } } @@ -677,34 +725,62 @@ async function reconcileIdentitiesByName(inSync){ * the assignment is kept. If it exists, but has a different assignment, the user is prompted * (not yet implemented). If it does not exist, it is created. */ -async function reconcileSiteAssignments(inSync) { - const assignedSitesBrowser = await assignManager.storageArea.getAssignedSites(); - console.log(assignedSitesBrowser); +async function reconcileSiteAssignments(inSync, firstSync = false) { + const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); + console.log(assignedSitesLocal); const syncAssignedSites = inSync.assignedSites; console.log(syncAssignedSites); for(const key of Object.keys(syncAssignedSites)) { - if (assignedSitesBrowser.hasOwnProperty(key)) { + if (assignedSitesLocal.hasOwnProperty(key)) { const syncCookieStoreId = "firefox-container-" + syncAssignedSites[key].userContextId; - const browserCookieStoreId = "firefox-container-" + assignedSitesBrowser[key].userContextId; - if (inSync.cookieStoreIDmap[syncCookieStoreId] === identityState.storageArea.get(browserCookieStoreId).macAddonUUID) { + const syncUUID = await inSync.cookieStoreIDmap[syncCookieStoreId]; + const assignedSite = assignedSitesLocal[key]; + const localCookieStoreId = "firefox-container-" + assignedSite.userContextId; + if (syncUUID === identityState.storageArea.get(localCookieStoreId).macAddonUUID) { continue; } - // TODO: if uuids are not the same, ask user where to assign the site. + if (!firstSync) { + // overwrite with Sync data + setAsignmentWithUUID(syncUUID, assignedSite); + // assignedSite.userContextId = identityState.lookupCookieStoreId(syncUUID).replace(/^firefox-container-/, ""); + // assignManager.storageArea.set( + // key.replace(/^siteContainerMap@@_/, "https://"), + // assignedSite + // ); + continue; + } + // TODO: on First Sync only, if uuids are not the same, + // ask user where to assign the site. continue; } - const data = syncAssignedSites[key]; - console.log("data", data); - const newUUID = inSync.cookieStoreIDmap["firefox-container-" + data.userContextId]; + const assignedSite = syncAssignedSites[key]; + console.log("assignedSite", assignedSite); + const newUUID = await inSync.cookieStoreIDmap["firefox-container-" + assignedSite.userContextId]; console.log("newUUID", newUUID); - data.userContextId = identityState.lookupCookieStoreId(newUUID); - console.log(data.userContextId); + // setAsignmentWithUUID(newUUID, assignedSite); + const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); + assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); assignManager.storageArea.set( key.replace(/^siteContainerMap@@_/, "https://"), - data + assignedSite ); } } +async function setAsignmentWithUUID (newUUID, assignedSite) { + console.log("setAssingment UUID: ", newUUID); + const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); + console.log(cookieStoreId); + // if (cookieStoreId) { + assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); + console.log(assignedSite.userContextId); + assignManager.storageArea.set( + key.replace(/^siteContainerMap@@_/, "https://"), + assignedSite + ); + // } +} + async function runSync() { console.log("runSync"); const inSync = await browser.storage.sync.get(); @@ -731,8 +807,8 @@ function removeContextualIdentityListeners(listener) { async function runFirstSync() { console.log("runFirstSync"); - const browserIdentities = await browser.contextualIdentities.query({}); - addUUIDsToContainers(browserIdentities); + const localIdentities = await browser.contextualIdentities.query({}); + addUUIDsToContainers(localIdentities); const inSync = await browser.storage.sync.get(); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); @@ -744,8 +820,8 @@ async function runFirstSync() { assignManager.storageArea.setSynced(); } -async function addUUIDsToContainers(browserIdentities) { - for (const identity of browserIdentities) { +async function addUUIDsToContainers(localIdentities) { + for (const identity of localIdentities) { identityState.addUUID(identity.cookieStoreId); } } diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index f3251c2..bad1213 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -76,12 +76,24 @@ const identityState = { return this.updateUUID(cookieStoreId, uuidv4()); }, + async lookupMACaddonUUID(cookieStoreId) { + const macConfigs = await this.storageArea.area.get(); + for(const key of Object.keys(macConfigs)) { + if (key.includes("identitiesState@@_")) { + if(macConfigs[key] === cookieStoreId) { + return macConfigs[key].macAddonUUID; + } + } + } + return false; + }, + async lookupCookieStoreId(macAddonUUID) { const macConfigs = await this.storageArea.area.get(); for(const key of Object.keys(macConfigs)) { if (key.includes("identitiesState@@_")) { if(macConfigs[key].macAddonUUID === macAddonUUID) { - return key.replace(/^firefox-container-@@_/, ""); + return String(key).replace(/^identitiesState@@_/, ""); } } } From 27225df2810455398f31bec6b92fd68e28ac02b3 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 18 Dec 2019 22:06:08 -0600 Subject: [PATCH 10/60] added restore on previously synced browser --- src/js/background/assignManager.js | 134 ++++++++++++++--------------- src/js/background/identityState.js | 5 +- 2 files changed, 69 insertions(+), 70 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 5732b16..7141a93 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -10,8 +10,8 @@ const assignManager = { area: browser.storage.local, exemptedTabs: {}, - getSynced() { - const beenSynced = this.area.get("beenSynced"); + async getSynced() { + const beenSynced = await this.area.get("beenSynced"); if (Object.entries(beenSynced).length === 0) return false; return true; }, @@ -558,7 +558,10 @@ const assignManager = { }, async initSync() { - console.log("initSync"); + const syncInfo = await browser.storage.sync.get(); + const localInfo = await browser.storage.local.get(); + console.log("inSync: ", syncInfo); + console.log("inLocal: ", localInfo); const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ runSync(); @@ -571,9 +574,10 @@ const assignManager = { assignManager.init(); async function backup() { - browser.storage.onChanged.removeListener(runSync); + console.log("backup"); + browser.storage.onChanged.removeListener(syncOnChangedListener); + removeContextualIdentityListeners(backup); const identities = await browser.contextualIdentities.query({}); - console.log("backup", identities); await browser.storage.sync.set({ identities: identities }); const cookieStoreIDmap = await identityState.getCookieStoreIDuuidMap(); await browser.storage.sync.set({ cookieStoreIDmap: cookieStoreIDmap }); @@ -581,12 +585,15 @@ async function backup() { await browser.storage.sync.set({ assignedSites: assignedSites}); const storage = await browser.storage.sync.get(); console.log("in sync: ", storage); - //browser.storage.onChanged.addListener(runSync); + const localStorage = await browser.storage.local.get(); + console.log("inLocal:", localStorage); + //browser.storage.onChanged.addListener(syncOnChangedListener); + //addContextualIdentityListeners(backup); } browser.resetMAC1 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(runSync); + browser.storage.onChanged.removeListener(syncOnChangedListener); // sync state on install: no sync data await browser.storage.sync.clear(); @@ -599,7 +606,7 @@ browser.resetMAC1 = async function () { browser.resetMAC2 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(runSync); + browser.storage.onChanged.removeListener(syncOnChangedListener); // sync state after FF1 (default + 1) await browser.storage.sync.clear(); @@ -618,11 +625,11 @@ browser.resetMAC2 = async function () { browser.resetMAC3 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(runSync); + browser.storage.onChanged.removeListener(syncOnChangedListener); // sync state after FF2 synced await browser.storage.sync.clear(); - const syncData = {"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}],"cookieStoreIDmap":{"firefox-container-1":"021feeaa-fb44-49ce-91fb-673277afbf95","firefox-container-2":"7bc490d6-b711-46b7-b5a0-c48411e787d3","firefox-container-3":"65e15c60-c90a-40c1-ac61-ca95f21c9325","firefox-container-4":"4c0eb718-b43f-4f62-b2dc-d0c5f912fe5d","firefox-container-6":"266d9c04-fdd5-4d27-a44e-73c69b88ce0a"},"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"}}}; + const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; browser.storage.sync.set(syncData); // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) @@ -630,19 +637,20 @@ browser.resetMAC3 = async function () { browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); browser.storage.local.clear(); - const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":10,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"a12c1ecf-52cd-4a2d-99e3-5e479b396f75"},"identitiesState@@_firefox-container-14":{"hiddenTabs":[],"macAddonUUID":"ee62f98b-6ec8-4ac7-9c6f-b76b1c3d91b4"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"d7d9a177-6bd4-4558-9495-03a8fb69443c"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"e04fc120-53cb-4d96-b960-b5ef8d285eca"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"eaff1081-32df-4dcc-aac4-a378655671ae"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"c9069f2f-346f-43c1-a071-8bcb74fa3fc2"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_www.hotjar.com":{"userContextId":"6","neverAsk":!0}}; + const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; browser.storage.local.set(localData); }; async function restore(inSync) { - removeContextualIdentityListeners(backup); - browser.storage.onChanged.removeListener(runSync); - reconcileIdentitiesByUUID(inSync); - reconcileSiteAssignments(inSync); - addContextualIdentityListeners(backup); - //browser.storage.onChanged.addListener(runSync); - backup(); + console.log("restore"); + await reconcileIdentitiesByUUID(inSync); + await reconcileSiteAssignments(inSync); + await backup(); +} + +function syncOnChangedListener (changes, areaName) { + if (areaName == "sync") runSync(); } /* @@ -650,6 +658,7 @@ async function restore(inSync) { * If there is no match, it creates the new container. */ async function reconcileIdentitiesByUUID(inSync) { + console.log("reconcileIdentitiesByUUID"); const syncIdentities = inSync.identities; const syncCookieStoreIDmap = inSync.cookieStoreIDmap; @@ -657,24 +666,27 @@ async function reconcileIdentitiesByUUID(inSync) { const syncUUID = syncCookieStoreIDmap[syncCookieStoreID]; //find localCookiesStoreID by looking up the syncUUID const localCookieStoreID = await identityState.lookupCookieStoreId(syncUUID); - console.log("rIBU", localCookieStoreID); // get correct indentity info from sync identityInfo = findIdentityFromSync(syncCookieStoreID, syncIdentities); - console.log(identityInfo); if (localCookieStoreID) { + //for testing purposes: + const getIdent = await browser.contextualIdentities.get(localCookieStoreID); + if (getIdent.name !== identityInfo.name) {console.log(getIdent.name, "Change name: ", identityInfo.name)} + if (getIdent.color !== identityInfo.color) {console.log(getIdent.name, "Change color: ", identityInfo.color)} + if (getIdent.icon !== identityInfo.icon) {console.log(getIdent.name, "Change icon: ", identityInfo.icon)} // update the local container with the sync data - console.log(localCookieStoreID); - browser.contextualIdentities.update(localCookieStoreID, identityInfo); + await browser.contextualIdentities.update(localCookieStoreID, identityInfo); continue; } //not found, create new with same UUID - const newIdentity = browser.contextualIdentities.create(identityInfo); - indentityState.updateUUID(newIdentity.cookieStoreId, syncUUID); + console.log("new Identity: ", identityInfo.name) + const newIdentity = await browser.contextualIdentities.create(identityInfo); + console.log(newIdentity.cookieStoreId) + await identityState.updateUUID(newIdentity.cookieStoreId, syncUUID); } } function findIdentityFromSync(cookieStoreId, identitiesList){ - console.log(cookieStoreId, identitiesList); for (const identity of identitiesList) { const { name, color, icon } = identity; if (identity.cookieStoreId === cookieStoreId) return { name, color, icon }; @@ -682,13 +694,10 @@ function findIdentityFromSync(cookieStoreId, identitiesList){ } async function restoreFirstRun(inSync) { - removeContextualIdentityListeners(backup); - browser.storage.onChanged.removeListener(runSync); + console.log("restoreFirstRun"); await reconcileIdentitiesByName(inSync); const firstRun = true; await reconcileSiteAssignments(inSync, firstRun); - addContextualIdentityListeners(backup); - browser.storage.onChanged.addListener(runSync); backup(); } @@ -697,6 +706,7 @@ async function restoreFirstRun(inSync) { * and the color and icon are overwritten from sync, if different. */ async function reconcileIdentitiesByName(inSync){ + console.log("reconcileIdentitiesByName"); const localIdentities = await browser.contextualIdentities.query({}); const syncIdentities = inSync.identities; const cookieStoreIDmap = inSync.cookieStoreIDmap; @@ -705,18 +715,21 @@ async function reconcileIdentitiesByName(inSync){ const compareNames = function (localIdentity) { return (localIdentity.name === syncIdentity.name); }; const match = localIdentities.find(compareNames); if (!match) { + console.log("create new ident: ", syncIdentity.name) newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); + await identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); continue; } if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { - console.log("everything is the same:", syncIdentity, match); identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); continue; } - console.log("somethings are different:", syncIdentity, match); - browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); + //for testing purposes: + if (match.color !== syncIdentity.color) {console.log(match.name, "Change color: ", syncIdentity.color)} + if (match.icon !== syncIdentity.icon) {console.log(match.name, "Change icon: ", syncIdentity.icon)} + // end testing + await browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + await identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); } } @@ -726,27 +739,22 @@ async function reconcileIdentitiesByName(inSync){ * (not yet implemented). If it does not exist, it is created. */ async function reconcileSiteAssignments(inSync, firstSync = false) { + console.log("reconcileSiteAssignments"); const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); - console.log(assignedSitesLocal); const syncAssignedSites = inSync.assignedSites; - console.log(syncAssignedSites); for(const key of Object.keys(syncAssignedSites)) { if (assignedSitesLocal.hasOwnProperty(key)) { const syncCookieStoreId = "firefox-container-" + syncAssignedSites[key].userContextId; const syncUUID = await inSync.cookieStoreIDmap[syncCookieStoreId]; const assignedSite = assignedSitesLocal[key]; const localCookieStoreId = "firefox-container-" + assignedSite.userContextId; - if (syncUUID === identityState.storageArea.get(localCookieStoreId).macAddonUUID) { + const localIdentityUUID = await identityState.storageArea.get(localCookieStoreId).macAddonUUID + if (syncUUID === localIdentityUUID) { continue; } if (!firstSync) { // overwrite with Sync data - setAsignmentWithUUID(syncUUID, assignedSite); - // assignedSite.userContextId = identityState.lookupCookieStoreId(syncUUID).replace(/^firefox-container-/, ""); - // assignManager.storageArea.set( - // key.replace(/^siteContainerMap@@_/, "https://"), - // assignedSite - // ); + await setAsignmentWithUUID(syncUUID, assignedSite, key); continue; } // TODO: on First Sync only, if uuids are not the same, @@ -754,39 +762,29 @@ async function reconcileSiteAssignments(inSync, firstSync = false) { continue; } const assignedSite = syncAssignedSites[key]; - console.log("assignedSite", assignedSite); + console.log("new assignment ", assignedSite, ": ", assignedSite.userContextId) const newUUID = await inSync.cookieStoreIDmap["firefox-container-" + assignedSite.userContextId]; - console.log("newUUID", newUUID); - // setAsignmentWithUUID(newUUID, assignedSite); - const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); - assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); - assignManager.storageArea.set( - key.replace(/^siteContainerMap@@_/, "https://"), - assignedSite - ); + await setAsignmentWithUUID(newUUID, assignedSite, key); } } -async function setAsignmentWithUUID (newUUID, assignedSite) { - console.log("setAssingment UUID: ", newUUID); +async function setAsignmentWithUUID (newUUID, assignedSite, key) { const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); - console.log(cookieStoreId); - // if (cookieStoreId) { - assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); - console.log(assignedSite.userContextId); - assignManager.storageArea.set( - key.replace(/^siteContainerMap@@_/, "https://"), - assignedSite - ); - // } + assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); + await assignManager.storageArea.set( + key.replace(/^siteContainerMap@@_/, "https://"), + assignedSite + ); } async function runSync() { + browser.storage.onChanged.removeListener(syncOnChangedListener); + removeContextualIdentityListeners(backup); console.log("runSync"); const inSync = await browser.storage.sync.get(); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); - backup(); + await backup(); return; } console.log("storage found, attempting to restore ..."); @@ -808,20 +806,20 @@ function removeContextualIdentityListeners(listener) { async function runFirstSync() { console.log("runFirstSync"); const localIdentities = await browser.contextualIdentities.query({}); - addUUIDsToContainers(localIdentities); + await addUUIDsToContainers(localIdentities); const inSync = await browser.storage.sync.get(); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); backup(); } else { console.log("storage found, attempting to restore ..."); - restoreFirstRun(inSync); + await restoreFirstRun(inSync); } - assignManager.storageArea.setSynced(); + await assignManager.storageArea.setSynced(); } async function addUUIDsToContainers(localIdentities) { for (const identity of localIdentities) { - identityState.addUUID(identity.cookieStoreId); + await identityState.addUUID(identity.cookieStoreId); } } diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index bad1213..bb48b03 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -70,10 +70,11 @@ const identityState = { async updateUUID(cookieStoreId, uuid) { const containerState = await this.storageArea.get(cookieStoreId); containerState.macAddonUUID = uuid; - return this.storageArea.set(cookieStoreId, containerState); + await this.storageArea.set(cookieStoreId, containerState); + return; }, async addUUID(cookieStoreId) { - return this.updateUUID(cookieStoreId, uuidv4()); + return await this.updateUUID(cookieStoreId, uuidv4()); }, async lookupMACaddonUUID(cookieStoreId) { From e65c88cde2bcfd9034b11c9a4dddcbbcdcc787fe Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 18 Dec 2019 22:26:55 -0600 Subject: [PATCH 11/60] updated with comments fixes from review --- src/js/background/assignManager.js | 40 +++++++++++++++--------------- src/js/background/identityState.js | 24 +++++++++--------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 7141a93..4a113d6 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -92,17 +92,17 @@ const assignManager = { async getAssignedSites(userContextId = null) { const sites = {}; const siteConfigs = await this.area.get(); - for(const key of Object.keys(siteConfigs)) { - if (key.includes("siteContainerMap@@_")) { + for(const urlKey of Object.keys(siteConfigs)) { + if (urlKey.includes("siteContainerMap@@_")) { // For some reason this is stored as string... lets check them both as that - if (!!userContextId && String(siteConfigs[key].userContextId) !== String(userContextId)) { + if (!!userContextId && String(siteConfigs[urlKey].userContextId) !== String(userContextId)) { continue; } - const site = siteConfigs[key]; + const site = siteConfigs[urlKey]; // In hindsight we should have stored this // TODO file a follow up to clean the storage onLoad - site.hostname = key.replace(/^siteContainerMap@@_/, ""); - sites[key] = site; + site.hostname = urlKey.replace(/^siteContainerMap@@_/, ""); + sites[urlKey] = site; } }; return sites; @@ -564,10 +564,10 @@ const assignManager = { console.log("inLocal: ", localInfo); const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ - runSync(); + await runSync(); return; } - runFirstSync(); + await runFirstSync(); }, }; @@ -741,12 +741,12 @@ async function reconcileIdentitiesByName(inSync){ async function reconcileSiteAssignments(inSync, firstSync = false) { console.log("reconcileSiteAssignments"); const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); - const syncAssignedSites = inSync.assignedSites; - for(const key of Object.keys(syncAssignedSites)) { - if (assignedSitesLocal.hasOwnProperty(key)) { - const syncCookieStoreId = "firefox-container-" + syncAssignedSites[key].userContextId; + const assignedSitesFromSync = inSync.assignedSites; + for(const urlKey of Object.keys(assignedSitesFromSync)) { + if (assignedSitesLocal.hasOwnProperty(urlKey)) { + const syncCookieStoreId = "firefox-container-" + assignedSitesFromSync[urlKey].userContextId; const syncUUID = await inSync.cookieStoreIDmap[syncCookieStoreId]; - const assignedSite = assignedSitesLocal[key]; + const assignedSite = assignedSitesLocal[urlKey]; const localCookieStoreId = "firefox-container-" + assignedSite.userContextId; const localIdentityUUID = await identityState.storageArea.get(localCookieStoreId).macAddonUUID if (syncUUID === localIdentityUUID) { @@ -754,25 +754,25 @@ async function reconcileSiteAssignments(inSync, firstSync = false) { } if (!firstSync) { // overwrite with Sync data - await setAsignmentWithUUID(syncUUID, assignedSite, key); + await setAsignmentWithUUID(syncUUID, assignedSite, urlKey); continue; } // TODO: on First Sync only, if uuids are not the same, // ask user where to assign the site. continue; } - const assignedSite = syncAssignedSites[key]; + const assignedSite = assignedSitesFromSync[urlKey]; console.log("new assignment ", assignedSite, ": ", assignedSite.userContextId) const newUUID = await inSync.cookieStoreIDmap["firefox-container-" + assignedSite.userContextId]; - await setAsignmentWithUUID(newUUID, assignedSite, key); + await setAsignmentWithUUID(newUUID, assignedSite, urlKey); } } -async function setAsignmentWithUUID (newUUID, assignedSite, key) { +async function setAsignmentWithUUID (newUUID, assignedSite, urlKey) { const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); await assignManager.storageArea.set( - key.replace(/^siteContainerMap@@_/, "https://"), + urlKey.replace(/^siteContainerMap@@_/, "https://"), assignedSite ); } @@ -788,7 +788,7 @@ async function runSync() { return; } console.log("storage found, attempting to restore ..."); - restore(inSync); + await restore(inSync); } function addContextualIdentityListeners(listener) { @@ -810,7 +810,7 @@ async function runFirstSync() { const inSync = await browser.storage.sync.get(); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); - backup(); + await backup(); } else { console.log("storage found, attempting to restore ..."); await restoreFirstRun(inSync); diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index bb48b03..7ccae7c 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -40,10 +40,10 @@ const identityState = { async getCookieStoreIDuuidMap() { const containers = {}; const containerInfo = await identityState.storageArea.area.get(); - for(const key of Object.keys(containerInfo)) { - if (key.includes("identitiesState@@_")) { - const container = containerInfo[key]; - const cookieStoreId = key.replace(/^identitiesState@@_/, ""); + for(const configKey of Object.keys(containerInfo)) { + if (configKey.includes("identitiesState@@_")) { + const container = containerInfo[configKey]; + const cookieStoreId = configKey.replace(/^identitiesState@@_/, ""); containers[cookieStoreId] = container.macAddonUUID; } } @@ -79,10 +79,10 @@ const identityState = { async lookupMACaddonUUID(cookieStoreId) { const macConfigs = await this.storageArea.area.get(); - for(const key of Object.keys(macConfigs)) { - if (key.includes("identitiesState@@_")) { - if(macConfigs[key] === cookieStoreId) { - return macConfigs[key].macAddonUUID; + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("identitiesState@@_")) { + if(macConfigs[configKey] === cookieStoreId) { + return macConfigs[configKey].macAddonUUID; } } } @@ -91,10 +91,10 @@ const identityState = { async lookupCookieStoreId(macAddonUUID) { const macConfigs = await this.storageArea.area.get(); - for(const key of Object.keys(macConfigs)) { - if (key.includes("identitiesState@@_")) { - if(macConfigs[key].macAddonUUID === macAddonUUID) { - return String(key).replace(/^identitiesState@@_/, ""); + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("identitiesState@@_")) { + if(macConfigs[configKey].macAddonUUID === macAddonUUID) { + return String(configKey).replace(/^identitiesState@@_/, ""); } } } From f4024bba66484800c128f2e63e01482e272f426b Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 18 Dec 2019 22:45:30 -0600 Subject: [PATCH 12/60] re-enabled listeners --- src/js/background/assignManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 4a113d6..479c4b5 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -587,8 +587,8 @@ async function backup() { console.log("in sync: ", storage); const localStorage = await browser.storage.local.get(); console.log("inLocal:", localStorage); - //browser.storage.onChanged.addListener(syncOnChangedListener); - //addContextualIdentityListeners(backup); + await browser.storage.onChanged.addListener(syncOnChangedListener); + await addContextualIdentityListeners(backup); } browser.resetMAC1 = async function () { From a7f6659204627d47513304a67cf864093b84c6cd Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 18 Dec 2019 23:08:01 -0600 Subject: [PATCH 13/60] added check for uuid in updateUUID --- src/js/background/assignManager.js | 3 +-- src/js/background/identityState.js | 13 +++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 479c4b5..58965c8 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -712,8 +712,7 @@ async function reconcileIdentitiesByName(inSync){ const cookieStoreIDmap = inSync.cookieStoreIDmap; for (const syncIdentity of inSync.identities) { syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; - const compareNames = function (localIdentity) { return (localIdentity.name === syncIdentity.name); }; - const match = localIdentities.find(compareNames); + const match = localIdentities.find(localIdentity => localIdentity.name === syncIdentity.name); if (!match) { console.log("create new ident: ", syncIdentity.name) newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 7ccae7c..8db6cf1 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -67,12 +67,17 @@ const identityState = { return this.storageArea.set(cookieStoreId, containerState); }, + async updateUUID(cookieStoreId, uuid) { - const containerState = await this.storageArea.get(cookieStoreId); - containerState.macAddonUUID = uuid; - await this.storageArea.set(cookieStoreId, containerState); - return; + if (cookieStoreId && uuid) { + const containerState = await this.storageArea.get(cookieStoreId); + containerState.macAddonUUID = uuid; + await this.storageArea.set(cookieStoreId, containerState); + return; + } + throw new Error ("cookieStoreId or uuid missing"); }, + async addUUID(cookieStoreId) { return await this.updateUUID(cookieStoreId, uuidv4()); }, From 136aa3ce0e5a8214d85d1e1aa593ebedf3341db0 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 20 Dec 2019 20:03:54 -0600 Subject: [PATCH 14/60] wip: cleaning up storage before sync --- src/js/background/assignManager.js | 134 ++++++++++++++++++++++++----- src/js/background/identityState.js | 25 ++++-- 2 files changed, 133 insertions(+), 26 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 58965c8..81a3ff5 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -573,22 +573,57 @@ const assignManager = { assignManager.init(); -async function backup() { +async function backup(options) { console.log("backup"); + // remove listeners to avoid an infinite loop! browser.storage.onChanged.removeListener(syncOnChangedListener); - removeContextualIdentityListeners(backup); - const identities = await browser.contextualIdentities.query({}); - await browser.storage.sync.set({ identities: identities }); - const cookieStoreIDmap = await identityState.getCookieStoreIDuuidMap(); - await browser.storage.sync.set({ cookieStoreIDmap: cookieStoreIDmap }); - const assignedSites = await assignManager.storageArea.getAssignedSites(); - await browser.storage.sync.set({ assignedSites: assignedSites}); + removeContextualIdentityListeners(syncCIListenerList); + + await updateSyncIdentities(); + await updateCookieStoreIdMap(); + await updateSyncSiteAssignments(); + if (options) { + if (options.uuid) { updateDeletedIdentityList(options.uuid);} + if (options.siteURL) { updateDeletedSiteAssignmentList(options.siteURL);} + } + // for testing const storage = await browser.storage.sync.get(); console.log("in sync: ", storage); const localStorage = await browser.storage.local.get(); console.log("inLocal:", localStorage); + // end testing + await browser.storage.onChanged.addListener(syncOnChangedListener); - await addContextualIdentityListeners(backup); + await addContextualIdentityListeners(syncCIListenerList); +} + +async function updateSyncIdentities() { + const identities = await browser.contextualIdentities.query({}); + await browser.storage.sync.set({ identities }); +} + +async function updateCookieStoreIdMap() { + const cookieStoreIDmap = await identityState.getCookieStoreIDuuidMap(); + await browser.storage.sync.set({ cookieStoreIDmap }); +} + +async function updateSyncSiteAssignments() { + const assignedSites = await assignManager.storageArea.getAssignedSites(); + await browser.storage.sync.set({ assignedSites }); +} + +async function updateDeletedIdentityList(deletedIdentityUUID) { + let deletedIdentityList = await browser.storage.sync.get("deletedIdentityList"); + if (Object.entries(deletedIdentityList).length === 0) deletedIdentityList = []; + deletedIdentityList.push(deletedIdentityUUID); + await browser.storage.sync.set({ deletedIdentityList }); +} + +async function updateDeletedSiteAssignmentList(deletedSiteURL) { + let deletedSiteAssignmentList = await browser.storage.sync.get("deletedSiteAssignmentList"); + if (Object.entries(deletedSiteAssignmentList).length === 0) deletedSiteAssignmentList = []; + deletedSiteAssignmentList.push(deletedSiteURL); + await browser.storage.sync.set({ deletedSiteAssignmentList }); } browser.resetMAC1 = async function () { @@ -614,7 +649,7 @@ browser.resetMAC2 = async function () { browser.storage.sync.set(syncData); // FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(backup); + removeContextualIdentityListeners(syncCIListenerList); browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); browser.storage.local.clear(); @@ -633,7 +668,26 @@ browser.resetMAC3 = async function () { browser.storage.sync.set(syncData); // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(backup); + removeContextualIdentityListeners(syncCIListenerList); + browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); + //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); + browser.storage.local.clear(); + const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + +}; + +browser.resetMAC4 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.storage.onChanged.removeListener(syncOnChangedListener); + + // sync state after FF2 synced + await browser.storage.sync.clear(); + const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; + browser.storage.sync.set(syncData); + + // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) + removeContextualIdentityListeners(syncCIListenerList); browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); browser.storage.local.clear(); @@ -650,7 +704,10 @@ async function restore(inSync) { } function syncOnChangedListener (changes, areaName) { + console.log("Listener Placed") + console.trace(); if (areaName == "sync") runSync(); + } /* @@ -661,6 +718,14 @@ async function reconcileIdentitiesByUUID(inSync) { console.log("reconcileIdentitiesByUUID"); const syncIdentities = inSync.identities; const syncCookieStoreIDmap = inSync.cookieStoreIDmap; + if (inSync.deletedIdentityList) { + for (const deletedUUID of inSync.deletedIdentityList) { + const deletedCookieStoreId = await identityState.lookupCookieStoreId(deletedUUID); + if (deletedCookieStoreId){ + await browser.contextualIdentities.remove(deletedCookieStoreId); + } + } + } for (const syncCookieStoreID of Object.keys(syncCookieStoreIDmap)) { const syncUUID = syncCookieStoreIDmap[syncCookieStoreID]; @@ -684,6 +749,7 @@ async function reconcileIdentitiesByUUID(inSync) { console.log(newIdentity.cookieStoreId) await identityState.updateUUID(newIdentity.cookieStoreId, syncUUID); } + return; } function findIdentityFromSync(cookieStoreId, identitiesList){ @@ -778,9 +844,11 @@ async function setAsignmentWithUUID (newUUID, assignedSite, urlKey) { async function runSync() { browser.storage.onChanged.removeListener(syncOnChangedListener); - removeContextualIdentityListeners(backup); + removeContextualIdentityListeners(syncCIListenerList); console.log("runSync"); + identityState.storageArea.cleanup(); const inSync = await browser.storage.sync.get(); + cleanupSync(inSync); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); await backup(); @@ -790,23 +858,36 @@ async function runSync() { await restore(inSync); } -function addContextualIdentityListeners(listener) { - browser.contextualIdentities.onCreated.addListener(listener); - browser.contextualIdentities.onRemoved.addListener(listener); - browser.contextualIdentities.onUpdated.addListener(listener); +const syncCIListenerList = [backup, addToDeletedList, backup]; + +function addContextualIdentityListeners(listenerList) { + browser.contextualIdentities.onCreated.addListener(listenerList[0]); + browser.contextualIdentities.onRemoved.addListener(listenerList[1]); + browser.contextualIdentities.onUpdated.addListener(listenerList[2]); } -function removeContextualIdentityListeners(listener) { - browser.contextualIdentities.onCreated.removeListener(listener); - browser.contextualIdentities.onRemoved.removeListener(listener); - browser.contextualIdentities.onUpdated.removeListener(listener); +function removeContextualIdentityListeners(listenerList) { + browser.contextualIdentities.onCreated.removeListener(listenerList[0]); + browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); + browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); +} + +async function addToDeletedList(changeInfo) { + const identity = changeInfo.contextualIdentity; + console.log("addToDeletedList", identity.cookieStoreId) + const deletedUUID = await identityState.lookupMACaddonUUID(identity.cookieStoreId); + await identityState.storageArea.remove(identity.cookieStoreId) + console.log(deletedUUID) + backup({uuid: deletedUUID}); } async function runFirstSync() { console.log("runFirstSync"); + identityState.storageArea.cleanup(); const localIdentities = await browser.contextualIdentities.query({}); await addUUIDsToContainers(localIdentities); const inSync = await browser.storage.sync.get(); + cleanupSync(inSync); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); await backup(); @@ -822,3 +903,16 @@ async function addUUIDsToContainers(localIdentities) { await identityState.addUUID(identity.cookieStoreId); } } + +async function cleanupSync(inSync) { + const identitiesList = inSync.identities; + const cookieStoreIDmap = inSync.cookieStoreIDmap; + for(const cookieStoreId of Object.keys(cookieStoreIDmap)) { + const match = identitiesList.find(syncIdentity => syncIdentity.cookieStoreId === cookieStoreId); + if (!match) { + delete inSync.cookieStoreIDmap[cookieStoreId]; + browser.storage.sync.set({cookieStoreIDmap: inSync.cookieStoreIDmap}); + console.log("removed ", cookieStoreId, " from sync list"); + } + } +} \ No newline at end of file diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 8db6cf1..ff8bfd2 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -27,9 +27,23 @@ const identityState = { }); }, - remove(cookieStoreId) { + async remove(cookieStoreId) { const storeKey = this.getContainerStoreKey(cookieStoreId); - return this.area.remove([storeKey]); + return await this.area.remove([storeKey]); + }, + async cleanup() { + const identitiesList = await browser.contextualIdentities.query({}); + const macConfigs = await this.area.get(); + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("identitiesState@@_")) { + const cookieStoreId = String(configKey).replace(/^identitiesState@@_/, ""); + const match = identitiesList.find(localIdentity => localIdentity.cookieStoreId === cookieStoreId); + if (!match) { + console.log("removed ", cookieStoreId, " from storage list"); + this.remove(cookieStoreId); + } + } + } } }, @@ -83,12 +97,11 @@ const identityState = { }, async lookupMACaddonUUID(cookieStoreId) { + console.log(cookieStoreId) const macConfigs = await this.storageArea.area.get(); for(const configKey of Object.keys(macConfigs)) { - if (configKey.includes("identitiesState@@_")) { - if(macConfigs[configKey] === cookieStoreId) { + if (configKey == "identitiesState@@_" + cookieStoreId) { return macConfigs[configKey].macAddonUUID; - } } } return false; @@ -119,4 +132,4 @@ function uuidv4() { return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); -} \ No newline at end of file +} From 063b7509bd9bd85b19e939d4c73db9413c18b44e Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 20 Dec 2019 20:41:48 -0600 Subject: [PATCH 15/60] removed awaits that were causing issues with error handling --- src/js/background/assignManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 81a3ff5..077ca7d 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -564,10 +564,10 @@ const assignManager = { console.log("inLocal: ", localInfo); const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ - await runSync(); + runSync(); return; } - await runFirstSync(); + runFirstSync(); }, }; From 0e45f06338350b793ccf70f065a88c5aa170849a Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 20 Dec 2019 22:01:59 -0600 Subject: [PATCH 16/60] deletes containers, and adds and deletes site assignments. --- src/js/background/assignManager.js | 41 ++++++++++++++---------------- src/js/background/identityState.js | 2 +- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 077ca7d..cda1455 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -65,23 +65,27 @@ const assignManager = { }); }, - set(pageUrl, data, exemptedTabIds) { + async set(pageUrl, data, exemptedTabIds) { const siteStoreKey = this.getSiteStoreKey(pageUrl); if (exemptedTabIds) { exemptedTabIds.forEach((tabId) => { this.setExempted(pageUrl, tabId); }); } - return this.area.set({ + await this.area.set({ [siteStoreKey]: data }); + await backup(); + return; }, - remove(pageUrl) { + async remove(pageUrl) { const siteStoreKey = this.getSiteStoreKey(pageUrl); // When we remove an assignment we should clear all the exemptions this.removeExempted(pageUrl); - return this.area.remove([siteStoreKey]); + await this.area.remove([siteStoreKey]); + await backup(); + return; }, async deleteContainer(userContextId) { @@ -582,10 +586,7 @@ async function backup(options) { await updateSyncIdentities(); await updateCookieStoreIdMap(); await updateSyncSiteAssignments(); - if (options) { - if (options.uuid) { updateDeletedIdentityList(options.uuid);} - if (options.siteURL) { updateDeletedSiteAssignmentList(options.siteURL);} - } + if (options && options.uuid) await updateDeletedIdentityList(options.uuid); // for testing const storage = await browser.storage.sync.get(); console.log("in sync: ", storage); @@ -613,19 +614,12 @@ async function updateSyncSiteAssignments() { } async function updateDeletedIdentityList(deletedIdentityUUID) { - let deletedIdentityList = await browser.storage.sync.get("deletedIdentityList"); - if (Object.entries(deletedIdentityList).length === 0) deletedIdentityList = []; + let { deletedIdentityList } = await browser.storage.sync.get("deletedIdentityList"); + if (!deletedIdentityList) deletedIdentityList = []; deletedIdentityList.push(deletedIdentityUUID); await browser.storage.sync.set({ deletedIdentityList }); } -async function updateDeletedSiteAssignmentList(deletedSiteURL) { - let deletedSiteAssignmentList = await browser.storage.sync.get("deletedSiteAssignmentList"); - if (Object.entries(deletedSiteAssignmentList).length === 0) deletedSiteAssignmentList = []; - deletedSiteAssignmentList.push(deletedSiteURL); - await browser.storage.sync.set({ deletedSiteAssignmentList }); -} - browser.resetMAC1 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created browser.storage.onChanged.removeListener(syncOnChangedListener); @@ -846,9 +840,9 @@ async function runSync() { browser.storage.onChanged.removeListener(syncOnChangedListener); removeContextualIdentityListeners(syncCIListenerList); console.log("runSync"); - identityState.storageArea.cleanup(); + await identityState.storageArea.cleanup(); const inSync = await browser.storage.sync.get(); - cleanupSync(inSync); + await cleanupSync(inSync); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); await backup(); @@ -883,15 +877,15 @@ async function addToDeletedList(changeInfo) { async function runFirstSync() { console.log("runFirstSync"); - identityState.storageArea.cleanup(); + await identityState.storageArea.cleanup(); const localIdentities = await browser.contextualIdentities.query({}); await addUUIDsToContainers(localIdentities); const inSync = await browser.storage.sync.get(); - cleanupSync(inSync); if (Object.entries(inSync).length === 0){ console.log("no sync storage, backing up..."); await backup(); } else { + await cleanupSync(inSync); console.log("storage found, attempting to restore ..."); await restoreFirstRun(inSync); } @@ -905,13 +899,16 @@ async function addUUIDsToContainers(localIdentities) { } async function cleanupSync(inSync) { + console.log("cleanupSync") const identitiesList = inSync.identities; + console.log(identitiesList) const cookieStoreIDmap = inSync.cookieStoreIDmap; + console.log(cookieStoreIDmap) for(const cookieStoreId of Object.keys(cookieStoreIDmap)) { const match = identitiesList.find(syncIdentity => syncIdentity.cookieStoreId === cookieStoreId); if (!match) { delete inSync.cookieStoreIDmap[cookieStoreId]; - browser.storage.sync.set({cookieStoreIDmap: inSync.cookieStoreIDmap}); + await browser.storage.sync.set({cookieStoreIDmap: inSync.cookieStoreIDmap}); console.log("removed ", cookieStoreId, " from sync list"); } } diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index ff8bfd2..37f995f 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -38,7 +38,7 @@ const identityState = { if (configKey.includes("identitiesState@@_")) { const cookieStoreId = String(configKey).replace(/^identitiesState@@_/, ""); const match = identitiesList.find(localIdentity => localIdentity.cookieStoreId === cookieStoreId); - if (!match) { + if (!match && cookieStoreId !== "firefox-default") { console.log("removed ", cookieStoreId, " from storage list"); this.remove(cookieStoreId); } From 0bdf8558f691bf3bf74949e8d866188c22c3c5a9 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 31 Dec 2019 13:59:00 -0600 Subject: [PATCH 17/60] Syncs deletion of site assignments and reassignments --- src/js/background/assignManager.js | 54 +++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index cda1455..a007c3d 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -75,7 +75,7 @@ const assignManager = { await this.area.set({ [siteStoreKey]: data }); - await backup(); + await backup({undelete: siteStoreKey}); return; }, @@ -84,7 +84,7 @@ const assignManager = { // When we remove an assignment we should clear all the exemptions this.removeExempted(pageUrl); await this.area.remove([siteStoreKey]); - await backup(); + await backup({siteStoreKey}); return; }, @@ -587,6 +587,8 @@ async function backup(options) { await updateCookieStoreIdMap(); await updateSyncSiteAssignments(); if (options && options.uuid) await updateDeletedIdentityList(options.uuid); + if (options && options.siteStoreKey) await addToDeletedSitesList(options.siteStoreKey); + if (options && options.undelete) await removeFromDeletedSitesList(options.undelete); // for testing const storage = await browser.storage.sync.get(); console.log("in sync: ", storage); @@ -616,10 +618,26 @@ async function updateSyncSiteAssignments() { async function updateDeletedIdentityList(deletedIdentityUUID) { let { deletedIdentityList } = await browser.storage.sync.get("deletedIdentityList"); if (!deletedIdentityList) deletedIdentityList = []; + if (deletedIdentityList.find(element => element === deletedIdentityUUID)) return; deletedIdentityList.push(deletedIdentityUUID); await browser.storage.sync.set({ deletedIdentityList }); } +async function addToDeletedSitesList(siteStoreKey) { + let { deletedSiteList } = await browser.storage.sync.get("deletedSiteList"); + if (!deletedSiteList) deletedSiteList = []; + if (deletedSiteList.find(element => element === siteStoreKey)) return; + deletedSiteList.push(siteStoreKey); + await browser.storage.sync.set({ deletedSiteList }); +} + +async function removeFromDeletedSitesList(siteStoreKey) { + let { deletedSiteList } = await browser.storage.sync.get("deletedSiteList"); + if (!deletedSiteList) return; + deletedSiteList = deletedSiteList.filter(element => element !== siteStoreKey); + await browser.storage.sync.set({ deletedSiteList }); +} + browser.resetMAC1 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created browser.storage.onChanged.removeListener(syncOnChangedListener); @@ -801,23 +819,25 @@ async function reconcileSiteAssignments(inSync, firstSync = false) { console.log("reconcileSiteAssignments"); const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); const assignedSitesFromSync = inSync.assignedSites; + if (inSync.hasOwnProperty("deletedSiteList")){ + for(const siteStoreKey of inSync.deletedSiteList) { + if (assignedSitesLocal.hasOwnProperty(siteStoreKey)) { + assignManager.storageArea.remove(siteStoreKey.replace(/^siteContainerMap@@_/, "https://")); + } + } + } for(const urlKey of Object.keys(assignedSitesFromSync)) { if (assignedSitesLocal.hasOwnProperty(urlKey)) { const syncCookieStoreId = "firefox-container-" + assignedSitesFromSync[urlKey].userContextId; const syncUUID = await inSync.cookieStoreIDmap[syncCookieStoreId]; const assignedSite = assignedSitesLocal[urlKey]; const localCookieStoreId = "firefox-container-" + assignedSite.userContextId; - const localIdentityUUID = await identityState.storageArea.get(localCookieStoreId).macAddonUUID + const localIdentityUUID = await identityState.storageArea.get(localCookieStoreId).macAddonUUID; if (syncUUID === localIdentityUUID) { continue; } - if (!firstSync) { - // overwrite with Sync data - await setAsignmentWithUUID(syncUUID, assignedSite, urlKey); - continue; - } - // TODO: on First Sync only, if uuids are not the same, - // ask user where to assign the site. + // overwrite with Sync data. Sync is the source of truth + await setAsignmentWithUUID(syncUUID, assignedSite, urlKey); continue; } const assignedSite = assignedSitesFromSync[urlKey]; @@ -829,11 +849,15 @@ async function reconcileSiteAssignments(inSync, firstSync = false) { async function setAsignmentWithUUID (newUUID, assignedSite, urlKey) { const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); - assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); - await assignManager.storageArea.set( - urlKey.replace(/^siteContainerMap@@_/, "https://"), - assignedSite - ); + if (cookieStoreId) { + assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); + await assignManager.storageArea.set( + urlKey.replace(/^siteContainerMap@@_/, "https://"), + assignedSite + ); + return; + } + throw new Error ("No cookieStoreId found for: ", newUUID, assignedSite, urlKey); } async function runSync() { From 19dce3ba452279fc9b2b854d09280ad45e552d1d Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 31 Dec 2019 17:20:00 -0600 Subject: [PATCH 18/60] refactor and fixed site assignment reconcilding --- src/js/background/assignManager.js | 382 +---------------------- src/js/background/index.html | 1 + src/js/background/sync.js | 467 +++++++++++++++++++++++++++++ 3 files changed, 470 insertions(+), 380 deletions(-) create mode 100644 src/js/background/sync.js diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index a007c3d..5ab7bb0 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -75,7 +75,7 @@ const assignManager = { await this.area.set({ [siteStoreKey]: data }); - await backup({undelete: siteStoreKey}); + await sync.storageArea.backup({undelete: siteStoreKey}); return; }, @@ -84,7 +84,7 @@ const assignManager = { // When we remove an assignment we should clear all the exemptions this.removeExempted(pageUrl); await this.area.remove([siteStoreKey]); - await backup({siteStoreKey}); + await sync.storageArea.backup({siteStoreKey}); return; }, @@ -260,10 +260,6 @@ const assignManager = { },{urls: [""], types: ["main_frame"]}); this.resetBookmarksMenuItem(); - - // Run when installed and on startup - browser.runtime.onInstalled.addListener(this.initSync); - browser.runtime.onStartup.addListener(this.initSync); }, async resetBookmarksMenuItem() { @@ -560,380 +556,6 @@ const assignManager = { browser.contextMenus.remove(identity.cookieStoreId); } }, - - async initSync() { - const syncInfo = await browser.storage.sync.get(); - const localInfo = await browser.storage.local.get(); - console.log("inSync: ", syncInfo); - console.log("inLocal: ", localInfo); - const beenSynced = await assignManager.storageArea.getSynced(); - if (beenSynced){ - runSync(); - return; - } - runFirstSync(); - }, }; assignManager.init(); - -async function backup(options) { - console.log("backup"); - // remove listeners to avoid an infinite loop! - browser.storage.onChanged.removeListener(syncOnChangedListener); - removeContextualIdentityListeners(syncCIListenerList); - - await updateSyncIdentities(); - await updateCookieStoreIdMap(); - await updateSyncSiteAssignments(); - if (options && options.uuid) await updateDeletedIdentityList(options.uuid); - if (options && options.siteStoreKey) await addToDeletedSitesList(options.siteStoreKey); - if (options && options.undelete) await removeFromDeletedSitesList(options.undelete); - // for testing - const storage = await browser.storage.sync.get(); - console.log("in sync: ", storage); - const localStorage = await browser.storage.local.get(); - console.log("inLocal:", localStorage); - // end testing - - await browser.storage.onChanged.addListener(syncOnChangedListener); - await addContextualIdentityListeners(syncCIListenerList); -} - -async function updateSyncIdentities() { - const identities = await browser.contextualIdentities.query({}); - await browser.storage.sync.set({ identities }); -} - -async function updateCookieStoreIdMap() { - const cookieStoreIDmap = await identityState.getCookieStoreIDuuidMap(); - await browser.storage.sync.set({ cookieStoreIDmap }); -} - -async function updateSyncSiteAssignments() { - const assignedSites = await assignManager.storageArea.getAssignedSites(); - await browser.storage.sync.set({ assignedSites }); -} - -async function updateDeletedIdentityList(deletedIdentityUUID) { - let { deletedIdentityList } = await browser.storage.sync.get("deletedIdentityList"); - if (!deletedIdentityList) deletedIdentityList = []; - if (deletedIdentityList.find(element => element === deletedIdentityUUID)) return; - deletedIdentityList.push(deletedIdentityUUID); - await browser.storage.sync.set({ deletedIdentityList }); -} - -async function addToDeletedSitesList(siteStoreKey) { - let { deletedSiteList } = await browser.storage.sync.get("deletedSiteList"); - if (!deletedSiteList) deletedSiteList = []; - if (deletedSiteList.find(element => element === siteStoreKey)) return; - deletedSiteList.push(siteStoreKey); - await browser.storage.sync.set({ deletedSiteList }); -} - -async function removeFromDeletedSitesList(siteStoreKey) { - let { deletedSiteList } = await browser.storage.sync.get("deletedSiteList"); - if (!deletedSiteList) return; - deletedSiteList = deletedSiteList.filter(element => element !== siteStoreKey); - await browser.storage.sync.set({ deletedSiteList }); -} - -browser.resetMAC1 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); - - // sync state on install: no sync data - await browser.storage.sync.clear(); - - // FF1: no sync, Only default containers and 1 extra - browser.storage.local.clear(); - const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; - browser.storage.local.set(localData); -}; - -browser.resetMAC2 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); - - // sync state after FF1 (default + 1) - await browser.storage.sync.clear(); - const syncData = {"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; - browser.storage.sync.set(syncData); - - // FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(syncCIListenerList); - browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); - browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); - browser.storage.local.clear(); - const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - -}; - -browser.resetMAC3 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); - - // sync state after FF2 synced - await browser.storage.sync.clear(); - const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; - browser.storage.sync.set(syncData); - - // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(syncCIListenerList); - browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); - //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); - browser.storage.local.clear(); - const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - -}; - -browser.resetMAC4 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); - - // sync state after FF2 synced - await browser.storage.sync.clear(); - const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; - browser.storage.sync.set(syncData); - - // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(syncCIListenerList); - browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); - //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); - browser.storage.local.clear(); - const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - -}; - -async function restore(inSync) { - console.log("restore"); - await reconcileIdentitiesByUUID(inSync); - await reconcileSiteAssignments(inSync); - await backup(); -} - -function syncOnChangedListener (changes, areaName) { - console.log("Listener Placed") - console.trace(); - if (areaName == "sync") runSync(); - -} - -/* - * Matches uuids in sync to uuids locally, and updates containers accordingly. - * If there is no match, it creates the new container. - */ -async function reconcileIdentitiesByUUID(inSync) { - console.log("reconcileIdentitiesByUUID"); - const syncIdentities = inSync.identities; - const syncCookieStoreIDmap = inSync.cookieStoreIDmap; - if (inSync.deletedIdentityList) { - for (const deletedUUID of inSync.deletedIdentityList) { - const deletedCookieStoreId = await identityState.lookupCookieStoreId(deletedUUID); - if (deletedCookieStoreId){ - await browser.contextualIdentities.remove(deletedCookieStoreId); - } - } - } - - for (const syncCookieStoreID of Object.keys(syncCookieStoreIDmap)) { - const syncUUID = syncCookieStoreIDmap[syncCookieStoreID]; - //find localCookiesStoreID by looking up the syncUUID - const localCookieStoreID = await identityState.lookupCookieStoreId(syncUUID); - // get correct indentity info from sync - identityInfo = findIdentityFromSync(syncCookieStoreID, syncIdentities); - if (localCookieStoreID) { - //for testing purposes: - const getIdent = await browser.contextualIdentities.get(localCookieStoreID); - if (getIdent.name !== identityInfo.name) {console.log(getIdent.name, "Change name: ", identityInfo.name)} - if (getIdent.color !== identityInfo.color) {console.log(getIdent.name, "Change color: ", identityInfo.color)} - if (getIdent.icon !== identityInfo.icon) {console.log(getIdent.name, "Change icon: ", identityInfo.icon)} - // update the local container with the sync data - await browser.contextualIdentities.update(localCookieStoreID, identityInfo); - continue; - } - //not found, create new with same UUID - console.log("new Identity: ", identityInfo.name) - const newIdentity = await browser.contextualIdentities.create(identityInfo); - console.log(newIdentity.cookieStoreId) - await identityState.updateUUID(newIdentity.cookieStoreId, syncUUID); - } - return; -} - -function findIdentityFromSync(cookieStoreId, identitiesList){ - for (const identity of identitiesList) { - const { name, color, icon } = identity; - if (identity.cookieStoreId === cookieStoreId) return { name, color, icon }; - } -} - -async function restoreFirstRun(inSync) { - console.log("restoreFirstRun"); - await reconcileIdentitiesByName(inSync); - const firstRun = true; - await reconcileSiteAssignments(inSync, firstRun); - backup(); -} - -/* - * Checks for the container name. If it exists, they are assumed to be the same container, - * and the color and icon are overwritten from sync, if different. - */ -async function reconcileIdentitiesByName(inSync){ - console.log("reconcileIdentitiesByName"); - const localIdentities = await browser.contextualIdentities.query({}); - const syncIdentities = inSync.identities; - const cookieStoreIDmap = inSync.cookieStoreIDmap; - for (const syncIdentity of inSync.identities) { - syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; - const match = localIdentities.find(localIdentity => localIdentity.name === syncIdentity.name); - if (!match) { - console.log("create new ident: ", syncIdentity.name) - newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - await identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); - continue; - } - if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { - identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); - continue; - } - //for testing purposes: - if (match.color !== syncIdentity.color) {console.log(match.name, "Change color: ", syncIdentity.color)} - if (match.icon !== syncIdentity.icon) {console.log(match.name, "Change icon: ", syncIdentity.icon)} - // end testing - await browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - await identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); - } -} - -/* - * Checks for site previously assigned. If it exists, and has the same container assignment, - * the assignment is kept. If it exists, but has a different assignment, the user is prompted - * (not yet implemented). If it does not exist, it is created. - */ -async function reconcileSiteAssignments(inSync, firstSync = false) { - console.log("reconcileSiteAssignments"); - const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); - const assignedSitesFromSync = inSync.assignedSites; - if (inSync.hasOwnProperty("deletedSiteList")){ - for(const siteStoreKey of inSync.deletedSiteList) { - if (assignedSitesLocal.hasOwnProperty(siteStoreKey)) { - assignManager.storageArea.remove(siteStoreKey.replace(/^siteContainerMap@@_/, "https://")); - } - } - } - for(const urlKey of Object.keys(assignedSitesFromSync)) { - if (assignedSitesLocal.hasOwnProperty(urlKey)) { - const syncCookieStoreId = "firefox-container-" + assignedSitesFromSync[urlKey].userContextId; - const syncUUID = await inSync.cookieStoreIDmap[syncCookieStoreId]; - const assignedSite = assignedSitesLocal[urlKey]; - const localCookieStoreId = "firefox-container-" + assignedSite.userContextId; - const localIdentityUUID = await identityState.storageArea.get(localCookieStoreId).macAddonUUID; - if (syncUUID === localIdentityUUID) { - continue; - } - // overwrite with Sync data. Sync is the source of truth - await setAsignmentWithUUID(syncUUID, assignedSite, urlKey); - continue; - } - const assignedSite = assignedSitesFromSync[urlKey]; - console.log("new assignment ", assignedSite, ": ", assignedSite.userContextId) - const newUUID = await inSync.cookieStoreIDmap["firefox-container-" + assignedSite.userContextId]; - await setAsignmentWithUUID(newUUID, assignedSite, urlKey); - } -} - -async function setAsignmentWithUUID (newUUID, assignedSite, urlKey) { - const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); - if (cookieStoreId) { - assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, ""); - await assignManager.storageArea.set( - urlKey.replace(/^siteContainerMap@@_/, "https://"), - assignedSite - ); - return; - } - throw new Error ("No cookieStoreId found for: ", newUUID, assignedSite, urlKey); -} - -async function runSync() { - browser.storage.onChanged.removeListener(syncOnChangedListener); - removeContextualIdentityListeners(syncCIListenerList); - console.log("runSync"); - await identityState.storageArea.cleanup(); - const inSync = await browser.storage.sync.get(); - await cleanupSync(inSync); - if (Object.entries(inSync).length === 0){ - console.log("no sync storage, backing up..."); - await backup(); - return; - } - console.log("storage found, attempting to restore ..."); - await restore(inSync); -} - -const syncCIListenerList = [backup, addToDeletedList, backup]; - -function addContextualIdentityListeners(listenerList) { - browser.contextualIdentities.onCreated.addListener(listenerList[0]); - browser.contextualIdentities.onRemoved.addListener(listenerList[1]); - browser.contextualIdentities.onUpdated.addListener(listenerList[2]); -} - -function removeContextualIdentityListeners(listenerList) { - browser.contextualIdentities.onCreated.removeListener(listenerList[0]); - browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); - browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); -} - -async function addToDeletedList(changeInfo) { - const identity = changeInfo.contextualIdentity; - console.log("addToDeletedList", identity.cookieStoreId) - const deletedUUID = await identityState.lookupMACaddonUUID(identity.cookieStoreId); - await identityState.storageArea.remove(identity.cookieStoreId) - console.log(deletedUUID) - backup({uuid: deletedUUID}); -} - -async function runFirstSync() { - console.log("runFirstSync"); - await identityState.storageArea.cleanup(); - const localIdentities = await browser.contextualIdentities.query({}); - await addUUIDsToContainers(localIdentities); - const inSync = await browser.storage.sync.get(); - if (Object.entries(inSync).length === 0){ - console.log("no sync storage, backing up..."); - await backup(); - } else { - await cleanupSync(inSync); - console.log("storage found, attempting to restore ..."); - await restoreFirstRun(inSync); - } - await assignManager.storageArea.setSynced(); -} - -async function addUUIDsToContainers(localIdentities) { - for (const identity of localIdentities) { - await identityState.addUUID(identity.cookieStoreId); - } -} - -async function cleanupSync(inSync) { - console.log("cleanupSync") - const identitiesList = inSync.identities; - console.log(identitiesList) - const cookieStoreIDmap = inSync.cookieStoreIDmap; - console.log(cookieStoreIDmap) - for(const cookieStoreId of Object.keys(cookieStoreIDmap)) { - const match = identitiesList.find(syncIdentity => syncIdentity.cookieStoreId === cookieStoreId); - if (!match) { - delete inSync.cookieStoreIDmap[cookieStoreId]; - await browser.storage.sync.set({cookieStoreIDmap: inSync.cookieStoreIDmap}); - console.log("removed ", cookieStoreId, " from sync list"); - } - } -} \ No newline at end of file diff --git a/src/js/background/index.html b/src/js/background/index.html index e167f0b..da380ba 100644 --- a/src/js/background/index.html +++ b/src/js/background/index.html @@ -18,5 +18,6 @@ + diff --git a/src/js/background/sync.js b/src/js/background/sync.js new file mode 100644 index 0000000..bfe6b34 --- /dev/null +++ b/src/js/background/sync.js @@ -0,0 +1,467 @@ +/* jshint esversion: 8*/ +SYNC_DEBUG = true; + +const sync = { + storageArea: { + area: browser.storage.sync, + + async get(){ + return await this.area.get(); + }, + + async set(options) { + return await this.area.set(options); + }, + + async getStoredArray(objectKey) { + const storedArray = await this.getStoredItem(objectKey); + return (storedArray) ? storedArray : []; + }, + + async getStoredObject(objectKey) { + const storedObject = await this.getStoredItem(objectKey); + return (storedObject) ? storedObject : {}; + }, + + async getStoredItem(objectKey) { + const outputObject = await this.area.get(objectKey); + console.log(outputObject) + if (outputObject && outputObject[objectKey]) + return outputObject[objectKey]; + if (SYNC_DEBUG) + console.warn(objectKey, " was requested and is not available."); + return false; + }, + + async hasSyncStorage(){ + const inSync = await this.storageArea.get(); + return !(Object.entries(inSync).length === 0); + }, + + async backup(options) { + console.log("backup"); + // remove listeners to avoid an infinite loop! + browser.storage.onChanged.removeListener(syncOnChangedListener); + removeContextualIdentityListeners(syncCIListenerList); + + await updateSyncIdentities(); + await updateCookieStoreIdMap(); + await updateSyncSiteAssignments(); + if (options && options.uuid) + await updateDeletedIdentityList(options.uuid); + if (options && options.siteStoreKey) + await addToDeletedSitesList(options.siteStoreKey); + if (options && options.undelete) + await removeFromDeletedSitesList(options.undelete); + + if (SYNC_DEBUG) { + const storage = await sync.storageArea.get(); + console.log("in sync: ", storage); + const localStorage = await browser.storage.local.get(); + console.log("inLocal:", localStorage); + } + + await browser.storage.onChanged.addListener(syncOnChangedListener); + await addContextualIdentityListeners(syncCIListenerList); + + async function updateSyncIdentities() { + const identities = await browser.contextualIdentities.query({}); + await sync.storageArea.set({ identities }); + } + + async function updateCookieStoreIdMap() { + const cookieStoreIDmap = + await identityState.getCookieStoreIDuuidMap(); + await sync.storageArea.set({ cookieStoreIDmap }); + } + + async function updateSyncSiteAssignments() { + const assignedSites = await assignManager.storageArea.getAssignedSites(); + await sync.storageArea.set({ assignedSites }); + } + + async function updateDeletedIdentityList(deletedIdentityUUID) { + let { deletedIdentityList } = + await sync.storageArea.get("deletedIdentityList"); + if (!deletedIdentityList) deletedIdentityList = []; + if ( + deletedIdentityList.find(element => element === deletedIdentityUUID) + ) return; + deletedIdentityList.push(deletedIdentityUUID); + await sync.storageArea.set({ deletedIdentityList }); + } + + async function addToDeletedSitesList(siteStoreKey) { + let { deletedSiteList } = await sync.storageArea.get("deletedSiteList"); + if (!deletedSiteList) deletedSiteList = []; + if (deletedSiteList.find(element => element === siteStoreKey)) return; + deletedSiteList.push(siteStoreKey); + await sync.storageArea.set({ deletedSiteList }); + } + + async function removeFromDeletedSitesList(siteStoreKey) { + let { deletedSiteList } = await sync.storageArea.get("deletedSiteList"); + if (!deletedSiteList) return; + deletedSiteList = deletedSiteList.filter(element => element !== siteStoreKey); + await sync.storageArea.set({ deletedSiteList }); + } + }, + + async cleanup() { + console.log("cleanupSync") + const identitiesList = await sync.storageArea.getStoredObject("identities"); + const cookieStoreIDmap = await sync.storageArea.getStoredObject("cookieStoreIDmap"); + for(const cookieStoreId of Object.keys(cookieStoreIDmap)) { + const match = identitiesList + .find(syncIdentity => syncIdentity.cookieStoreId === cookieStoreId); + if (!match) { + delete cookieStoreIDmap[cookieStoreId]; + await sync.storageArea.set({ cookieStoreIDmap }); + console.log("removed ", cookieStoreId, " from sync list"); + } + } + }, + }, + + init() { + browser.runtime.onInstalled.addListener(this.initSync); + browser.runtime.onStartup.addListener(this.initSync); + }, + + async initSync() { + const syncInfo = await sync.storageArea.get(); + const localInfo = await browser.storage.local.get(); + console.log("inSync: ", syncInfo); + console.log("inLocal: ", localInfo); + const beenSynced = await assignManager.storageArea.getSynced(); + if (beenSynced){ + runSync(); + return; + } + runFirstSync(); + }, +}; + +sync.init(); + + +async function runFirstSync() { + console.log("runFirstSync"); + await identityState.storageArea.cleanup(); + const localIdentities = await browser.contextualIdentities.query({}); + await addUUIDsToContainers(localIdentities); + // const inSync = await sync.storageArea.get(); + if (await sync.storageArea.hasSyncStorage()){ + await sync.storageArea.cleanup(); + console.log("storage found, attempting to restore ..."); + await restoreFirstRun(); + }else { + console.log("no sync storage, backing up..."); + await sync.storageArea.backup(); + } + await assignManager.storageArea.setSynced(); +} + +async function addUUIDsToContainers(localIdentities) { + for (const identity of localIdentities) { + await identityState.addUUID(identity.cookieStoreId); + } +} + +async function restoreFirstRun() { + console.log("restoreFirstRun"); + await reconcileIdentitiesByName(); + await reconcileSiteAssignments(); + sync.storageArea.backup(); +} + +/* + * Checks for the container name. If it exists, they are assumed to be the + * same container, and the color and icon are overwritten from sync, if + * different. + */ +async function reconcileIdentitiesByName(){ + console.log("reconcileIdentitiesByName"); + const localIdentities = await browser.contextualIdentities.query({}); + const syncIdentities = sync.storageArea.getStoredObject("identities"); + const cookieStoreIDmap = sync.storageArea.getStoredObject("cookieStoreIDmap"); + for (const syncIdentity of syncIdentities) { + syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; + const match = localIdentities.find(localIdentity => localIdentity.name === syncIdentity.name); + if (!match) { + console.log("create new ident: ", syncIdentity.name) + newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + await identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); + continue; + } + if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { + identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); + continue; + } + if (SYNC_DEBUG) { + if (match.color !== syncIdentity.color) {console.log(match.name, "Change color: ", syncIdentity.color)} + if (match.icon !== syncIdentity.icon) {console.log(match.name, "Change icon: ", syncIdentity.icon)} + } + // end testing + await browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); + await identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); + } +} + +/* + * Checks for site previously assigned. If it exists, and has the same + * container assignment, the assignment is kept. If it exists, but has + * a different assignment, the user is prompted (not yet implemented). + * If it does not exist, it is created. + */ +async function reconcileSiteAssignments(inSync) { + console.log("reconcileSiteAssignments"); + const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); + const assignedSitesFromSync = await sync.storageArea.getStoredObject("assignedSites"); + const deletedSiteList = await sync.storageArea.getStoredArray("deletedSiteList"); + for(const siteStoreKey of deletedSiteList) { + if (assignedSitesLocal.hasOwnProperty(siteStoreKey)) { + assignManager + .storageArea + .remove(siteStoreKey.replace(/^siteContainerMap@@_/, "https://")); + } + } + const cookieStoreIDmap = + await sync.storageArea.getStoredObject("cookieStoreIDmap"); + + for(const urlKey of Object.keys(assignedSitesFromSync)) { + const assignedSite = assignedSitesFromSync[urlKey] + if (assignedSitesLocal.hasOwnProperty(urlKey)) { + const syncUUID = + lookupSyncSiteAssigmentIdentityUUID(assignedSite, cookieStoreIDmap); + + const localIdentityUUID = + lookupLocalSiteAssignmentIdentityUUID(urlKey); + + if (syncUUID === localIdentityUUID) { + continue; + } + // overwrite with Sync data. Sync is the source of truth + await setAssignmentWithUUID(syncUUID, assignedSite, urlKey); + continue; + } + console.log("new assignment ", assignedSite, ": ", assignedSite.userContextId) + const newUUID = await inSync.cookieStoreIDmap[ + "firefox-container-" + assignedSite.userContextId + ]; + await setAssignmentWithUUID(newUUID, assignedSite, urlKey); + } + + async function lookupLocalSiteAssignmentIdentityUUID(urlKey){ + const localAssignedSite = await assignManager.storageArea.getByUrlKey(urlKey); + if (!localAssignedSite.userContextId) + throw new Error (urlKey, "userContextId does not exist"); + const localCookieStoreId = "firefox-container-" + + localAssignedSite.userContextId; + return await identityState.storageArea.get(localCookieStoreId).macAddonUUID; + } + + async function lookupSyncSiteAssigmentIdentityUUID(assignedSite, cookieStoreIDmap){ + if (!assignedSite.userContextId) + throw new Error (urlKey, "userContextId does not exist"); + const syncCookieStoreId = "firefox-container-" + assignedSite.userContextId; + if (!cookieStoreIDmap[syncCookieStoreId]) + throw new Error (syncCookieStoreId, " does not have a uuid"); + return cookieStoreIDmap[syncCookieStoreId]; + } +} + +async function setAssignmentWithUUID (newUUID, assignedSite, urlKey) { + const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); + if (cookieStoreId) { + assignedSite.userContextId = cookieStoreId + .replace(/^firefox-container-/, ""); + await assignManager.storageArea.set( + urlKey.replace(/^siteContainerMap@@_/, "https://"), + assignedSite + ); + return; + } + throw new Error ("No cookieStoreId found for: ", + newUUID, assignedSite, urlKey); +} + +async function runSync() { + browser.storage.onChanged.removeListener(syncOnChangedListener); + removeContextualIdentityListeners(syncCIListenerList); + console.log("runSync"); + await identityState.storageArea.cleanup(); + const inSync = await sync.storageArea.get(); + await sync.storageArea.cleanup(); + if (Object.entries(inSync).length === 0){ + console.log("no sync storage, backing up..."); + await sync.storageArea.backup(); + return; + } + console.log("storage found, attempting to restore ..."); + await restore(inSync); +} + +async function restore(inSync) { + console.log("restore"); + await reconcileIdentitiesByUUID(inSync); + await reconcileSiteAssignments(inSync); + await sync.storageArea.backup(); +} + +function syncOnChangedListener(changes, areaName) { + if (areaName == "sync") runSync(); +} + +/* + * Matches uuids in sync to uuids locally, and updates containers accordingly. + * If there is no match, it creates the new container. + */ +async function reconcileIdentitiesByUUID(inSync) { + console.log("reconcileIdentitiesByUUID"); + const syncIdentities = inSync.identities; + const syncCookieStoreIDmap = inSync.cookieStoreIDmap; + if (inSync.deletedIdentityList) { + for (const deletedUUID of inSync.deletedIdentityList) { + const deletedCookieStoreId = + await identityState.lookupCookieStoreId(deletedUUID); + if (deletedCookieStoreId){ + await browser.contextualIdentities.remove(deletedCookieStoreId); + } + } + } + + for (const syncCookieStoreID of Object.keys(syncCookieStoreIDmap)) { + const syncUUID = syncCookieStoreIDmap[syncCookieStoreID]; + //find localCookiesStoreID by looking up the syncUUID + const localCookieStoreID = await identityState.lookupCookieStoreId(syncUUID); + // get correct indentity info from sync + identityInfo = findIdentityFromSync(syncCookieStoreID, syncIdentities); + if (localCookieStoreID) { + if (SYNC_DEBUG) { + const getIdent = await browser.contextualIdentities.get(localCookieStoreID); + if (getIdent.name !== identityInfo.name) {console.log(getIdent.name, "Change name: ", identityInfo.name)} + if (getIdent.color !== identityInfo.color) {console.log(getIdent.name, "Change color: ", identityInfo.color)} + if (getIdent.icon !== identityInfo.icon) {console.log(getIdent.name, "Change icon: ", identityInfo.icon)} + } + + // update the local container with the sync data + await browser.contextualIdentities.update(localCookieStoreID, identityInfo); + continue; + } + //not found, create new with same UUID + console.log("new Identity: ", identityInfo.name) + const newIdentity = await browser.contextualIdentities.create(identityInfo); + console.log(newIdentity.cookieStoreId) + await identityState.updateUUID(newIdentity.cookieStoreId, syncUUID); + } + return; +} + +function findIdentityFromSync(cookieStoreId, identitiesList){ + for (const identity of identitiesList) { + const { name, color, icon } = identity; + if (identity.cookieStoreId === cookieStoreId) return { name, color, icon }; + } +} + +const syncCIListenerList = [ + sync.storageArea.backup, + addToDeletedList, + sync.storageArea.backup +]; + +function addContextualIdentityListeners(listenerList) { + browser.contextualIdentities.onCreated.addListener(listenerList[0]); + browser.contextualIdentities.onRemoved.addListener(listenerList[1]); + browser.contextualIdentities.onUpdated.addListener(listenerList[2]); +} + +function removeContextualIdentityListeners(listenerList) { + browser.contextualIdentities.onCreated.removeListener(listenerList[0]); + browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); + browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); +} + +async function addToDeletedList(changeInfo) { + const identity = changeInfo.contextualIdentity; + console.log("addToDeletedList", identity.cookieStoreId); + const deletedUUID = + await identityState.lookupMACaddonUUID(identity.cookieStoreId); + await identityState.storageArea.remove(identity.cookieStoreId); + console.log(deletedUUID); + backup({uuid: deletedUUID}); +} + +if(SYNC_DEBUG) { + browser.resetMAC1 = async function () { + // for debugging and testing: remove all containers except the + // default 4 and the first one created + browser.storage.onChanged.removeListener(syncOnChangedListener); + + // sync state on install: no sync data + await browser.storage.sync.clear(); + + // FF1: no sync, Only default containers and 1 extra + browser.storage.local.clear(); + const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; + browser.storage.local.set(localData); + }; + + browser.resetMAC2 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.storage.onChanged.removeListener(syncOnChangedListener); + + // sync state after FF1 (default + 1) + await browser.storage.sync.clear(); + const syncData = {"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; + sync.storageArea.set(syncData); + + // FF2 (intial sync w/ default 4 + 1 with some changes) + removeContextualIdentityListeners(syncCIListenerList); + browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); + browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); + browser.storage.local.clear(); + const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + + }; + + browser.resetMAC3 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.storage.onChanged.removeListener(syncOnChangedListener); + + // sync state after FF2 synced + await browser.storage.sync.clear(); + const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; + sync.storageArea.set(syncData); + + // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) + removeContextualIdentityListeners(syncCIListenerList); + browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); + browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); + browser.storage.local.clear(); + const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + + }; + + browser.resetMAC4 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.storage.onChanged.removeListener(syncOnChangedListener); + + // sync state after FF2 synced + await browser.storage.sync.clear(); + const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; + sync.storageArea.set(syncData); + + // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) + removeContextualIdentityListeners(syncCIListenerList); + browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); + //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); + browser.storage.local.clear(); + const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + + }; +} \ No newline at end of file From 0252f9d1c39e8cfa17a847d8f7166da4b003f317 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 2 Jan 2020 17:42:09 -0600 Subject: [PATCH 19/60] refactored runSync and following functions --- src/js/background/assignManager.js | 15 +- src/js/background/identityState.js | 20 ++- src/js/background/sync.js | 262 ++++++++++++++++++----------- 3 files changed, 183 insertions(+), 114 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 5ab7bb0..765432d 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -1,4 +1,3 @@ -/* jshint esversion: 8*/ const assignManager = { MENU_ASSIGN_ID: "open-in-this-container", MENU_REMOVE_ID: "remove-open-in-this-container", @@ -14,11 +13,11 @@ const assignManager = { const beenSynced = await this.area.get("beenSynced"); if (Object.entries(beenSynced).length === 0) return false; return true; - }, + }, setSynced() { this.area.set({beenSynced: true}); - }, + }, getSiteStoreKey(pageUrl) { const url = new window.URL(pageUrl); @@ -53,14 +52,18 @@ const assignManager = { get(pageUrl) { const siteStoreKey = this.getSiteStoreKey(pageUrl); + return this.getByUrlKey(siteStoreKey); + }, + + getByUrlKey(siteStoreKey) { return new Promise((resolve, reject) => { this.area.get([siteStoreKey]).then((storageResponse) => { if (storageResponse && siteStoreKey in storageResponse) { resolve(storageResponse[siteStoreKey]); } - resolve(null); + resolve(()=> { throw new Error (siteStoreKey, " does not exist"); }); }).catch((e) => { - reject(e); + throw e; // reject(e); }); }); }, @@ -108,7 +111,7 @@ const assignManager = { site.hostname = urlKey.replace(/^siteContainerMap@@_/, ""); sites[urlKey] = site; } - }; + } return sites; }, }, diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 37f995f..92ced00 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -1,4 +1,3 @@ -/* jshint esversion: 8*/ const identityState = { storageArea: { area: browser.storage.local, @@ -14,10 +13,15 @@ const identityState = { if (storageResponse && storeKey in storageResponse) { return storageResponse[storeKey]; } - const defaultContainerState = identityState._createIdentityState(); - await this.set(cookieStoreId, defaultContainerState); - - return defaultContainerState; + const identities = await browser.contextualIdentities.query({}); + const match = identities.find( + (identity) => identity.cookieStoreId === cookieStoreId); + if (match) { + const defaultContainerState = identityState._createIdentityState(); + await this.set(cookieStoreId, defaultContainerState); + return defaultContainerState; + } + throw new Error (`${cookieStoreId} not found`); }, set(cookieStoreId, data) { @@ -97,11 +101,11 @@ const identityState = { }, async lookupMACaddonUUID(cookieStoreId) { - console.log(cookieStoreId) + console.log(cookieStoreId); const macConfigs = await this.storageArea.area.get(); for(const configKey of Object.keys(macConfigs)) { - if (configKey == "identitiesState@@_" + cookieStoreId) { - return macConfigs[configKey].macAddonUUID; + if (configKey === "identitiesState@@_" + cookieStoreId) { + return macConfigs[configKey].macAddonUUID; } } return false; diff --git a/src/js/background/sync.js b/src/js/background/sync.js index bfe6b34..7a0dd80 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,5 +1,4 @@ -/* jshint esversion: 8*/ -SYNC_DEBUG = true; +const SYNC_DEBUG = true; const sync = { storageArea: { @@ -24,8 +23,7 @@ const sync = { }, async getStoredItem(objectKey) { - const outputObject = await this.area.get(objectKey); - console.log(outputObject) + const outputObject = await this.get(objectKey); if (outputObject && outputObject[objectKey]) return outputObject[objectKey]; if (SYNC_DEBUG) @@ -34,14 +32,14 @@ const sync = { }, async hasSyncStorage(){ - const inSync = await this.storageArea.get(); + const inSync = await this.get(); return !(Object.entries(inSync).length === 0); }, async backup(options) { console.log("backup"); // remove listeners to avoid an infinite loop! - browser.storage.onChanged.removeListener(syncOnChangedListener); + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); removeContextualIdentityListeners(syncCIListenerList); await updateSyncIdentities(); @@ -61,7 +59,7 @@ const sync = { console.log("inLocal:", localStorage); } - await browser.storage.onChanged.addListener(syncOnChangedListener); + await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); await addContextualIdentityListeners(syncCIListenerList); async function updateSyncIdentities() { @@ -76,7 +74,8 @@ const sync = { } async function updateSyncSiteAssignments() { - const assignedSites = await assignManager.storageArea.getAssignedSites(); + const assignedSites = + await assignManager.storageArea.getAssignedSites(); await sync.storageArea.set({ assignedSites }); } @@ -92,7 +91,8 @@ const sync = { } async function addToDeletedSitesList(siteStoreKey) { - let { deletedSiteList } = await sync.storageArea.get("deletedSiteList"); + let { deletedSiteList } = + await sync.storageArea.get("deletedSiteList"); if (!deletedSiteList) deletedSiteList = []; if (deletedSiteList.find(element => element === siteStoreKey)) return; deletedSiteList.push(siteStoreKey); @@ -100,27 +100,49 @@ const sync = { } async function removeFromDeletedSitesList(siteStoreKey) { - let { deletedSiteList } = await sync.storageArea.get("deletedSiteList"); + let { deletedSiteList } = + await sync.storageArea.get("deletedSiteList"); if (!deletedSiteList) return; - deletedSiteList = deletedSiteList.filter(element => element !== siteStoreKey); + deletedSiteList = deletedSiteList + .filter(element => element !== siteStoreKey); await sync.storageArea.set({ deletedSiteList }); } }, async cleanup() { - console.log("cleanupSync") - const identitiesList = await sync.storageArea.getStoredObject("identities"); - const cookieStoreIDmap = await sync.storageArea.getStoredObject("cookieStoreIDmap"); + console.log("cleanupSync"); + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); + const identitiesList = + await sync.storageArea.getStoredObject("identities"); + const cookieStoreIDmap = + await sync.storageArea.getStoredObject("cookieStoreIDmap"); for(const cookieStoreId of Object.keys(cookieStoreIDmap)) { const match = identitiesList - .find(syncIdentity => syncIdentity.cookieStoreId === cookieStoreId); + .find(syncIdentity => + syncIdentity.cookieStoreId === cookieStoreId + ); if (!match) { delete cookieStoreIDmap[cookieStoreId]; await sync.storageArea.set({ cookieStoreIDmap }); console.log("removed ", cookieStoreId, " from sync list"); } } + await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); }, + + onChangedListener(changes, areaName) { + if (areaName === "sync") runSync(); + }, + + async addToDeletedList(changeInfo) { + const identity = changeInfo.contextualIdentity; + console.log("addToDeletedList", identity.cookieStoreId); + const deletedUUID = + await identityState.lookupMACaddonUUID(identity.cookieStoreId); + await identityState.storageArea.remove(identity.cookieStoreId); + console.log(deletedUUID); + sync.storageArea.backup({uuid: deletedUUID}); + } }, init() { @@ -183,28 +205,51 @@ async function restoreFirstRun() { async function reconcileIdentitiesByName(){ console.log("reconcileIdentitiesByName"); const localIdentities = await browser.contextualIdentities.query({}); - const syncIdentities = sync.storageArea.getStoredObject("identities"); - const cookieStoreIDmap = sync.storageArea.getStoredObject("cookieStoreIDmap"); + const syncIdentities = await sync.storageArea.getStoredObject("identities"); + const cookieStoreIDmap = + await sync.storageArea.getStoredObject("cookieStoreIDmap"); for (const syncIdentity of syncIdentities) { syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; - const match = localIdentities.find(localIdentity => localIdentity.name === syncIdentity.name); + const match = localIdentities.find( + localIdentity => localIdentity.name === syncIdentity.name + ); if (!match) { - console.log("create new ident: ", syncIdentity.name) - newIdentity = await browser.contextualIdentities.create({name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - await identityState.updateUUID(newIdentity.cookieStoreId, syncIdentity.macAddonUUID); + console.log("create new ident: ", syncIdentity.name); + const newIdentity = + await browser.contextualIdentities.create({ + name: syncIdentity.name, + color: syncIdentity.color, + icon: syncIdentity.icon + }); + await identityState.updateUUID( + newIdentity.cookieStoreId, + syncIdentity.macAddonUUID + ); continue; } - if (syncIdentity.color === match.color && syncIdentity.icon === match.icon) { - identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); + if (syncIdentity.color !== match.color + || syncIdentity.icon !== match.icon) { + await browser.contextualIdentities.update( + match.cookieStoreId, { + name: syncIdentity.name, + color: syncIdentity.color, + icon: syncIdentity.icon + }); continue; } if (SYNC_DEBUG) { - if (match.color !== syncIdentity.color) {console.log(match.name, "Change color: ", syncIdentity.color)} - if (match.icon !== syncIdentity.icon) {console.log(match.name, "Change icon: ", syncIdentity.icon)} + if (match.color !== syncIdentity.color) { + console.log(match.name, "Change color: ", syncIdentity.color); + } + if (match.icon !== syncIdentity.icon) { + console.log(match.name, "Change icon: ", syncIdentity.icon); + } } // end testing - await browser.contextualIdentities.update(match.cookieStoreId, {name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon}); - await identityState.updateUUID(match.cookieStoreId, syncIdentity.macAddonUUID); + await identityState.updateUUID( + match.cookieStoreId, + cookieStoreIDmap[syncIdentity.cookieStoreId] + ); } } @@ -214,11 +259,14 @@ async function reconcileIdentitiesByName(){ * a different assignment, the user is prompted (not yet implemented). * If it does not exist, it is created. */ -async function reconcileSiteAssignments(inSync) { +async function reconcileSiteAssignments() { console.log("reconcileSiteAssignments"); - const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); - const assignedSitesFromSync = await sync.storageArea.getStoredObject("assignedSites"); - const deletedSiteList = await sync.storageArea.getStoredArray("deletedSiteList"); + const assignedSitesLocal = + await assignManager.storageArea.getAssignedSites(); + const assignedSitesFromSync = + await sync.storageArea.getStoredObject("assignedSites"); + const deletedSiteList = + await sync.storageArea.getStoredArray("deletedSiteList"); for(const siteStoreKey of deletedSiteList) { if (assignedSitesLocal.hasOwnProperty(siteStoreKey)) { assignManager @@ -230,13 +278,15 @@ async function reconcileSiteAssignments(inSync) { await sync.storageArea.getStoredObject("cookieStoreIDmap"); for(const urlKey of Object.keys(assignedSitesFromSync)) { - const assignedSite = assignedSitesFromSync[urlKey] + const assignedSite = assignedSitesFromSync[urlKey]; if (assignedSitesLocal.hasOwnProperty(urlKey)) { const syncUUID = - lookupSyncSiteAssigmentIdentityUUID(assignedSite, cookieStoreIDmap); + await lookupSyncSiteAssigmentIdentityUUID( + assignedSite, cookieStoreIDmap, urlKey + ); const localIdentityUUID = - lookupLocalSiteAssignmentIdentityUUID(urlKey); + await lookupLocalSiteAssignmentIdentityUUID(urlKey); if (syncUUID === localIdentityUUID) { continue; @@ -245,29 +295,36 @@ async function reconcileSiteAssignments(inSync) { await setAssignmentWithUUID(syncUUID, assignedSite, urlKey); continue; } - console.log("new assignment ", assignedSite, ": ", assignedSite.userContextId) - const newUUID = await inSync.cookieStoreIDmap[ + console.log("new assignment ", assignedSite, ": ", + assignedSite.userContextId); + const newUUID = cookieStoreIDmap[ "firefox-container-" + assignedSite.userContextId ]; await setAssignmentWithUUID(newUUID, assignedSite, urlKey); } async function lookupLocalSiteAssignmentIdentityUUID(urlKey){ - const localAssignedSite = await assignManager.storageArea.getByUrlKey(urlKey); - if (!localAssignedSite.userContextId) - throw new Error (urlKey, "userContextId does not exist"); + const localAssignedSite = + await assignManager.storageArea.getByUrlKey(urlKey); + if (!localAssignedSite || !localAssignedSite.userContextId) + throw new Error (urlKey, "userContextId does not exist"); const localCookieStoreId = "firefox-container-" + localAssignedSite.userContextId; - return await identityState.storageArea.get(localCookieStoreId).macAddonUUID; + return await identityState.storageArea + .get(localCookieStoreId).macAddonUUID; } - async function lookupSyncSiteAssigmentIdentityUUID(assignedSite, cookieStoreIDmap){ - if (!assignedSite.userContextId) - throw new Error (urlKey, "userContextId does not exist"); - const syncCookieStoreId = "firefox-container-" + assignedSite.userContextId; - if (!cookieStoreIDmap[syncCookieStoreId]) - throw new Error (syncCookieStoreId, " does not have a uuid"); - return cookieStoreIDmap[syncCookieStoreId]; + async function lookupSyncSiteAssigmentIdentityUUID( + assignedSite, + cookieStoreIDmap, + urlKey + ){ + if (!assignedSite.userContextId) + throw new Error (`${urlKey} userContextId does not exist`); + const syncCookieStoreId = "firefox-container-" + assignedSite.userContextId; + if (!cookieStoreIDmap[syncCookieStoreId]) + throw new Error (syncCookieStoreId, " does not have a uuid"); + return cookieStoreIDmap[syncCookieStoreId]; } } @@ -282,77 +339,87 @@ async function setAssignmentWithUUID (newUUID, assignedSite, urlKey) { ); return; } - throw new Error ("No cookieStoreId found for: ", - newUUID, assignedSite, urlKey); + throw new Error (`No cookieStoreId found for: ${newUUID}, ${urlKey}`); } async function runSync() { - browser.storage.onChanged.removeListener(syncOnChangedListener); + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); removeContextualIdentityListeners(syncCIListenerList); console.log("runSync"); await identityState.storageArea.cleanup(); - const inSync = await sync.storageArea.get(); await sync.storageArea.cleanup(); - if (Object.entries(inSync).length === 0){ - console.log("no sync storage, backing up..."); - await sync.storageArea.backup(); + if (await sync.storageArea.hasSyncStorage()){ + console.log("storage found, attempting to restore ..."); + await restore(); return; } - console.log("storage found, attempting to restore ..."); - await restore(inSync); -} - -async function restore(inSync) { - console.log("restore"); - await reconcileIdentitiesByUUID(inSync); - await reconcileSiteAssignments(inSync); + console.log("no sync storage, backing up..."); await sync.storageArea.backup(); + return; } -function syncOnChangedListener(changes, areaName) { - if (areaName == "sync") runSync(); +async function restore() { + console.log("restore"); + await reconcileIdentitiesByUUID(); + await reconcileSiteAssignments(); + await sync.storageArea.backup(); } /* * Matches uuids in sync to uuids locally, and updates containers accordingly. * If there is no match, it creates the new container. */ -async function reconcileIdentitiesByUUID(inSync) { +async function reconcileIdentitiesByUUID() { console.log("reconcileIdentitiesByUUID"); - const syncIdentities = inSync.identities; - const syncCookieStoreIDmap = inSync.cookieStoreIDmap; - if (inSync.deletedIdentityList) { - for (const deletedUUID of inSync.deletedIdentityList) { - const deletedCookieStoreId = - await identityState.lookupCookieStoreId(deletedUUID); - if (deletedCookieStoreId){ - await browser.contextualIdentities.remove(deletedCookieStoreId); - } + const syncIdentities = await sync.storageArea.getStoredObject("identities"); + const cookieStoreIDmap = + await sync.storageArea.getStoredObject("cookieStoreIDmap"); + const deletedIdentityList = + await sync.storageArea.getStoredArray("deletedIdentityList"); + + // first remove any deleted identities + for (const deletedUUID of deletedIdentityList) { + const deletedCookieStoreId = + await identityState.lookupCookieStoreId(deletedUUID); + if (deletedCookieStoreId){ + await browser.contextualIdentities.remove(deletedCookieStoreId); } } - for (const syncCookieStoreID of Object.keys(syncCookieStoreIDmap)) { - const syncUUID = syncCookieStoreIDmap[syncCookieStoreID]; + // Lookup all identities in teh cookieStoreIDmap and make sure they + // exist locally + for (const syncCookieStoreID of Object.keys(cookieStoreIDmap)) { + const syncUUID = cookieStoreIDmap[syncCookieStoreID]; //find localCookiesStoreID by looking up the syncUUID - const localCookieStoreID = await identityState.lookupCookieStoreId(syncUUID); + const localCookieStoreID = + await identityState.lookupCookieStoreId(syncUUID); // get correct indentity info from sync - identityInfo = findIdentityFromSync(syncCookieStoreID, syncIdentities); + const identityInfo = + findIdentityFromSync(syncCookieStoreID, syncIdentities); if (localCookieStoreID) { if (SYNC_DEBUG) { - const getIdent = await browser.contextualIdentities.get(localCookieStoreID); - if (getIdent.name !== identityInfo.name) {console.log(getIdent.name, "Change name: ", identityInfo.name)} - if (getIdent.color !== identityInfo.color) {console.log(getIdent.name, "Change color: ", identityInfo.color)} - if (getIdent.icon !== identityInfo.icon) {console.log(getIdent.name, "Change icon: ", identityInfo.icon)} + const getIdent = + await browser.contextualIdentities.get(localCookieStoreID); + if (getIdent.name !== identityInfo.name) { + console.log(getIdent.name, "Change name: ", identityInfo.name); + } + if (getIdent.color !== identityInfo.color) { + console.log(getIdent.name, "Change color: ", identityInfo.color); + } + if (getIdent.icon !== identityInfo.icon) { + console.log(getIdent.name, "Change icon: ", identityInfo.icon); + } } // update the local container with the sync data - await browser.contextualIdentities.update(localCookieStoreID, identityInfo); + await browser.contextualIdentities + .update(localCookieStoreID, identityInfo); continue; } //not found, create new with same UUID - console.log("new Identity: ", identityInfo.name) - const newIdentity = await browser.contextualIdentities.create(identityInfo); - console.log(newIdentity.cookieStoreId) + console.log("new Identity: ", identityInfo.name); + const newIdentity = + await browser.contextualIdentities.create(identityInfo); await identityState.updateUUID(newIdentity.cookieStoreId, syncUUID); } return; @@ -367,7 +434,7 @@ function findIdentityFromSync(cookieStoreId, identitiesList){ const syncCIListenerList = [ sync.storageArea.backup, - addToDeletedList, + sync.storageArea.addToDeletedList, sync.storageArea.backup ]; @@ -383,21 +450,16 @@ function removeContextualIdentityListeners(listenerList) { browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); } -async function addToDeletedList(changeInfo) { - const identity = changeInfo.contextualIdentity; - console.log("addToDeletedList", identity.cookieStoreId); - const deletedUUID = - await identityState.lookupMACaddonUUID(identity.cookieStoreId); - await identityState.storageArea.remove(identity.cookieStoreId); - console.log(deletedUUID); - backup({uuid: deletedUUID}); -} + + + + if(SYNC_DEBUG) { browser.resetMAC1 = async function () { // for debugging and testing: remove all containers except the // default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); // sync state on install: no sync data await browser.storage.sync.clear(); @@ -410,7 +472,7 @@ if(SYNC_DEBUG) { browser.resetMAC2 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); // sync state after FF1 (default + 1) await browser.storage.sync.clear(); @@ -429,7 +491,7 @@ if(SYNC_DEBUG) { browser.resetMAC3 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); // sync state after FF2 synced await browser.storage.sync.clear(); @@ -448,7 +510,7 @@ if(SYNC_DEBUG) { browser.resetMAC4 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(syncOnChangedListener); + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); // sync state after FF2 synced await browser.storage.sync.clear(); From be3904cee8b983c1d122c0e47fad47cba248457c Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 6 Jan 2020 10:50:00 -0600 Subject: [PATCH 20/60] package.json testing scripts --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 753f292..85d20e9 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,8 @@ "lint:js": "eslint .", "package": "rm -rf src/web-ext-artifacts && npm run build && mv src/web-ext-artifacts/firefox_multi-account_containers-*.zip addon.xpi", "test": "npm run lint && npm run coverage", + "mocha": "mocha ./test/setup.js test/**/*.test.js", + "mochaSingle": "mocha", "test-watch": "mocha ./test/setup.js test/**/*.test.js --watch", "coverage": "nyc --reporter=html --reporter=text mocha ./test/setup.js test/**/*.test.js --timeout 60000" } From 26cd3c3cc89c9779c672b3ede0d35f788a020ffd Mon Sep 17 00:00:00 2001 From: stoically Date: Thu, 19 Dec 2019 07:49:41 +0100 Subject: [PATCH 21/60] Feature test container sync initialization --- test/features/sync.test.js | 66 ++++++++++++++++++++++++++++++++++++++ test/setup.js | 4 +++ 2 files changed, 70 insertions(+) create mode 100644 test/features/sync.test.js diff --git a/test/features/sync.test.js b/test/features/sync.test.js new file mode 100644 index 0000000..8a9e3cb --- /dev/null +++ b/test/features/sync.test.js @@ -0,0 +1,66 @@ +describe("Sync", () => { + let tab; + beforeEach(async () => { + tab = await helper.browser.initializeWithTab(); + }); + + it.only("should init sync on startup", async () => { + const mozContainer = await background.browser.contextualIdentities.create({ + name: "Mozilla", + color: "red", + icon: "briefcase", + }); + + await background.browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); + await background.browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); + + await Promise.all([ + { + userContextId: "1", + url: "https://twitter.com", + }, + { + userContextId: "2", + url: "https://www.facebook.com", + }, + { + userContextId: "4", + url: "https://www.linkedin.com", + neverAsk: true, + }, + { + userContextId: mozContainer.cookieStoreId.replace("firefox-container-", ""), + url: "https://developer.mozilla.org", + neverAsk: true, + } + ].map(async (assign) => { + await background.browser.tabs.update(tab.id, { + cookieStoreId: `firefox-container-${assign.userContextId}` + }); + + await background.browser.runtime.onMessage.addListener.yield({ + method: "setOrRemoveAssignment", + tabId: tab.id, + url: assign.url, + userContextId: assign.userContextId, + value: !true + }); + + if (assign.neverAsk) { + await nextTick(); + await background.browser.runtime.onMessage.addListener.yield({ + method: "neverAsk", + neverAsk: true, + pageUrl: assign.url, + }); + } + })); + + await background.browser.runtime.onStartup.addListener.yield(); + await nextTick(); + + const sync = await background.browser.storage.sync.get(); + + expect(sync.identities.length).to.equal(5); + }); +}); \ No newline at end of file diff --git a/test/setup.js b/test/setup.js index 0cc45ee..b674ba0 100644 --- a/test/setup.js +++ b/test/setup.js @@ -5,6 +5,7 @@ if (!process.listenerCount("unhandledRejection")) { const path = require("path"); const chai = require("chai"); const sinonChai = require("sinon-chai"); +const crypto = require("crypto"); global.sinon = require("sinon"); global.expect = chai.expect; chai.should(); @@ -29,6 +30,9 @@ global.buildDom = async ({background = {}, popup = {}}) => { ...background.jsom, beforeParse(window) { window.browser.permissions.getAll.resolves({permissions: ["bookmarks"]}); + window.crypto = { + getRandomValues: arr => crypto.randomBytes(arr.length), + }; } } }; From d0332927842c5b47cbbd5e0bdd56304c7ff95cae Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 6 Jan 2020 13:27:57 -0600 Subject: [PATCH 22/60] pulled in sync tests --- package.json | 2 +- src/js/background/sync.js | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 85d20e9..6a2d979 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "package": "rm -rf src/web-ext-artifacts && npm run build && mv src/web-ext-artifacts/firefox_multi-account_containers-*.zip addon.xpi", "test": "npm run lint && npm run coverage", "mocha": "mocha ./test/setup.js test/**/*.test.js", - "mochaSingle": "mocha", + "mochaSingle": "mocha ./test/setup.js", "test-watch": "mocha ./test/setup.js test/**/*.test.js --watch", "coverage": "nyc --reporter=html --reporter=text mocha ./test/setup.js test/**/*.test.js --timeout 60000" } diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 7a0dd80..a8c8a40 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,4 +1,4 @@ -const SYNC_DEBUG = true; +const SYNC_DEBUG = false; const sync = { storageArea: { @@ -153,8 +153,10 @@ const sync = { async initSync() { const syncInfo = await sync.storageArea.get(); const localInfo = await browser.storage.local.get(); - console.log("inSync: ", syncInfo); - console.log("inLocal: ", localInfo); + if (SYNC_DEBUG) { + console.log("inSync: ", syncInfo); + console.log("inLocal: ", localInfo); + } const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ runSync(); From f7b20f97b8a057f7969e105e7295348100093d8e Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 7 Jan 2020 14:14:19 -0600 Subject: [PATCH 23/60] working with tests --- src/js/background/identityState.js | 6 ++- src/js/background/sync.js | 53 ++++++------------- test/features/external-webextensions.test.js | 1 + test/features/sync.test.js | 54 +++++++++++++++++--- test/helper.js | 37 +++++++++++++- 5 files changed, 107 insertions(+), 44 deletions(-) diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 92ced00..850ee50 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -11,6 +11,10 @@ const identityState = { const storeKey = this.getContainerStoreKey(cookieStoreId); const storageResponse = await this.area.get([storeKey]); if (storageResponse && storeKey in storageResponse) { + if (!storageResponse[storeKey].macAddonUUID){ + await identityState.addUUID(cookieStoreId); + return this.get(cookieStoreId); + } return storageResponse[storeKey]; } const identities = await browser.contextualIdentities.query({}); @@ -91,7 +95,7 @@ const identityState = { const containerState = await this.storageArea.get(cookieStoreId); containerState.macAddonUUID = uuid; await this.storageArea.set(cookieStoreId, containerState); - return; + return uuid; } throw new Error ("cookieStoreId or uuid missing"); }, diff --git a/src/js/background/sync.js b/src/js/background/sync.js index a8c8a40..a8175ea 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -37,7 +37,7 @@ const sync = { }, async backup(options) { - console.log("backup"); + if (SYNC_DEBUG) console.log("backup"); // remove listeners to avoid an infinite loop! browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); removeContextualIdentityListeners(syncCIListenerList); @@ -281,51 +281,32 @@ async function reconcileSiteAssignments() { for(const urlKey of Object.keys(assignedSitesFromSync)) { const assignedSite = assignedSitesFromSync[urlKey]; - if (assignedSitesLocal.hasOwnProperty(urlKey)) { - const syncUUID = - await lookupSyncSiteAssigmentIdentityUUID( - assignedSite, cookieStoreIDmap, urlKey - ); - - const localIdentityUUID = - await lookupLocalSiteAssignmentIdentityUUID(urlKey); - - if (syncUUID === localIdentityUUID) { - continue; - } - // overwrite with Sync data. Sync is the source of truth - await setAssignmentWithUUID(syncUUID, assignedSite, urlKey); + const syncUUID = + await lookupSyncSiteAssigmentIdentityUUID( + assignedSite, cookieStoreIDmap, urlKey + ); + if (syncUUID) { + // Sync is truth. + // Not even looking it up. Just overwrite + console.log("new assignment ", assignedSite, ": ", + assignedSite.userContextId); + const newUUID = cookieStoreIDmap[ + "firefox-container-" + assignedSite.userContextId + ]; + await setAssignmentWithUUID(newUUID, assignedSite, urlKey); continue; } - console.log("new assignment ", assignedSite, ": ", - assignedSite.userContextId); - const newUUID = cookieStoreIDmap[ - "firefox-container-" + assignedSite.userContextId - ]; - await setAssignmentWithUUID(newUUID, assignedSite, urlKey); - } - async function lookupLocalSiteAssignmentIdentityUUID(urlKey){ - const localAssignedSite = - await assignManager.storageArea.getByUrlKey(urlKey); - if (!localAssignedSite || !localAssignedSite.userContextId) - throw new Error (urlKey, "userContextId does not exist"); - const localCookieStoreId = "firefox-container-" + - localAssignedSite.userContextId; - return await identityState.storageArea - .get(localCookieStoreId).macAddonUUID; + // if there's no syncUUID, something is wrong, since these site + // assignments are from sync + throw new Error("Sync storage not aligned"); } async function lookupSyncSiteAssigmentIdentityUUID( assignedSite, cookieStoreIDmap, - urlKey ){ - if (!assignedSite.userContextId) - throw new Error (`${urlKey} userContextId does not exist`); const syncCookieStoreId = "firefox-container-" + assignedSite.userContextId; - if (!cookieStoreIDmap[syncCookieStoreId]) - throw new Error (syncCookieStoreId, " does not have a uuid"); return cookieStoreIDmap[syncCookieStoreId]; } } diff --git a/test/features/external-webextensions.test.js b/test/features/external-webextensions.test.js index 30e6b49..04ebb99 100644 --- a/test/features/external-webextensions.test.js +++ b/test/features/external-webextensions.test.js @@ -26,6 +26,7 @@ describe("External Webextensions", () => { const [promise] = background.browser.runtime.onMessageExternal.addListener.yield(message, sender); const answer = await promise; expect(answer).to.deep.equal({ + hostname: "example.com", userContextId: "1", neverAsk: false }); diff --git a/test/features/sync.test.js b/test/features/sync.test.js index 8a9e3cb..9a91c98 100644 --- a/test/features/sync.test.js +++ b/test/features/sync.test.js @@ -1,10 +1,9 @@ describe("Sync", () => { - let tab; - beforeEach(async () => { - tab = await helper.browser.initializeWithTab(); - }); it.only("should init sync on startup", async () => { + console.log("!!!a") + const tab = await helper.browser.initializeWithTab(); + console.log(await background.browser.storage.local.get()); const mozContainer = await background.browser.contextualIdentities.create({ name: "Mozilla", color: "red", @@ -55,12 +54,55 @@ describe("Sync", () => { }); } })); - + console.log("!!!c"); await background.browser.runtime.onStartup.addListener.yield(); await nextTick(); const sync = await background.browser.storage.sync.get(); + console.log(await background.browser.storage.local.get()); expect(sync.identities.length).to.equal(5); + console.log("!!!b"); }); -}); \ No newline at end of file + + it("should sync for the first time", async () => { + const mozContainer = await background.browser.contextualIdentities.create({ + name:"Test", + color:"green", + icon:"pet" + }); + console.log(await background.browser.contextualIdentities.query({})); + await helper.browser.initSyncTest({localStorage:SYNC_TEST_1_LOCAL}); + console.log(await background.browser.storage.local.get()); + for (const containerName of SYNC_TEST_CONTAINERS) { + const storageKeyString = "identitiesState@@_" + containerName; + const answer = await background.browser.storage.local.get(storageKeyString); + expect(answer[storageKeyString].hasOwnProperty("macAddonUUID")).to.be.true; + } + const storageKeyString = "identitiesState@@_" + mozContainer.cookieStoreId; + const answer = await background.browser.storage.local.get(storageKeyString); + expect(answer[storageKeyString].hasOwnProperty("macAddonUUID")).to.be.true; + }); +}); + +const SYNC_TEST_1_LOCAL = { + "browserActionBadgesClicked":["6.1.1"], + "containerTabsOpened":6, + "identitiesState@@_firefox-container-1":{"hiddenTabs":[]}, + "identitiesState@@_firefox-container-2":{"hiddenTabs":[]}, + "identitiesState@@_firefox-container-3":{"hiddenTabs":[]}, + "identitiesState@@_firefox-container-4":{"hiddenTabs":[]}, + "identitiesState@@_firefox-container-6":{"hiddenTabs":[]}, + "identitiesState@@_firefox-default":{"hiddenTabs":[]}, + "onboarding-stage":5, + "siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true}, + "siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true}, + "siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false} +}; + +const SYNC_TEST_CONTAINERS = [ + "firefox-container-1", + "firefox-container-2", + "firefox-container-3", + "firefox-container-4" +]; \ No newline at end of file diff --git a/test/helper.js b/test/helper.js index 2704bac..f14ed81 100644 --- a/test/helper.js +++ b/test/helper.js @@ -19,6 +19,7 @@ module.exports = { "achievements": [] }); window.browser.storage.local.set.resetHistory(); + window.browser.storage.sync.clear(); } } } @@ -29,7 +30,41 @@ module.exports = { async openNewTab(tab, options = {}) { return background.browser.tabs._create(tab, options); - } + }, + + async initSyncTest(details = {}) { + if (!details.cookieStoreId) details.cookieStoreId = "firefox-default"; + if (!details.localStorage) { + details.localStorage = { + "browserActionBadgesClicked": [], + "onboarding-stage": 5, + "achievements": [] + }; + } + if (!details.syncStorage) details.syncStorage = {}; + let tab; + await buildDom({ + background: { + async afterBuild(background) { + tab = await background.browser.tabs._create({ cookieStoreId: details.cookieStoreId }); + } + }, + popup: { + jsdom: { + beforeParse(window) { + window.browser.storage.clear(); + window.browser.storage.local.set(details.localStorage); + window.browser.storage.local.set.resetHistory(); + window.browser.storage.sync.clear(); + window.browser.storage.sync.set(details.syncStorage); + window.browser.storage.sync.set.resetHistory(); + } + }, + } + }); + + return tab; + }, }, popup: { From c522d36a660e8a46dbb9725a4ae3f9006b289ffd Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 8 Jan 2020 13:23:35 -0600 Subject: [PATCH 24/60] error handling --- src/js/background/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/background/index.html b/src/js/background/index.html index da380ba..78dbe21 100644 --- a/src/js/background/index.html +++ b/src/js/background/index.html @@ -19,5 +19,6 @@ + From 53a901d0232c36fdf1032ae949c21a19d5ce0c9f Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 8 Jan 2020 13:32:02 -0600 Subject: [PATCH 25/60] saving to do some work --- src/js/background/sync.js | 101 ++++------------------- src/js/background/test.js | 168 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 86 deletions(-) create mode 100644 src/js/background/test.js diff --git a/src/js/background/sync.js b/src/js/background/sync.js index a8175ea..15447db 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,4 +1,4 @@ -const SYNC_DEBUG = false; +const SYNC_DEBUG = true; const sync = { storageArea: { @@ -40,7 +40,7 @@ const sync = { if (SYNC_DEBUG) console.log("backup"); // remove listeners to avoid an infinite loop! browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - removeContextualIdentityListeners(syncCIListenerList); + removeContextualIdentityListeners(); await updateSyncIdentities(); await updateCookieStoreIdMap(); @@ -60,7 +60,7 @@ const sync = { } await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); - await addContextualIdentityListeners(syncCIListenerList); + await addContextualIdentityListeners(); async function updateSyncIdentities() { const identities = await browser.contextualIdentities.query({}); @@ -146,8 +146,13 @@ const sync = { }, init() { - browser.runtime.onInstalled.addListener(this.initSync); - browser.runtime.onStartup.addListener(this.initSync); + const errorHandledInitSync = () => { + this.initSync().catch((error)=> { + console.error("Error from initSync", error); + }); + }; + browser.runtime.onInstalled.addListener(errorHandledInitSync); + browser.runtime.onStartup.addListener(errorHandledInitSync); }, async initSync() { @@ -159,10 +164,10 @@ const sync = { } const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ - runSync(); + await runSync(); return; } - runFirstSync(); + await runFirstSync(); }, }; @@ -327,7 +332,7 @@ async function setAssignmentWithUUID (newUUID, assignedSite, urlKey) { async function runSync() { browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - removeContextualIdentityListeners(syncCIListenerList); + removeContextualIdentityListeners(); console.log("runSync"); await identityState.storageArea.cleanup(); await sync.storageArea.cleanup(); @@ -422,91 +427,15 @@ const syncCIListenerList = [ ]; function addContextualIdentityListeners(listenerList) { + if(!listenerList) listenerList = syncCIListenerList; browser.contextualIdentities.onCreated.addListener(listenerList[0]); browser.contextualIdentities.onRemoved.addListener(listenerList[1]); browser.contextualIdentities.onUpdated.addListener(listenerList[2]); } function removeContextualIdentityListeners(listenerList) { + if(!listenerList) listenerList = syncCIListenerList; browser.contextualIdentities.onCreated.removeListener(listenerList[0]); browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); -} - - - - - - -if(SYNC_DEBUG) { - browser.resetMAC1 = async function () { - // for debugging and testing: remove all containers except the - // default 4 and the first one created - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - - // sync state on install: no sync data - await browser.storage.sync.clear(); - - // FF1: no sync, Only default containers and 1 extra - browser.storage.local.clear(); - const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; - browser.storage.local.set(localData); - }; - - browser.resetMAC2 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - - // sync state after FF1 (default + 1) - await browser.storage.sync.clear(); - const syncData = {"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; - sync.storageArea.set(syncData); - - // FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(syncCIListenerList); - browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); - browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); - browser.storage.local.clear(); - const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - - }; - - browser.resetMAC3 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - - // sync state after FF2 synced - await browser.storage.sync.clear(); - const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; - sync.storageArea.set(syncData); - - // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(syncCIListenerList); - browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); - browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); - browser.storage.local.clear(); - const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - - }; - - browser.resetMAC4 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - - // sync state after FF2 synced - await browser.storage.sync.clear(); - const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; - sync.storageArea.set(syncData); - - // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) - removeContextualIdentityListeners(syncCIListenerList); - browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); - //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); - browser.storage.local.clear(); - const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - - }; } \ No newline at end of file diff --git a/src/js/background/test.js b/src/js/background/test.js new file mode 100644 index 0000000..0cdee0a --- /dev/null +++ b/src/js/background/test.js @@ -0,0 +1,168 @@ +browser.tests = { + async runAll() { + await this.test1(); + }, + + async test1() { + await browser.tests.stopSyncListeners(); + + // sync state on install: no sync data + await browser.storage.sync.clear(); + await this.removeAllContainers(); + await browser.storage.local.clear(); + const localData = { + "browserActionBadgesClicked": [ "6.1.1" ], + "containerTabsOpened": 7, + "identitiesState@@_firefox-default": { "hiddenTabs": [] }, + "onboarding-stage": 5 + }; + await browser.storage.local.set(localData); + for (const containerInputSet of TEST_CONTAINERS) { + await browser.contextualIdentities.create(containerInputSet); + } + + await sync.initSync(); + + const getSync = await browser.storage.sync.get(); + const getAssignedSites = + await assignManager.storageArea.getAssignedSites(); + const identities = await browser.contextualIdentities.query({}); + const localCookieStoreIDmap = + await identityState.getCookieStoreIDuuidMap(); + + console.assert( + Object.keys(getSync.cookieStoreIDmap).length === 5, + "cookieStoreIDmap should have 5 entries" + ); + + console.assert( + Object.keys(localCookieStoreIDmap).length === 6, + "localCookieStoreIDmap should have 6 entries" + ); + + console.assert( + identities.length === 5, + "There should be 5 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 0, + "There should be no site assignments" + ); + console.log("Finished!"); + }, + + async removeAllContainers() { + const identities = await browser.contextualIdentities.query({}); + for (const identity of identities) { + await browser.contextualIdentities.remove(identity.cookieStoreId); + } + }, + + stopSyncListeners() { + browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); + removeContextualIdentityListeners(); + }, + + startListeners() { + browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); + addContextualIdentityListeners(); + }, + +}; + +const TEST_CONTAINERS = [ + { + name: "Personal", + color: "blue", + icon: "fingerprint" + }, + { + name: "Banking", + color: "green", + icon: "dollar" + }, + { + name: "Mozilla", + color: "red", + icon: "briefcase" + }, + { + name: "Groceries, obviously", + color: "yellow", + icon: "cart" + }, + { + name: "Facebook", + color: "toolbar", + icon: "fence" + }, +]; + + +browser.resetMAC1 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.tests.stopSyncListeners(); + + // sync state on install: no sync data + await browser.storage.sync.clear(); + + // FF1: no sync, Only default containers and 1 extra + browser.storage.local.clear(); + const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; + browser.storage.local.set(localData); +}; + +browser.resetMAC2 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.tests.stopSyncListeners(); + + // sync state after FF1 (default + 1) + await browser.storage.sync.clear(); + const syncData = {"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; + browser.storage.sync.set(syncData); + + // FF2 (intial sync w/ default 4 + 1 with some changes) + browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); + browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); + browser.storage.local.clear(); + const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + +}; + +browser.resetMAC3 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.tests.stopSyncListeners(); + + // sync state after FF2 synced + await browser.storage.sync.clear(); + const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; + browser.storage.sync.set(syncData); + + // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) + browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); + //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); + browser.storage.local.clear(); + const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + +}; + +browser.resetMAC4 = async function () { + // for debugging and testing: remove all containers except the default 4 and the first one created + browser.tests.stopSyncListeners(); + + // sync state after FF2 synced + await browser.storage.sync.clear(); + const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; + browser.storage.sync.set(syncData); + + // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) + browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); + //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); + browser.storage.local.clear(); + const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; + browser.storage.local.set(localData); + +}; \ No newline at end of file From 53f7dc491581603b3f32e2158723b189398a92da Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 8 Jan 2020 15:37:08 -0600 Subject: [PATCH 26/60] added some tests in the browser html --- src/js/background/assignManager.js | 133 ++++++++++++++++++--------- src/js/background/sync.js | 62 +++++++------ src/js/background/test.js | 139 ++++++++++++++++++++++++++--- test/features/sync.test.js | 42 +-------- 4 files changed, 253 insertions(+), 123 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 765432d..7098f62 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -61,9 +61,9 @@ const assignManager = { if (storageResponse && siteStoreKey in storageResponse) { resolve(storageResponse[siteStoreKey]); } - resolve(()=> { throw new Error (siteStoreKey, " does not exist"); }); + resolve(null); }).catch((e) => { - throw e; // reject(e); + reject(e); }); }); }, @@ -101,8 +101,11 @@ const assignManager = { const siteConfigs = await this.area.get(); for(const urlKey of Object.keys(siteConfigs)) { if (urlKey.includes("siteContainerMap@@_")) { - // For some reason this is stored as string... lets check them both as that - if (!!userContextId && String(siteConfigs[urlKey].userContextId) !== String(userContextId)) { + // For some reason this is stored as string... lets check + // them both as that + if (!!userContextId && + String(siteConfigs[urlKey].userContextId) + !== String(userContextId)) { continue; } const site = siteConfigs[urlKey]; @@ -119,7 +122,8 @@ const assignManager = { _neverAsk(m) { const pageUrl = m.pageUrl; if (m.neverAsk === true) { - // If we have existing data and for some reason it hasn't been deleted etc lets update it + // If we have existing data and for some reason it hasn't been + // deleted etc lets update it this.storageArea.get(pageUrl).then((siteSettings) => { if (siteSettings) { siteSettings.neverAsk = true; @@ -138,7 +142,8 @@ const assignManager = { return true; }, - // Before a request is handled by the browser we decide if we should route through a different container + // Before a request is handled by the browser we decide if we should + // route through a different container async onBeforeRequest(options) { if (options.frameId !== 0 || options.tabId === -1) { return {}; @@ -150,13 +155,14 @@ const assignManager = { ]); let container; try { - container = await browser.contextualIdentities.get(backgroundLogic.cookieStoreId(siteSettings.userContextId)); + container = await browser.contextualIdentities + .get(backgroundLogic.cookieStoreId(siteSettings.userContextId)); } catch (e) { container = false; } - // The container we have in the assignment map isn't present any more so lets remove it - // then continue the existing load + // The container we have in the assignment map isn't present any + // more so lets remove it then continue the existing load if (siteSettings && !container) { this.deleteContainer(siteSettings.userContextId); return {}; @@ -173,7 +179,8 @@ const assignManager = { const openTabId = removeTab ? tab.openerTabId : tab.id; if (!this.canceledRequests[tab.id]) { - // we decided to cancel the request at this point, register canceled request + // we decided to cancel the request at this point, register + // canceled request this.canceledRequests[tab.id] = { requestIds: { [options.requestId]: true @@ -183,8 +190,10 @@ const assignManager = { } }; - // since webRequest onCompleted and onErrorOccurred are not 100% reliable (see #1120) - // we register a timer here to cleanup canceled requests, just to make sure we don't + // since webRequest onCompleted and onErrorOccurred are not 100% + // reliable (see #1120) + // we register a timer here to cleanup canceled requests, just to + // make sure we don't // end up in a situation where certain urls in a tab.id stay canceled setTimeout(() => { if (this.canceledRequests[tab.id]) { @@ -196,10 +205,12 @@ const assignManager = { if (this.canceledRequests[tab.id].requestIds[options.requestId] || this.canceledRequests[tab.id].urls[options.url]) { // same requestId or url from the same tab - // this is a redirect that we have to cancel early to prevent opening two tabs + // this is a redirect that we have to cancel early to prevent + // opening two tabs cancelEarly = true; } - // we decided to cancel the request at this point, register canceled request + // we decided to cancel the request at this point, register canceled + // request this.canceledRequests[tab.id].requestIds[options.requestId] = true; this.canceledRequests[tab.id].urls[options.url] = true; if (cancelEarly) { @@ -221,15 +232,27 @@ const assignManager = { this.calculateContextMenu(tab); /* Removal of existing tabs: - We aim to open the new assigned container tab / warning prompt in it's own tab: - - As the history won't span from one container to another it seems most sane to not try and reopen a tab on history.back() - - When users open a new tab themselves we want to make sure we don't end up with three tabs as per: https://github.com/mozilla/testpilot-containers/issues/421 - If we are coming from an internal url that are used for the new tab page (NEW_TAB_PAGES), we can safely close as user is unlikely losing history - Detecting redirects on "new tab" opening actions is pretty hard as we don't get tab history: - - Redirects happen from Short URLs and tracking links that act as a gateway - - Extensions don't provide a way to history crawl for tabs, we could inject content scripts to do this - however they don't run on about:blank so this would likely be just as hacky. - We capture the time the tab was created and close if it was within the timeout to try to capture pages which haven't had user interaction or history. + We aim to open the new assigned container tab / warning prompt in + it's own tab: + - As the history won't span from one container to another it + seems most sane to not try and reopen a tab on history.back() + - When users open a new tab themselves we want to make sure we + don't end up with three tabs as per: + https://github.com/mozilla/testpilot-containers/issues/421 + If we are coming from an internal url that are used for the new + tab page (NEW_TAB_PAGES), we can safely close as user is unlikely + losing history + Detecting redirects on "new tab" opening actions is pretty hard + as we don't get tab history: + - Redirects happen from Short URLs and tracking links that act as + a gateway + - Extensions don't provide a way to history crawl for tabs, we + could inject content scripts to do this + however they don't run on about:blank so this would likely be + just as hacky. + We capture the time the tab was created and close if it was within + the timeout to try to capture pages which haven't had user + interaction or history. */ if (removeTab) { browser.tabs.remove(tab.id); @@ -241,10 +264,13 @@ const assignManager = { init() { browser.contextMenus.onClicked.addListener((info, tab) => { - info.bookmarkId ? this._onClickedBookmark(info) : this._onClickedHandler(info, tab); + info.bookmarkId ? + this._onClickedBookmark(info) : + this._onClickedHandler(info, tab); }); - // Before a request is handled by the browser we decide if we should route through a different container + // Before a request is handled by the browser we decide if we should + // route through a different container this.canceledRequests = {}; browser.webRequest.onBeforeRequest.addListener((options) => { return this.onBeforeRequest(options); @@ -266,21 +292,29 @@ const assignManager = { }, async resetBookmarksMenuItem() { - const hasPermission = await browser.permissions.contains({permissions: ["bookmarks"]}); + const hasPermission = await browser.permissions.contains({ + permissions: ["bookmarks"] + }); if (this.hadBookmark === hasPermission) { return; } this.hadBookmark = hasPermission; if (hasPermission) { this.initBookmarksMenu(); - browser.contextualIdentities.onCreated.addListener(this.contextualIdentityCreated); - browser.contextualIdentities.onUpdated.addListener(this.contextualIdentityUpdated); - browser.contextualIdentities.onRemoved.addListener(this.contextualIdentityRemoved); + browser.contextualIdentities.onCreated + .addListener(this.contextualIdentityCreated); + browser.contextualIdentities.onUpdated + .addListener(this.contextualIdentityUpdated); + browser.contextualIdentities.onRemoved + .addListener(this.contextualIdentityRemoved); } else { this.removeBookmarksMenu(); - browser.contextualIdentities.onCreated.removeListener(this.contextualIdentityCreated); - browser.contextualIdentities.onUpdated.removeListener(this.contextualIdentityUpdated); - browser.contextualIdentities.onRemoved.removeListener(this.contextualIdentityRemoved); + browser.contextualIdentities.onCreated + .removeListener(this.contextualIdentityCreated); + browser.contextualIdentities.onUpdated + .removeListener(this.contextualIdentityUpdated); + browser.contextualIdentities.onRemoved + .removeListener(this.contextualIdentityRemoved); } }, @@ -289,19 +323,25 @@ const assignManager = { parentId: assignManager.OPEN_IN_CONTAINER, id: changeInfo.contextualIdentity.cookieStoreId, title: changeInfo.contextualIdentity.name, - icons: { "16": `img/usercontext.svg#${changeInfo.contextualIdentity.icon}` } + icons: { "16": `img/usercontext.svg#${ + changeInfo.contextualIdentity.icon + }` } }); }, contextualIdentityUpdated(changeInfo) { - browser.contextMenus.update(changeInfo.contextualIdentity.cookieStoreId, { - title: changeInfo.contextualIdentity.name, - icons: { "16": `img/usercontext.svg#${changeInfo.contextualIdentity.icon}` } - }); + browser.contextMenus.update( + changeInfo.contextualIdentity.cookieStoreId, { + title: changeInfo.contextualIdentity.name, + icons: { "16": `img/usercontext.svg#${ + changeInfo.contextualIdentity.icon}` } + }); }, contextualIdentityRemoved(changeInfo) { - browser.contextMenus.remove(changeInfo.contextualIdentity.cookieStoreId); + browser.contextMenus.remove( + changeInfo.contextualIdentity.cookieStoreId + ); }, async _onClickedHandler(info, tab) { @@ -317,7 +357,9 @@ const assignManager = { } else { remove = true; } - await this._setOrRemoveAssignment(tab.id, info.pageUrl, userContextId, remove); + await this._setOrRemoveAssignment( + tab.id, info.pageUrl, userContextId, remove + ); break; case this.MENU_MOVE_ID: backgroundLogic.moveTabsToWindow({ @@ -338,7 +380,8 @@ const assignManager = { async _onClickedBookmark(info) { async function _getBookmarksFromInfo(info) { - const [bookmarkTreeNode] = await browser.bookmarks.get(info.bookmarkId); + const [bookmarkTreeNode] = + await browser.bookmarks.get(info.bookmarkId); if (bookmarkTreeNode.type === "folder") { return await browser.bookmarks.getChildren(bookmarkTreeNode.id); } @@ -347,8 +390,10 @@ const assignManager = { const bookmarks = await _getBookmarksFromInfo(info); for (const bookmark of bookmarks) { - // Some checks on the urls from https://github.com/Rob--W/bookmark-container-tab/ thanks! - if ( !/^(javascript|place):/i.test(bookmark.url) && bookmark.type !== "folder") { + // Some checks on the urls from + // https://github.com/Rob--W/bookmark-container-tab/ thanks! + if ( !/^(javascript|place):/i.test(bookmark.url) && + bookmark.type !== "folder") { const openInReaderMode = bookmark.url.startsWith("about:reader"); if(openInReaderMode) { try { @@ -376,7 +421,9 @@ const assignManager = { if (!("cookieStoreId" in tab)) { return false; } - return backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId); + return backgroundLogic.getUserContextIdFromCookieStoreId( + tab.cookieStoreId + ); }, isTabPermittedAssign(tab) { diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 15447db..41497bf 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,4 +1,4 @@ -const SYNC_DEBUG = true; +const SYNC_DEBUG = false; const sync = { storageArea: { @@ -39,28 +39,32 @@ const sync = { async backup(options) { if (SYNC_DEBUG) console.log("backup"); // remove listeners to avoid an infinite loop! - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); + browser.storage.onChanged.removeListener( + sync.storageArea.onChangedListener); removeContextualIdentityListeners(); - - await updateSyncIdentities(); - await updateCookieStoreIdMap(); - await updateSyncSiteAssignments(); - if (options && options.uuid) - await updateDeletedIdentityList(options.uuid); - if (options && options.siteStoreKey) - await addToDeletedSitesList(options.siteStoreKey); - if (options && options.undelete) - await removeFromDeletedSitesList(options.undelete); + try { + await updateSyncIdentities(); + await updateCookieStoreIdMap(); + await updateSyncSiteAssignments(); + if (options && options.uuid) + await updateDeletedIdentityList(options.uuid); + if (options && options.siteStoreKey) + await addToDeletedSitesList(options.siteStoreKey); + if (options && options.undelete) + await removeFromDeletedSitesList(options.undelete); - if (SYNC_DEBUG) { - const storage = await sync.storageArea.get(); - console.log("in sync: ", storage); - const localStorage = await browser.storage.local.get(); - console.log("inLocal:", localStorage); + if (SYNC_DEBUG) { + const storage = await sync.storageArea.get(); + console.log("in sync: ", storage); + const localStorage = await browser.storage.local.get(); + console.log("inLocal:", localStorage); + } + } catch (error) { + console.error("Error backing up", error); } - - await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); - await addContextualIdentityListeners(); + browser.storage.onChanged.addListener( + sync.storageArea.onChangedListener); + addContextualIdentityListeners(); async function updateSyncIdentities() { const identities = await browser.contextualIdentities.query({}); @@ -111,7 +115,8 @@ const sync = { async cleanup() { console.log("cleanupSync"); - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); + browser.storage.onChanged.removeListener( + sync.storageArea.onChangedListener); const identitiesList = await sync.storageArea.getStoredObject("identities"); const cookieStoreIDmap = @@ -127,7 +132,8 @@ const sync = { console.log("removed ", cookieStoreId, " from sync list"); } } - await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); + await browser.storage.onChanged.addListener( + sync.storageArea.onChangedListener); }, onChangedListener(changes, areaName) { @@ -212,7 +218,8 @@ async function restoreFirstRun() { async function reconcileIdentitiesByName(){ console.log("reconcileIdentitiesByName"); const localIdentities = await browser.contextualIdentities.query({}); - const syncIdentities = await sync.storageArea.getStoredObject("identities"); + const syncIdentities = + await sync.storageArea.getStoredObject("identities"); const cookieStoreIDmap = await sync.storageArea.getStoredObject("cookieStoreIDmap"); for (const syncIdentity of syncIdentities) { @@ -311,7 +318,8 @@ async function reconcileSiteAssignments() { assignedSite, cookieStoreIDmap, ){ - const syncCookieStoreId = "firefox-container-" + assignedSite.userContextId; + const syncCookieStoreId = + "firefox-container-" + assignedSite.userContextId; return cookieStoreIDmap[syncCookieStoreId]; } } @@ -331,7 +339,8 @@ async function setAssignmentWithUUID (newUUID, assignedSite, urlKey) { } async function runSync() { - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); + browser.storage.onChanged.removeListener( + sync.storageArea.onChangedListener); removeContextualIdentityListeners(); console.log("runSync"); await identityState.storageArea.cleanup(); @@ -416,7 +425,8 @@ async function reconcileIdentitiesByUUID() { function findIdentityFromSync(cookieStoreId, identitiesList){ for (const identity of identitiesList) { const { name, color, icon } = identity; - if (identity.cookieStoreId === cookieStoreId) return { name, color, icon }; + if (identity.cookieStoreId === cookieStoreId) + return { name, color, icon }; } } diff --git a/src/js/background/test.js b/src/js/background/test.js index 0cdee0a..97a6c53 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -1,10 +1,12 @@ browser.tests = { async runAll() { await this.test1(); + await this.test2(); }, async test1() { await browser.tests.stopSyncListeners(); + console.log("Testing new install with no sync"); // sync state on install: no sync data await browser.storage.sync.clear(); @@ -52,6 +54,123 @@ browser.tests = { console.log("Finished!"); }, + async test2() { + await browser.tests.stopSyncListeners(); + console.log("Testing sync differing"); + + // sync state on install: no sync data + await browser.storage.sync.clear(); + const syncData = { + "identities": [ + { + "name": "Personal", + "icon": "fingerprint", + "iconUrl": "resource://usercontext-content/fingerprint.svg", + "color": "red", + "colorCode": "#37adff", + "cookieStoreId": "firefox-container-146" + }, + { + "name": "Oscar", + "icon": "dollar", + "iconUrl": "resource://usercontext-content/dollar.svg", + "color": "green", + "colorCode": "#51cd00", + "cookieStoreId": "firefox-container-147" + }, + { + "name": "Mozilla", + "icon": "pet", + "iconUrl": "resource://usercontext-content/briefcase.svg", + "color": "red", + "colorCode": "#ff613d", + "cookieStoreId": "firefox-container-148" + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "iconUrl": "resource://usercontext-content/cart.svg", + "color": "pink", + "colorCode": "#ffcb00", + "cookieStoreId": "firefox-container-149" + }, + { + "name": "Facebook", + "icon": "fence", + "iconUrl": "resource://usercontext-content/fence.svg", + "color": "toolbar", + "colorCode": "#7c7c7d", + "cookieStoreId": "firefox-container-150" + } + ], + "cookieStoreIDmap": { + "firefox-container-146": "22ded543-5173-44a5-a47a-8813535945ca", + "firefox-container-147": "63e5212f-0858-418e-b5a3-09c2dea61fcd", + "firefox-container-148": "71335417-158e-4d74-a55b-e9e9081601ec", + "firefox-container-149": "59c4e5f7-fe3b-435a-ae60-1340db31a91b", + "firefox-container-150": "3dc916fb-8c0a-4538-9758-73ef819a45f7" + }, + "assignedSites": {} + }; + await browser.storage.sync.set(syncData); + await browser.storage.local.clear(); + const localData = { + "browserActionBadgesClicked": [ "6.1.1" ], + "containerTabsOpened": 7, + "identitiesState@@_firefox-default": { "hiddenTabs": [] }, + "onboarding-stage": 5 + }; + await this.removeAllContainers(); + console.log("TEST_CONTAINERS.length", TEST_CONTAINERS.length); + for (let i=0; i < TEST_CONTAINERS.length; i++) { + //build identities + const newIdentity = + await browser.contextualIdentities.create(TEST_CONTAINERS[i]); + // fill identies with site assignments + if (TEST_ASSIGNMENTS[i]) { + localData[TEST_ASSIGNMENTS[i]] = { + "userContextId": + String( + newIdentity.cookieStoreId.replace(/^firefox-container-/, "") + ), + "neverAsk": true + }; + } + } + await browser.storage.local.set(localData); + console.log("local storage set: ", await browser.storage.local.get()); + + await sync.initSync(); + + const getSync = await browser.storage.sync.get(); + const getAssignedSites = + await assignManager.storageArea.getAssignedSites(); + const identities = await browser.contextualIdentities.query({}); + const localCookieStoreIDmap = + await identityState.getCookieStoreIDuuidMap(); + console.log(getSync.cookieStoreIDmap); + console.assert( + Object.keys(getSync.cookieStoreIDmap).length === 6, + "cookieStoreIDmap should have 6 entries" + ); + + console.assert( + Object.keys(localCookieStoreIDmap).length === 7, + "localCookieStoreIDmap should have 7 entries" + ); + + console.assert( + identities.length === 6, + "There should be 6 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 5, + "There should be 5 site assignments" + ); + console.log("Finished!"); + }, + async removeAllContainers() { const identities = await browser.contextualIdentities.query({}); for (const identity of identities) { @@ -99,19 +218,13 @@ const TEST_CONTAINERS = [ }, ]; - -browser.resetMAC1 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.tests.stopSyncListeners(); - - // sync state on install: no sync data - await browser.storage.sync.clear(); - - // FF1: no sync, Only default containers and 1 extra - browser.storage.local.clear(); - const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":6,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false}}; - browser.storage.local.set(localData); -}; +const TEST_ASSIGNMENTS = [ + "siteContainerMap@@_developer.mozilla.org", + "siteContainerMap@@_twitter.com", + "siteContainerMap@@_www.facebook.com", + "siteContainerMap@@_www.linkedin.com", + "siteContainerMap@@_reddit.com" +]; browser.resetMAC2 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created diff --git a/test/features/sync.test.js b/test/features/sync.test.js index 9a91c98..ddc87a0 100644 --- a/test/features/sync.test.js +++ b/test/features/sync.test.js @@ -65,44 +65,4 @@ describe("Sync", () => { console.log("!!!b"); }); - it("should sync for the first time", async () => { - const mozContainer = await background.browser.contextualIdentities.create({ - name:"Test", - color:"green", - icon:"pet" - }); - console.log(await background.browser.contextualIdentities.query({})); - await helper.browser.initSyncTest({localStorage:SYNC_TEST_1_LOCAL}); - console.log(await background.browser.storage.local.get()); - for (const containerName of SYNC_TEST_CONTAINERS) { - const storageKeyString = "identitiesState@@_" + containerName; - const answer = await background.browser.storage.local.get(storageKeyString); - expect(answer[storageKeyString].hasOwnProperty("macAddonUUID")).to.be.true; - } - const storageKeyString = "identitiesState@@_" + mozContainer.cookieStoreId; - const answer = await background.browser.storage.local.get(storageKeyString); - expect(answer[storageKeyString].hasOwnProperty("macAddonUUID")).to.be.true; - }); -}); - -const SYNC_TEST_1_LOCAL = { - "browserActionBadgesClicked":["6.1.1"], - "containerTabsOpened":6, - "identitiesState@@_firefox-container-1":{"hiddenTabs":[]}, - "identitiesState@@_firefox-container-2":{"hiddenTabs":[]}, - "identitiesState@@_firefox-container-3":{"hiddenTabs":[]}, - "identitiesState@@_firefox-container-4":{"hiddenTabs":[]}, - "identitiesState@@_firefox-container-6":{"hiddenTabs":[]}, - "identitiesState@@_firefox-default":{"hiddenTabs":[]}, - "onboarding-stage":5, - "siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":true}, - "siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":true}, - "siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":false} -}; - -const SYNC_TEST_CONTAINERS = [ - "firefox-container-1", - "firefox-container-2", - "firefox-container-3", - "firefox-container-4" -]; \ No newline at end of file +}); \ No newline at end of file From 3a7744b41b3f45c9bc9459c704b8d0f49a1e8b9e Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 8 Jan 2020 18:33:02 -0600 Subject: [PATCH 27/60] wrote tests tests for browser use --- src/js/background/identityState.js | 24 +++- src/js/background/sync.js | 130 +++++++++++---------- src/js/background/test.js | 179 +++++++++++++++++------------ test/features/sync.test.js | 2 +- 4 files changed, 197 insertions(+), 138 deletions(-) diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 850ee50..d032790 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -39,19 +39,37 @@ const identityState = { const storeKey = this.getContainerStoreKey(cookieStoreId); return await this.area.remove([storeKey]); }, + + /* + * Looks for abandoned identities keys in local storage, and makes sure all + * identities registered in the browser are also in local storage. (this + * appears to not always be the case based on how this.get() is written) + */ async cleanup() { const identitiesList = await browser.contextualIdentities.query({}); const macConfigs = await this.area.get(); for(const configKey of Object.keys(macConfigs)) { if (configKey.includes("identitiesState@@_")) { const cookieStoreId = String(configKey).replace(/^identitiesState@@_/, ""); - const match = identitiesList.find(localIdentity => localIdentity.cookieStoreId === cookieStoreId); - if (!match && cookieStoreId !== "firefox-default") { - console.log("removed ", cookieStoreId, " from storage list"); + const match = identitiesList.find( + localIdentity => localIdentity.cookieStoreId === cookieStoreId + ); + if (cookieStoreId === "firefox-default") continue; + if (!match) { this.remove(cookieStoreId); + continue; + } + if (!macConfigs[configKey].macAddonUUID) { + await identityState.addUUID(cookieStoreId); } } } + + for (const identity of identitiesList) { + // ensure all identities have an entry in local storage + const data = await this.get(identity.cookieStoreId); + await this.set(identity.cookieStoreId, data); + } } }, diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 41497bf..ff01e82 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,4 +1,4 @@ -const SYNC_DEBUG = false; +const SYNC_DEBUG = true; const sync = { storageArea: { @@ -39,28 +39,25 @@ const sync = { async backup(options) { if (SYNC_DEBUG) console.log("backup"); // remove listeners to avoid an infinite loop! - browser.storage.onChanged.removeListener( + await browser.storage.onChanged.removeListener( sync.storageArea.onChangedListener); - removeContextualIdentityListeners(); - try { - await updateSyncIdentities(); - await updateCookieStoreIdMap(); - await updateSyncSiteAssignments(); - if (options && options.uuid) - await updateDeletedIdentityList(options.uuid); - if (options && options.siteStoreKey) - await addToDeletedSitesList(options.siteStoreKey); - if (options && options.undelete) - await removeFromDeletedSitesList(options.undelete); - - if (SYNC_DEBUG) { - const storage = await sync.storageArea.get(); - console.log("in sync: ", storage); - const localStorage = await browser.storage.local.get(); - console.log("inLocal:", localStorage); - } - } catch (error) { - console.error("Error backing up", error); + + await removeContextualIdentityListeners(); + + await updateSyncIdentities(); + await updateCookieStoreIdMap(); + await updateSyncSiteAssignments(); + if (options && options.uuid) + await updateDeletedIdentityList(options.uuid); + if (options && options.siteStoreKey) + await addToDeletedSitesList(options.siteStoreKey); + if (options && options.undelete) + await removeFromDeletedSitesList(options.undelete); + if (SYNC_DEBUG) { + const storage = await sync.storageArea.get(); + console.log("in sync: ", storage); + const localStorage = await browser.storage.local.get(); + console.log("inLocal:", localStorage); } browser.storage.onChanged.addListener( sync.storageArea.onChangedListener); @@ -113,6 +110,10 @@ const sync = { } }, + /* + * Ensures all sync info matches. But maybe we shouldn't even use + * sync info that doesn't match. + */ async cleanup() { console.log("cleanupSync"); browser.storage.onChanged.removeListener( @@ -180,12 +181,38 @@ const sync = { sync.init(); +async function runSync() { + browser.storage.onChanged.removeListener( + sync.storageArea.onChangedListener); + removeContextualIdentityListeners(); + console.log("runSync"); + await identityState.storageArea.cleanup(); + + + if (await sync.storageArea.hasSyncStorage()){ + await sync.storageArea.cleanup(); + console.log("storage found, attempting to restore ..."); + await restore(); + return; + } + console.log("no sync storage, backing up..."); + await sync.storageArea.backup(); + return; +} + +async function restore() { + console.log("restore"); + await reconcileIdentitiesByUUID(); + await reconcileSiteAssignments(); + await sync.storageArea.backup(); +} + async function runFirstSync() { console.log("runFirstSync"); + // looks for abandoned identities keys in local storage, and identities + // not in localstorage (which also adds a uuid) await identityState.storageArea.cleanup(); - const localIdentities = await browser.contextualIdentities.query({}); - await addUUIDsToContainers(localIdentities); - // const inSync = await sync.storageArea.get(); + if (await sync.storageArea.hasSyncStorage()){ await sync.storageArea.cleanup(); console.log("storage found, attempting to restore ..."); @@ -197,17 +224,11 @@ async function runFirstSync() { await assignManager.storageArea.setSynced(); } -async function addUUIDsToContainers(localIdentities) { - for (const identity of localIdentities) { - await identityState.addUUID(identity.cookieStoreId); - } -} - async function restoreFirstRun() { console.log("restoreFirstRun"); - await reconcileIdentitiesByName(); + await reconcileIdentities(); await reconcileSiteAssignments(); - sync.storageArea.backup(); + await sync.storageArea.backup(); } /* @@ -215,8 +236,21 @@ async function restoreFirstRun() { * same container, and the color and icon are overwritten from sync, if * different. */ -async function reconcileIdentitiesByName(){ - console.log("reconcileIdentitiesByName"); +async function reconcileIdentities(){ + console.log("reconcileIdentities"); + + // first delete any from the deleted list + const deletedIdentityList = + await sync.storageArea.getStoredArray("deletedIdentityList"); + // first remove any deleted identities + for (const deletedUUID of deletedIdentityList) { + const deletedCookieStoreId = + await identityState.lookupCookieStoreId(deletedUUID); + if (deletedCookieStoreId){ + await browser.contextualIdentities.remove(deletedCookieStoreId); + } + } + const localIdentities = await browser.contextualIdentities.query({}); const syncIdentities = await sync.storageArea.getStoredObject("identities"); @@ -338,30 +372,6 @@ async function setAssignmentWithUUID (newUUID, assignedSite, urlKey) { throw new Error (`No cookieStoreId found for: ${newUUID}, ${urlKey}`); } -async function runSync() { - browser.storage.onChanged.removeListener( - sync.storageArea.onChangedListener); - removeContextualIdentityListeners(); - console.log("runSync"); - await identityState.storageArea.cleanup(); - await sync.storageArea.cleanup(); - if (await sync.storageArea.hasSyncStorage()){ - console.log("storage found, attempting to restore ..."); - await restore(); - return; - } - console.log("no sync storage, backing up..."); - await sync.storageArea.backup(); - return; -} - -async function restore() { - console.log("restore"); - await reconcileIdentitiesByUUID(); - await reconcileSiteAssignments(); - await sync.storageArea.backup(); -} - /* * Matches uuids in sync to uuids locally, and updates containers accordingly. * If there is no match, it creates the new container. @@ -371,9 +381,9 @@ async function reconcileIdentitiesByUUID() { const syncIdentities = await sync.storageArea.getStoredObject("identities"); const cookieStoreIDmap = await sync.storageArea.getStoredObject("cookieStoreIDmap"); + const deletedIdentityList = await sync.storageArea.getStoredArray("deletedIdentityList"); - // first remove any deleted identities for (const deletedUUID of deletedIdentityList) { const deletedCookieStoreId = diff --git a/src/js/background/test.js b/src/js/background/test.js index 97a6c53..1001075 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -1,24 +1,54 @@ browser.tests = { async runAll() { + await this.testIdentityStateCleanup(); await this.test1(); await this.test2(); }, + async testIdentityStateCleanup() { + await browser.tests.stopSyncListeners(); + console.log("Testing the cleanup of local storage"); + await this.removeAllContainers(); + const localData = { + "browserActionBadgesClicked": [ "6.1.1" ], + "containerTabsOpened": 7, + "identitiesState@@_firefox-default": { "hiddenTabs": [] }, + "onboarding-stage": 5, + "identitiesState@@_firefox-container-7": { "hiddenTabs": [] } + }; + await browser.storage.local.clear(); + await browser.storage.local.set(localData); + // async function assignIdentities () { + for (const containerInputSet of TEST_CONTAINERS) { + await browser.contextualIdentities.create(containerInputSet); + } + // } + // await assignIdentities(); + await identityState.storageArea.cleanup(); + const macConfigs = await browser.storage.local.get(); + const identities = []; + + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("identitiesState@@_") && !configKey.includes("default")) { + identities.push(macConfigs[configKey]); + } + } + + console.assert(identities.length === 5, "There should be 5 identity entries"); + for (const identity of identities) { + console.assert(!!identity.macAddonUUID, `${identity.name} should have a uuid`); + } + console.log("Finished!"); + }, async test1() { await browser.tests.stopSyncListeners(); console.log("Testing new install with no sync"); // sync state on install: no sync data await browser.storage.sync.clear(); - await this.removeAllContainers(); await browser.storage.local.clear(); - const localData = { - "browserActionBadgesClicked": [ "6.1.1" ], - "containerTabsOpened": 7, - "identitiesState@@_firefox-default": { "hiddenTabs": [] }, - "onboarding-stage": 5 - }; - await browser.storage.local.set(localData); + await browser.storage.local.set(LOCAL_DATA); + await this.removeAllContainers(); for (const containerInputSet of TEST_CONTAINERS) { await browser.contextualIdentities.create(containerInputSet); } @@ -56,72 +86,13 @@ browser.tests = { async test2() { await browser.tests.stopSyncListeners(); - console.log("Testing sync differing"); + console.log("Testing sync differing from local"); - // sync state on install: no sync data - await browser.storage.sync.clear(); - const syncData = { - "identities": [ - { - "name": "Personal", - "icon": "fingerprint", - "iconUrl": "resource://usercontext-content/fingerprint.svg", - "color": "red", - "colorCode": "#37adff", - "cookieStoreId": "firefox-container-146" - }, - { - "name": "Oscar", - "icon": "dollar", - "iconUrl": "resource://usercontext-content/dollar.svg", - "color": "green", - "colorCode": "#51cd00", - "cookieStoreId": "firefox-container-147" - }, - { - "name": "Mozilla", - "icon": "pet", - "iconUrl": "resource://usercontext-content/briefcase.svg", - "color": "red", - "colorCode": "#ff613d", - "cookieStoreId": "firefox-container-148" - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "iconUrl": "resource://usercontext-content/cart.svg", - "color": "pink", - "colorCode": "#ffcb00", - "cookieStoreId": "firefox-container-149" - }, - { - "name": "Facebook", - "icon": "fence", - "iconUrl": "resource://usercontext-content/fence.svg", - "color": "toolbar", - "colorCode": "#7c7c7d", - "cookieStoreId": "firefox-container-150" - } - ], - "cookieStoreIDmap": { - "firefox-container-146": "22ded543-5173-44a5-a47a-8813535945ca", - "firefox-container-147": "63e5212f-0858-418e-b5a3-09c2dea61fcd", - "firefox-container-148": "71335417-158e-4d74-a55b-e9e9081601ec", - "firefox-container-149": "59c4e5f7-fe3b-435a-ae60-1340db31a91b", - "firefox-container-150": "3dc916fb-8c0a-4538-9758-73ef819a45f7" - }, - "assignedSites": {} - }; - await browser.storage.sync.set(syncData); - await browser.storage.local.clear(); - const localData = { - "browserActionBadgesClicked": [ "6.1.1" ], - "containerTabsOpened": 7, - "identitiesState@@_firefox-default": { "hiddenTabs": [] }, - "onboarding-stage": 5 - }; await this.removeAllContainers(); - console.log("TEST_CONTAINERS.length", TEST_CONTAINERS.length); + await browser.storage.sync.clear(); + await browser.storage.sync.set(SYNC_DATA); + await browser.storage.local.clear(); + const localData = LOCAL_DATA; for (let i=0; i < TEST_CONTAINERS.length; i++) { //build identities const newIdentity = @@ -141,14 +112,16 @@ browser.tests = { console.log("local storage set: ", await browser.storage.local.get()); await sync.initSync(); - + const getSync = await browser.storage.sync.get(); const getAssignedSites = await assignManager.storageArea.getAssignedSites(); + const identities = await browser.contextualIdentities.query({}); + const localCookieStoreIDmap = await identityState.getCookieStoreIDuuidMap(); - console.log(getSync.cookieStoreIDmap); + console.assert( Object.keys(getSync.cookieStoreIDmap).length === 6, "cookieStoreIDmap should have 6 entries" @@ -225,7 +198,65 @@ const TEST_ASSIGNMENTS = [ "siteContainerMap@@_www.linkedin.com", "siteContainerMap@@_reddit.com" ]; +const LOCAL_DATA = { + "browserActionBadgesClicked": [ "6.1.1" ], + "containerTabsOpened": 7, + "identitiesState@@_firefox-default": { "hiddenTabs": [] }, + "onboarding-stage": 5 +}; +const SYNC_DATA = { + "identities": [ + { + "name": "Personal", + "icon": "fingerprint", + "iconUrl": "resource://usercontext-content/fingerprint.svg", + "color": "red", + "colorCode": "#37adff", + "cookieStoreId": "firefox-container-146" + }, + { + "name": "Oscar", + "icon": "dollar", + "iconUrl": "resource://usercontext-content/dollar.svg", + "color": "green", + "colorCode": "#51cd00", + "cookieStoreId": "firefox-container-147" + }, + { + "name": "Mozilla", + "icon": "pet", + "iconUrl": "resource://usercontext-content/briefcase.svg", + "color": "red", + "colorCode": "#ff613d", + "cookieStoreId": "firefox-container-148" + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "iconUrl": "resource://usercontext-content/cart.svg", + "color": "pink", + "colorCode": "#ffcb00", + "cookieStoreId": "firefox-container-149" + }, + { + "name": "Facebook", + "icon": "fence", + "iconUrl": "resource://usercontext-content/fence.svg", + "color": "toolbar", + "colorCode": "#7c7c7d", + "cookieStoreId": "firefox-container-150" + } + ], + "cookieStoreIDmap": { + "firefox-container-146": "22ded543-5173-44a5-a47a-8813535945ca", + "firefox-container-147": "63e5212f-0858-418e-b5a3-09c2dea61fcd", + "firefox-container-148": "71335417-158e-4d74-a55b-e9e9081601ec", + "firefox-container-149": "59c4e5f7-fe3b-435a-ae60-1340db31a91b", + "firefox-container-150": "3dc916fb-8c0a-4538-9758-73ef819a45f7" + }, + "assignedSites": {} +}; browser.resetMAC2 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created browser.tests.stopSyncListeners(); diff --git a/test/features/sync.test.js b/test/features/sync.test.js index ddc87a0..72656fa 100644 --- a/test/features/sync.test.js +++ b/test/features/sync.test.js @@ -1,6 +1,6 @@ describe("Sync", () => { - it.only("should init sync on startup", async () => { + it("should init sync on startup", async () => { console.log("!!!a") const tab = await helper.browser.initializeWithTab(); console.log(await background.browser.storage.local.get()); From 34180aa2d537fdf0792a0195275d4e926fa35b94 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 8 Jan 2020 23:38:01 -0600 Subject: [PATCH 28/60] worked on the duplicate bug --- src/js/background/sync.js | 127 +++++++++++----- src/js/background/test.js | 304 ++++++++++++++++++++++++++++++++------ 2 files changed, 346 insertions(+), 85 deletions(-) diff --git a/src/js/background/sync.js b/src/js/background/sync.js index ff01e82..2905e53 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -58,6 +58,7 @@ const sync = { console.log("in sync: ", storage); const localStorage = await browser.storage.local.get(); console.log("inLocal:", localStorage); + console.log("indents: ", await browser.contextualIdentities.query({})); } browser.storage.onChanged.addListener( sync.storageArea.onChangedListener); @@ -168,6 +169,7 @@ const sync = { if (SYNC_DEBUG) { console.log("inSync: ", syncInfo); console.log("inLocal: ", localInfo); + console.log("indents: ", await browser.contextualIdentities.query({})); } const beenSynced = await assignManager.storageArea.getSynced(); if (beenSynced){ @@ -202,7 +204,7 @@ async function runSync() { async function restore() { console.log("restore"); - await reconcileIdentitiesByUUID(); + await reconcileIdentities(); await reconcileSiteAssignments(); await sync.storageArea.backup(); } @@ -250,57 +252,104 @@ async function reconcileIdentities(){ await browser.contextualIdentities.remove(deletedCookieStoreId); } } - + const localIdentities = await browser.contextualIdentities.query({}); const syncIdentities = - await sync.storageArea.getStoredObject("identities"); + await sync.storageArea.getStoredArray("identities"); const cookieStoreIDmap = await sync.storageArea.getStoredObject("cookieStoreIDmap"); + // now compare all containers for matching names. for (const syncIdentity of syncIdentities) { syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; - const match = localIdentities.find( + const localMatch = localIdentities.find( localIdentity => localIdentity.name === syncIdentity.name ); - if (!match) { - console.log("create new ident: ", syncIdentity.name); - const newIdentity = + if (!localMatch) { + // if there's no name match found, check on uuid, + const localCookieStoreID = + await identityState.lookupCookieStoreId(syncIdentity.macAddonUUID); + if (localCookieStoreID) { + await ifUUIDMatch(syncIdentity, localCookieStoreID); + continue; + } + await ifNoMatch(syncIdentity); + continue; + } + await ifNamesMatch(syncIdentity, localMatch); + continue; + } +} + +async function ifNamesMatch(syncIdentity, localMatch) { + // Sync is truth. if there is a match, compare data and update as needed + if (syncIdentity.color !== localMatch.color + || syncIdentity.icon !== localMatch.icon) { + await browser.contextualIdentities.update( + localMatch.cookieStoreId, { + name: syncIdentity.name, + color: syncIdentity.color, + icon: syncIdentity.icon + }); + + if (SYNC_DEBUG) { + if (localMatch.color !== syncIdentity.color) { + console.log(localMatch.name, "Change color: ", syncIdentity.color); + } + if (localMatch.icon !== syncIdentity.icon) { + console.log(localMatch.name, "Change icon: ", syncIdentity.icon); + } + } + } + + // Sync is truth. If all is the same, update the local uuid to match sync + await identityState.updateUUID( + localMatch.cookieStoreId, + syncIdentity.macAddonUUID + ); +} + +async function ifUUIDMatch(syncIdentity, localCookieStoreID) { + // if there's a local uuid, it's the same container. Sync is truth + const identityInfo = { + name: syncIdentity.name, + color: syncIdentity.color, + icon: syncIdentity.icon + }; + if (SYNC_DEBUG) { + const getIdent = + await browser.contextualIdentities.get(localCookieStoreID); + if (getIdent.name !== identityInfo.name) { + console.log(getIdent.name, "Change name: ", identityInfo.name); + } + if (getIdent.color !== identityInfo.color) { + console.log(getIdent.name, "Change color: ", identityInfo.color); + } + if (getIdent.icon !== identityInfo.icon) { + console.log(getIdent.name, "Change icon: ", identityInfo.icon); + } + } + + // update the local container with the sync data + await browser.contextualIdentities + .update(localCookieStoreID, identityInfo); + return; +} + +async function ifNoMatch(syncIdentity){ + // if no uuid match either, make new identity + console.log("create new ident: ", syncIdentity.name); + const newIdentity = await browser.contextualIdentities.create({ name: syncIdentity.name, color: syncIdentity.color, icon: syncIdentity.icon }); - await identityState.updateUUID( - newIdentity.cookieStoreId, - syncIdentity.macAddonUUID - ); - continue; - } - if (syncIdentity.color !== match.color - || syncIdentity.icon !== match.icon) { - await browser.contextualIdentities.update( - match.cookieStoreId, { - name: syncIdentity.name, - color: syncIdentity.color, - icon: syncIdentity.icon - }); - continue; - } - if (SYNC_DEBUG) { - if (match.color !== syncIdentity.color) { - console.log(match.name, "Change color: ", syncIdentity.color); - } - if (match.icon !== syncIdentity.icon) { - console.log(match.name, "Change icon: ", syncIdentity.icon); - } - } - // end testing - await identityState.updateUUID( - match.cookieStoreId, - cookieStoreIDmap[syncIdentity.cookieStoreId] - ); - } + await identityState.updateUUID( + newIdentity.cookieStoreId, + syncIdentity.macAddonUUID + ); + return; } - /* * Checks for site previously assigned. If it exists, and has the same * container assignment, the assignment is kept. If it exists, but has @@ -381,7 +430,7 @@ async function reconcileIdentitiesByUUID() { const syncIdentities = await sync.storageArea.getStoredObject("identities"); const cookieStoreIDmap = await sync.storageArea.getStoredObject("cookieStoreIDmap"); - + const deletedIdentityList = await sync.storageArea.getStoredArray("deletedIdentityList"); // first remove any deleted identities diff --git a/src/js/background/test.js b/src/js/background/test.js index 1001075..d6bba42 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -3,31 +3,35 @@ browser.tests = { await this.testIdentityStateCleanup(); await this.test1(); await this.test2(); + await this.dupeTest(); }, async testIdentityStateCleanup() { await browser.tests.stopSyncListeners(); console.log("Testing the cleanup of local storage"); - await this.removeAllContainers(); - const localData = { - "browserActionBadgesClicked": [ "6.1.1" ], - "containerTabsOpened": 7, - "identitiesState@@_firefox-default": { "hiddenTabs": [] }, - "onboarding-stage": 5, - "identitiesState@@_firefox-container-7": { "hiddenTabs": [] } - }; - await browser.storage.local.clear(); - await browser.storage.local.set(localData); - // async function assignIdentities () { - for (const containerInputSet of TEST_CONTAINERS) { - await browser.contextualIdentities.create(containerInputSet); - } + + await this.setState({}, LOCAL_DATA, TEST_CONTAINERS); + + // await this.removeAllContainers(); + // const localData = { + // "browserActionBadgesClicked": [ "6.1.1" ], + // "containerTabsOpened": 7, + // "identitiesState@@_firefox-default": { "hiddenTabs": [] }, + // "onboarding-stage": 5, + // "identitiesState@@_firefox-container-7": { "hiddenTabs": [] } + // }; + // await browser.storage.local.clear(); + // await browser.storage.local.set(localData); + // // async function assignIdentities () { + // for (const containerInputSet of TEST_CONTAINERS) { + // await browser.contextualIdentities.create(containerInputSet); + // } // } // await assignIdentities(); await identityState.storageArea.cleanup(); + const macConfigs = await browser.storage.local.get(); const identities = []; - for(const configKey of Object.keys(macConfigs)) { if (configKey.includes("identitiesState@@_") && !configKey.includes("default")) { identities.push(macConfigs[configKey]); @@ -44,14 +48,7 @@ browser.tests = { await browser.tests.stopSyncListeners(); console.log("Testing new install with no sync"); - // sync state on install: no sync data - await browser.storage.sync.clear(); - await browser.storage.local.clear(); - await browser.storage.local.set(LOCAL_DATA); - await this.removeAllContainers(); - for (const containerInputSet of TEST_CONTAINERS) { - await browser.contextualIdentities.create(containerInputSet); - } + await this.setState({}, LOCAL_DATA, TEST_CONTAINERS); await sync.initSync(); @@ -88,31 +85,10 @@ browser.tests = { await browser.tests.stopSyncListeners(); console.log("Testing sync differing from local"); - await this.removeAllContainers(); - await browser.storage.sync.clear(); - await browser.storage.sync.set(SYNC_DATA); - await browser.storage.local.clear(); - const localData = LOCAL_DATA; - for (let i=0; i < TEST_CONTAINERS.length; i++) { - //build identities - const newIdentity = - await browser.contextualIdentities.create(TEST_CONTAINERS[i]); - // fill identies with site assignments - if (TEST_ASSIGNMENTS[i]) { - localData[TEST_ASSIGNMENTS[i]] = { - "userContextId": - String( - newIdentity.cookieStoreId.replace(/^firefox-container-/, "") - ), - "neverAsk": true - }; - } - } - await browser.storage.local.set(localData); - console.log("local storage set: ", await browser.storage.local.get()); + await this.setState(SYNC_DATA, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); await sync.initSync(); - + const getSync = await browser.storage.sync.get(); const getAssignedSites = await assignManager.storageArea.getAssignedSites(); @@ -144,6 +120,102 @@ browser.tests = { console.log("Finished!"); }, + async dupeTest() { + await browser.tests.stopSyncListeners(); + console.log("Test state from duped sync"); + + await this.setState( + DUPE_TEST_SYNC, + DUPE_TEST_LOCAL, + DUPE_TEST_IDENTS, + DUPE_TEST_ASSIGNMENTS + ); + + await sync.initSync(); + + const getSync = await browser.storage.sync.get(); + const getAssignedSites = + await assignManager.storageArea.getAssignedSites(); + + const identities = await browser.contextualIdentities.query({}); + + const localCookieStoreIDmap = + await identityState.getCookieStoreIDuuidMap(); + + console.assert( + Object.keys(getSync.cookieStoreIDmap).length === 7, + "cookieStoreIDmap should have 7 entries" + ); + + console.assert( + Object.keys(localCookieStoreIDmap).length === 8, + "localCookieStoreIDmap should have 8 entries" + ); + + console.assert( + identities.length === 7, + "There should be 7 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 5, + "There should be 5 site assignments" + ); + + const personalContainer = + this.lookupIdentityBy(identities, {name: "Personal"}); + console.log(personalContainer); + console.assert( + personalContainer.color === "red", + "Personal Container should be red" + ); + const mozillaContainer = + this.lookupIdentityBy(identities, {name: "Mozilla"}); + console.assert( + mozillaContainer.icon === "pet", + "Mozilla Container should be pet" + ); + console.log("Finished!"); + }, + + lookupIdentityBy(identities, options) { + for (const identity of identities) { + if (options && options.name) { + if (identity.name === options.name) return identity; + } + if (options && options.color) { + if (identity.color === options.color) return identity; + } + if (options && options.color) { + if (identity.color === options.color) return identity; + } + } + return false; + }, + async setState(syncData, localData, indentityData, assignmentData){ + await this.removeAllContainers(); + await browser.storage.sync.clear(); + await browser.storage.sync.set(syncData); + await browser.storage.local.clear(); + for (let i=0; i < indentityData.length; i++) { + //build identities + const newIdentity = + await browser.contextualIdentities.create(indentityData[i]); + // fill identies with site assignments + if (assignmentData && assignmentData[i]) { + localData[assignmentData[i]] = { + "userContextId": + String( + newIdentity.cookieStoreId.replace(/^firefox-container-/, "") + ), + "neverAsk": true + }; + } + } + await browser.storage.local.set(localData); + console.log("local storage set: ", await browser.storage.local.get()); + return; + }, async removeAllContainers() { const identities = await browser.contextualIdentities.query({}); for (const identity of identities) { @@ -275,6 +347,146 @@ browser.resetMAC2 = async function () { }; +const DUPE_TEST_SYNC = { + "identities": [ + { + "name": "Personal", + "icon": "fingerprint", + "iconUrl": "resource://usercontext-content/fingerprint.svg", + "color": "red", + "colorCode": "#ff613d", + "cookieStoreId": "firefox-container-588" + }, + { + "name": "Banking", + "icon": "dollar", + "iconUrl": "resource://usercontext-content/dollar.svg", + "color": "green", + "colorCode": "#51cd00", + "cookieStoreId": "firefox-container-589" + }, + { + "name": "Mozilla", + "icon": "pet", + "iconUrl": "resource://usercontext-content/pet.svg", + "color": "red", + "colorCode": "#ff613d", + "cookieStoreId": "firefox-container-590" + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "iconUrl": "resource://usercontext-content/cart.svg", + "color": "pink", + "colorCode": "#ff4bda", + "cookieStoreId": "firefox-container-591" + }, + { + "name": "Facebook", + "icon": "fence", + "iconUrl": "resource://usercontext-content/fence.svg", + "color": "toolbar", + "colorCode": "#7c7c7d", + "cookieStoreId": "firefox-container-592" + }, + { + "name": "Oscar", + "icon": "dollar", + "iconUrl": "resource://usercontext-content/dollar.svg", + "color": "green", + "colorCode": "#51cd00", + "cookieStoreId": "firefox-container-593" + } + ], + "cookieStoreIDmap": { + "firefox-container-588": "d20d7af2-9866-468e-bb43-541efe8c2c2e", + "firefox-container-589": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", + "firefox-container-590": "32cc4a9b-05ed-4e54-8e11-732468de62f4", + "firefox-container-591": "9ff381e3-4c11-420d-8e12-e352a3318be1", + "firefox-container-592": "3dc916fb-8c0a-4538-9758-73ef819a45f7", + "firefox-container-593": "63e5212f-0858-418e-b5a3-09c2dea61fcd" + }, + "assignedSites": { + "siteContainerMap@@_developer.mozilla.org": { + "userContextId": "588", + "neverAsk": true, + "hostname": "developer.mozilla.org" + }, + "siteContainerMap@@_reddit.com": { + "userContextId": "592", + "neverAsk": true, + "hostname": "reddit.com" + }, + "siteContainerMap@@_twitter.com": { + "userContextId": "589", + "neverAsk": true, + "hostname": "twitter.com" + }, + "siteContainerMap@@_www.facebook.com": { + "userContextId": "590", + "neverAsk": true, + "hostname": "www.facebook.com" + }, + "siteContainerMap@@_www.linkedin.com": { + "userContextId": "591", + "neverAsk": true, + "hostname": "www.linkedin.com" + } + } +}; + +const DUPE_TEST_LOCAL = { + "beenSynced": true, + "browserActionBadgesClicked": [ + "6.1.1" + ], + "containerTabsOpened": 7, + "identitiesState@@_firefox-default": { + "hiddenTabs": [] + }, + "onboarding-stage": 5, +}; + +const DUPE_TEST_ASSIGNMENTS = [ + "siteContainerMap@@_developer.mozilla.org", + "siteContainerMap@@_reddit.com", + "siteContainerMap@@_twitter.com", + "siteContainerMap@@_www.facebook.com", + "siteContainerMap@@_www.linkedin.com" +]; + +const DUPE_TEST_IDENTS = [ + { + "name": "Personal", + "icon": "fingerprint", + "color": "blue", + }, + { + "name": "Banking", + "icon": "pet", + "color": "green", + }, + { + "name": "Mozilla", + "icon": "briefcase", + "color": "red", + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "color": "orange", + }, + { + "name": "Facebook", + "icon": "fence", + "color": "toolbar", + }, + { + "name": "Big Bird", + "icon": "dollar", + "color": "yellow", + } +]; browser.resetMAC3 = async function () { // for debugging and testing: remove all containers except the default 4 and the first one created browser.tests.stopSyncListeners(); From 6184dbb65600f64b2aa5c67bd72a6191f825dd9b Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 9 Jan 2020 13:52:40 -0600 Subject: [PATCH 29/60] fixed bug that was showing all assigned site in the create new container panel --- src/js/background/sync.js | 154 ++++++-------------------------------- src/js/background/test.js | 22 +----- 2 files changed, 27 insertions(+), 149 deletions(-) diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 2905e53..683471e 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -37,11 +37,9 @@ const sync = { }, async backup(options) { - if (SYNC_DEBUG) console.log("backup"); // remove listeners to avoid an infinite loop! await browser.storage.onChanged.removeListener( sync.storageArea.onChangedListener); - await removeContextualIdentityListeners(); await updateSyncIdentities(); @@ -55,10 +53,10 @@ const sync = { await removeFromDeletedSitesList(options.undelete); if (SYNC_DEBUG) { const storage = await sync.storageArea.get(); - console.log("in sync: ", storage); + console.log("inSync: ", storage); const localStorage = await browser.storage.local.get(); console.log("inLocal:", localStorage); - console.log("indents: ", await browser.contextualIdentities.query({})); + console.log("idents: ", await browser.contextualIdentities.query({})); } browser.storage.onChanged.addListener( sync.storageArea.onChangedListener); @@ -139,7 +137,7 @@ const sync = { }, onChangedListener(changes, areaName) { - if (areaName === "sync") runSync(); + if (areaName === "sync") sync.runSync(); }, async addToDeletedList(changeInfo) { @@ -154,54 +152,42 @@ const sync = { }, init() { - const errorHandledInitSync = () => { - this.initSync().catch((error)=> { - console.error("Error from initSync", error); + const errorHandledRunSync = () => { + this.runSync().catch((error)=> { + console.error("Error from runSync", error); }); }; - browser.runtime.onInstalled.addListener(errorHandledInitSync); - browser.runtime.onStartup.addListener(errorHandledInitSync); + browser.runtime.onInstalled.addListener(errorHandledRunSync); + browser.runtime.onStartup.addListener(errorHandledRunSync); }, - async initSync() { - const syncInfo = await sync.storageArea.get(); - const localInfo = await browser.storage.local.get(); + async runSync() { if (SYNC_DEBUG) { + const syncInfo = await sync.storageArea.get(); + const localInfo = await browser.storage.local.get(); console.log("inSync: ", syncInfo); console.log("inLocal: ", localInfo); console.log("indents: ", await browser.contextualIdentities.query({})); } - const beenSynced = await assignManager.storageArea.getSynced(); - if (beenSynced){ - await runSync(); + browser.storage.onChanged.removeListener( + sync.storageArea.onChangedListener); + removeContextualIdentityListeners(); + console.log("runSync"); + await identityState.storageArea.cleanup(); + + if (await sync.storageArea.hasSyncStorage()){ + await sync.storageArea.cleanup(); + console.log("storage found, attempting to restore ..."); + await restore(); return; } - await runFirstSync(); - }, + console.log("no sync storage, backing up..."); + await sync.storageArea.backup(); + return; }, }; sync.init(); - -async function runSync() { - browser.storage.onChanged.removeListener( - sync.storageArea.onChangedListener); - removeContextualIdentityListeners(); - console.log("runSync"); - await identityState.storageArea.cleanup(); - - - if (await sync.storageArea.hasSyncStorage()){ - await sync.storageArea.cleanup(); - console.log("storage found, attempting to restore ..."); - await restore(); - return; - } - console.log("no sync storage, backing up..."); - await sync.storageArea.backup(); - return; -} - async function restore() { console.log("restore"); await reconcileIdentities(); @@ -209,30 +195,6 @@ async function restore() { await sync.storageArea.backup(); } -async function runFirstSync() { - console.log("runFirstSync"); - // looks for abandoned identities keys in local storage, and identities - // not in localstorage (which also adds a uuid) - await identityState.storageArea.cleanup(); - - if (await sync.storageArea.hasSyncStorage()){ - await sync.storageArea.cleanup(); - console.log("storage found, attempting to restore ..."); - await restoreFirstRun(); - }else { - console.log("no sync storage, backing up..."); - await sync.storageArea.backup(); - } - await assignManager.storageArea.setSynced(); -} - -async function restoreFirstRun() { - console.log("restoreFirstRun"); - await reconcileIdentities(); - await reconcileSiteAssignments(); - await sync.storageArea.backup(); -} - /* * Checks for the container name. If it exists, they are assumed to be the * same container, and the color and icon are overwritten from sync, if @@ -421,74 +383,6 @@ async function setAssignmentWithUUID (newUUID, assignedSite, urlKey) { throw new Error (`No cookieStoreId found for: ${newUUID}, ${urlKey}`); } -/* - * Matches uuids in sync to uuids locally, and updates containers accordingly. - * If there is no match, it creates the new container. - */ -async function reconcileIdentitiesByUUID() { - console.log("reconcileIdentitiesByUUID"); - const syncIdentities = await sync.storageArea.getStoredObject("identities"); - const cookieStoreIDmap = - await sync.storageArea.getStoredObject("cookieStoreIDmap"); - - const deletedIdentityList = - await sync.storageArea.getStoredArray("deletedIdentityList"); - // first remove any deleted identities - for (const deletedUUID of deletedIdentityList) { - const deletedCookieStoreId = - await identityState.lookupCookieStoreId(deletedUUID); - if (deletedCookieStoreId){ - await browser.contextualIdentities.remove(deletedCookieStoreId); - } - } - - // Lookup all identities in teh cookieStoreIDmap and make sure they - // exist locally - for (const syncCookieStoreID of Object.keys(cookieStoreIDmap)) { - const syncUUID = cookieStoreIDmap[syncCookieStoreID]; - //find localCookiesStoreID by looking up the syncUUID - const localCookieStoreID = - await identityState.lookupCookieStoreId(syncUUID); - // get correct indentity info from sync - const identityInfo = - findIdentityFromSync(syncCookieStoreID, syncIdentities); - if (localCookieStoreID) { - if (SYNC_DEBUG) { - const getIdent = - await browser.contextualIdentities.get(localCookieStoreID); - if (getIdent.name !== identityInfo.name) { - console.log(getIdent.name, "Change name: ", identityInfo.name); - } - if (getIdent.color !== identityInfo.color) { - console.log(getIdent.name, "Change color: ", identityInfo.color); - } - if (getIdent.icon !== identityInfo.icon) { - console.log(getIdent.name, "Change icon: ", identityInfo.icon); - } - } - - // update the local container with the sync data - await browser.contextualIdentities - .update(localCookieStoreID, identityInfo); - continue; - } - //not found, create new with same UUID - console.log("new Identity: ", identityInfo.name); - const newIdentity = - await browser.contextualIdentities.create(identityInfo); - await identityState.updateUUID(newIdentity.cookieStoreId, syncUUID); - } - return; -} - -function findIdentityFromSync(cookieStoreId, identitiesList){ - for (const identity of identitiesList) { - const { name, color, icon } = identity; - if (identity.cookieStoreId === cookieStoreId) - return { name, color, icon }; - } -} - const syncCIListenerList = [ sync.storageArea.backup, sync.storageArea.addToDeletedList, diff --git a/src/js/background/test.js b/src/js/background/test.js index d6bba42..b1d19b1 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -12,22 +12,6 @@ browser.tests = { await this.setState({}, LOCAL_DATA, TEST_CONTAINERS); - // await this.removeAllContainers(); - // const localData = { - // "browserActionBadgesClicked": [ "6.1.1" ], - // "containerTabsOpened": 7, - // "identitiesState@@_firefox-default": { "hiddenTabs": [] }, - // "onboarding-stage": 5, - // "identitiesState@@_firefox-container-7": { "hiddenTabs": [] } - // }; - // await browser.storage.local.clear(); - // await browser.storage.local.set(localData); - // // async function assignIdentities () { - // for (const containerInputSet of TEST_CONTAINERS) { - // await browser.contextualIdentities.create(containerInputSet); - // } - // } - // await assignIdentities(); await identityState.storageArea.cleanup(); const macConfigs = await browser.storage.local.get(); @@ -50,7 +34,7 @@ browser.tests = { await this.setState({}, LOCAL_DATA, TEST_CONTAINERS); - await sync.initSync(); + await sync.runSync(); const getSync = await browser.storage.sync.get(); const getAssignedSites = @@ -87,7 +71,7 @@ browser.tests = { await this.setState(SYNC_DATA, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); - await sync.initSync(); + await sync.runSync(); const getSync = await browser.storage.sync.get(); const getAssignedSites = @@ -131,7 +115,7 @@ browser.tests = { DUPE_TEST_ASSIGNMENTS ); - await sync.initSync(); + await sync.runSync(); const getSync = await browser.storage.sync.get(); const getAssignedSites = From 9de6df6157ad555f1deda28a4fc02fdc3dcdc75f Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 9 Jan 2020 13:56:14 -0600 Subject: [PATCH 30/60] fixed bug that was showing all assigned site in the create new container panel --- src/js/background/assignManager.js | 10 ------- src/js/background/sync.js | 43 +++++++++++++++++++----------- src/js/popup.js | 12 ++++++--- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 7098f62..2f4656e 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -9,16 +9,6 @@ const assignManager = { area: browser.storage.local, exemptedTabs: {}, - async getSynced() { - const beenSynced = await this.area.get("beenSynced"); - if (Object.entries(beenSynced).length === 0) return false; - return true; - }, - - setSynced() { - this.area.set({beenSynced: true}); - }, - getSiteStoreKey(pageUrl) { const url = new window.URL(pageUrl); const storagePrefix = "siteContainerMap@@_"; diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 683471e..dbb8f11 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -12,22 +12,35 @@ const sync = { return await this.area.set(options); }, - async getStoredArray(objectKey) { - const storedArray = await this.getStoredItem(objectKey); + async getDeletedIdentityList() { + const storedArray = await this.getStoredItem("deletedIdentityList"); return (storedArray) ? storedArray : []; }, - async getStoredObject(objectKey) { - const storedObject = await this.getStoredItem(objectKey); - return (storedObject) ? storedObject : {}; + async getIdentities() { + const storedArray = await this.getStoredItem("identities"); + return (storedArray) ? storedArray : []; + }, + + async getDeletedSiteList() { + const storedArray = await this.getStoredItem("deletedSiteList"); + return (storedArray) ? storedArray : []; + }, + + async getCookieStoreIDMap() { + const storedArray = await this.getStoredItem("cookieStoreIDmap"); + return (storedArray) ? storedArray : {}; + }, + + async getAssignedSites() { + const storedArray = await this.getStoredItem("assignedSites"); + return (storedArray) ? storedArray : {}; }, async getStoredItem(objectKey) { const outputObject = await this.get(objectKey); if (outputObject && outputObject[objectKey]) return outputObject[objectKey]; - if (SYNC_DEBUG) - console.warn(objectKey, " was requested and is not available."); return false; }, @@ -118,9 +131,9 @@ const sync = { browser.storage.onChanged.removeListener( sync.storageArea.onChangedListener); const identitiesList = - await sync.storageArea.getStoredObject("identities"); + await sync.storageArea.getIdentities(); const cookieStoreIDmap = - await sync.storageArea.getStoredObject("cookieStoreIDmap"); + await sync.storageArea.getCookieStoreIDMap(); for(const cookieStoreId of Object.keys(cookieStoreIDmap)) { const match = identitiesList .find(syncIdentity => @@ -205,7 +218,7 @@ async function reconcileIdentities(){ // first delete any from the deleted list const deletedIdentityList = - await sync.storageArea.getStoredArray("deletedIdentityList"); + await sync.storageArea.getDeletedIdentityList(); // first remove any deleted identities for (const deletedUUID of deletedIdentityList) { const deletedCookieStoreId = @@ -217,9 +230,9 @@ async function reconcileIdentities(){ const localIdentities = await browser.contextualIdentities.query({}); const syncIdentities = - await sync.storageArea.getStoredArray("identities"); + await sync.storageArea.getIdentities(); const cookieStoreIDmap = - await sync.storageArea.getStoredObject("cookieStoreIDmap"); + await sync.storageArea.getCookieStoreIDMap(); // now compare all containers for matching names. for (const syncIdentity of syncIdentities) { syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; @@ -323,9 +336,9 @@ async function reconcileSiteAssignments() { const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); const assignedSitesFromSync = - await sync.storageArea.getStoredObject("assignedSites"); + await sync.storageArea.getAssignedSites(); const deletedSiteList = - await sync.storageArea.getStoredArray("deletedSiteList"); + await sync.storageArea.getDeletedSiteList(); for(const siteStoreKey of deletedSiteList) { if (assignedSitesLocal.hasOwnProperty(siteStoreKey)) { assignManager @@ -334,7 +347,7 @@ async function reconcileSiteAssignments() { } } const cookieStoreIDmap = - await sync.storageArea.getStoredObject("cookieStoreIDmap"); + await sync.storageArea.getCookieStoreIDMap(); for(const urlKey of Object.keys(assignedSitesFromSync)) { const assignedSite = assignedSitesFromSync[urlKey]; diff --git a/src/js/popup.js b/src/js/popup.js index 64dca45..b539816 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -352,10 +352,13 @@ const Logic = { }, getAssignmentObjectByContainer(userContextId) { - return browser.runtime.sendMessage({ - method: "getAssignmentObjectByContainer", - message: { userContextId } - }); + if (userContextId) { + return browser.runtime.sendMessage({ + method: "getAssignmentObjectByContainer", + message: { userContextId } + }); + } + return {}; }, setOrRemoveAssignment(tabId, url, userContextId, value) { @@ -1022,6 +1025,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { while (tableElement.firstChild) { tableElement.firstChild.remove(); } + assignmentKeys.forEach((siteKey) => { const site = assignments[siteKey]; const trElement = document.createElement("div"); From 5ae7a395a174ca2d3a4a285e9d22b2a7b5f2b5a7 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 9 Jan 2020 16:36:26 -0600 Subject: [PATCH 31/60] added some checks on sync and some error handling for bad site assignment info --- src/js/background/assignManager.js | 25 +++ src/js/background/sync.js | 242 +++++++++++++++++------------ src/js/background/test.js | 173 +++++++++++++-------- src/js/popup.js | 8 +- 4 files changed, 285 insertions(+), 163 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 2f4656e..096ebf1 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -107,6 +107,31 @@ const assignManager = { } return sites; }, + + /* + * Looks for abandoned site assignments. If there is no identity with + * the site assignment's userContextId (cookieStoreId), then the assignment + * is removed. + */ + async cleanup() { + const identitiesList = await browser.contextualIdentities.query({}); + const macConfigs = await this.area.get(); + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("siteContainerMap@@_")) { + const cookieStoreId = + "firefox-container-" + macConfigs[configKey].userContextId; + const match = identitiesList.find( + localIdentity => localIdentity.cookieStoreId === cookieStoreId + ); + if (!match) { + await this.remove(configKey.replace(/^siteContainerMap@@_/, "https://")); + continue; + } + } + } + + } + }, _neverAsk(m) { diff --git a/src/js/background/sync.js b/src/js/background/sync.js index dbb8f11..b56a634 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -51,9 +51,7 @@ const sync = { async backup(options) { // remove listeners to avoid an infinite loop! - await browser.storage.onChanged.removeListener( - sync.storageArea.onChangedListener); - await removeContextualIdentityListeners(); + await sync.checkForListenersMaybeRemove(); await updateSyncIdentities(); await updateCookieStoreIdMap(); @@ -71,9 +69,8 @@ const sync = { console.log("inLocal:", localStorage); console.log("idents: ", await browser.contextualIdentities.query({})); } - browser.storage.onChanged.addListener( - sync.storageArea.onChangedListener); - addContextualIdentityListeners(); + + await sync.checkForListenersMaybeAdd(); async function updateSyncIdentities() { const identities = await browser.contextualIdentities.query({}); @@ -93,9 +90,8 @@ const sync = { } async function updateDeletedIdentityList(deletedIdentityUUID) { - let { deletedIdentityList } = - await sync.storageArea.get("deletedIdentityList"); - if (!deletedIdentityList) deletedIdentityList = []; + const deletedIdentityList = + await sync.storageArea.getDeletedIdentityList(); if ( deletedIdentityList.find(element => element === deletedIdentityUUID) ) return; @@ -104,74 +100,91 @@ const sync = { } async function addToDeletedSitesList(siteStoreKey) { - let { deletedSiteList } = - await sync.storageArea.get("deletedSiteList"); - if (!deletedSiteList) deletedSiteList = []; + const deletedSiteList = + await sync.storageArea.getDeletedSiteList(); if (deletedSiteList.find(element => element === siteStoreKey)) return; deletedSiteList.push(siteStoreKey); await sync.storageArea.set({ deletedSiteList }); } async function removeFromDeletedSitesList(siteStoreKey) { - let { deletedSiteList } = - await sync.storageArea.get("deletedSiteList"); - if (!deletedSiteList) return; - deletedSiteList = deletedSiteList + const deletedSiteList = + await sync.storageArea.getDeletedSiteList(); + const newDeletedSiteList = deletedSiteList .filter(element => element !== siteStoreKey); - await sync.storageArea.set({ deletedSiteList }); + await sync.storageArea.set({ deletedSiteList: newDeletedSiteList }); } }, - /* - * Ensures all sync info matches. But maybe we shouldn't even use - * sync info that doesn't match. - */ - async cleanup() { - console.log("cleanupSync"); - browser.storage.onChanged.removeListener( - sync.storageArea.onChangedListener); - const identitiesList = - await sync.storageArea.getIdentities(); - const cookieStoreIDmap = - await sync.storageArea.getCookieStoreIDMap(); - for(const cookieStoreId of Object.keys(cookieStoreIDmap)) { - const match = identitiesList - .find(syncIdentity => - syncIdentity.cookieStoreId === cookieStoreId - ); - if (!match) { - delete cookieStoreIDmap[cookieStoreId]; - await sync.storageArea.set({ cookieStoreIDmap }); - console.log("removed ", cookieStoreId, " from sync list"); - } - } - await browser.storage.onChanged.addListener( - sync.storageArea.onChangedListener); - }, - onChangedListener(changes, areaName) { - if (areaName === "sync") sync.runSync(); + if (areaName === "sync") sync.errorHandledRunSync(); }, async addToDeletedList(changeInfo) { const identity = changeInfo.contextualIdentity; - console.log("addToDeletedList", identity.cookieStoreId); const deletedUUID = await identityState.lookupMACaddonUUID(identity.cookieStoreId); await identityState.storageArea.remove(identity.cookieStoreId); - console.log(deletedUUID); sync.storageArea.backup({uuid: deletedUUID}); + }, + + async checkSyncForMismatches() { + const cookieStoreIDmap = await this.getCookieStoreIDMap(); + const identities = await this.getIdentities(); + for (const cookieStoreId of Object.keys(cookieStoreIDmap)) { + const match = identities.find(identity => + identity.cookieStoreId === cookieStoreId + ); + if (!match) return false; + // if one has no match, this is bad data. + console.log("Bad Data, skipping"); + } + return !(Object.entries(cookieStoreIDmap).length === 0); } }, init() { - const errorHandledRunSync = () => { - this.runSync().catch((error)=> { - console.error("Error from runSync", error); - }); - }; - browser.runtime.onInstalled.addListener(errorHandledRunSync); - browser.runtime.onStartup.addListener(errorHandledRunSync); + browser.runtime.onInstalled.addListener(this.errorHandledRunSync); + browser.runtime.onStartup.addListener(this.errorHandledRunSync); + }, + + async errorHandledRunSync () { + sync.runSync().catch(async (error)=> { + console.error("Error from runSync", error); + sync.checkForListenersMaybeAdd(); + }); + }, + + async checkForListenersMaybeAdd() { + const hasStorageListener = + await browser.storage.onChanged.hasListener( + sync.storageArea.onChangedListener + ); + + if (! await hasContextualIdentityListeners()) { + addContextualIdentityListeners(); + } + + if (! hasStorageListener) { + browser.storage.onChanged.addListener( + sync.storageArea.onChangedListener); + } + }, + + async checkForListenersMaybeRemove() { + const hasStorageListener = + await browser.storage.onChanged.hasListener( + sync.storageArea.onChangedListener + ); + + if (await hasContextualIdentityListeners()) { + removeContextualIdentityListeners(); + } + + if (hasStorageListener) { + browser.storage.onChanged.removeListener( + sync.storageArea.onChangedListener); + } }, async runSync() { @@ -182,21 +195,19 @@ const sync = { console.log("inLocal: ", localInfo); console.log("indents: ", await browser.contextualIdentities.query({})); } - browser.storage.onChanged.removeListener( - sync.storageArea.onChangedListener); - removeContextualIdentityListeners(); + await sync.checkForListenersMaybeRemove(); console.log("runSync"); - await identityState.storageArea.cleanup(); - if (await sync.storageArea.hasSyncStorage()){ - await sync.storageArea.cleanup(); - console.log("storage found, attempting to restore ..."); - await restore(); - return; - } - console.log("no sync storage, backing up..."); + await identityState.storageArea.cleanup(); + await assignManager.storageArea.cleanup(); + + const hasSyncStorage = await sync.storageArea.hasSyncStorage(); + const dataIsReliable = await sync.storageArea.checkSyncForMismatches(); + if (hasSyncStorage && dataIsReliable) await restore(); + await sync.storageArea.backup(); - return; }, + return; + }, }; sync.init(); @@ -205,7 +216,7 @@ async function restore() { console.log("restore"); await reconcileIdentities(); await reconcileSiteAssignments(); - await sync.storageArea.backup(); + return; } /* @@ -224,7 +235,13 @@ async function reconcileIdentities(){ const deletedCookieStoreId = await identityState.lookupCookieStoreId(deletedUUID); if (deletedCookieStoreId){ - await browser.contextualIdentities.remove(deletedCookieStoreId); + try{ + await browser.contextualIdentities.remove(deletedCookieStoreId); + } catch (error) { + // if the identity we are deleting is not there, that's fine. + console.error("Error deleting contextualIdentity", deletedCookieStoreId); + continue; + } } } @@ -291,23 +308,32 @@ async function ifUUIDMatch(syncIdentity, localCookieStoreID) { icon: syncIdentity.icon }; if (SYNC_DEBUG) { - const getIdent = + try { + const getIdent = await browser.contextualIdentities.get(localCookieStoreID); - if (getIdent.name !== identityInfo.name) { - console.log(getIdent.name, "Change name: ", identityInfo.name); - } - if (getIdent.color !== identityInfo.color) { - console.log(getIdent.name, "Change color: ", identityInfo.color); - } - if (getIdent.icon !== identityInfo.icon) { - console.log(getIdent.name, "Change icon: ", identityInfo.icon); + if (getIdent.name !== identityInfo.name) { + console.log(getIdent.name, "Change name: ", identityInfo.name); + } + if (getIdent.color !== identityInfo.color) { + console.log(getIdent.name, "Change color: ", identityInfo.color); + } + if (getIdent.icon !== identityInfo.icon) { + console.log(getIdent.name, "Change icon: ", identityInfo.icon); + } + } catch (error) { + //if this fails, there is probably differing sync info. + console.error("Error getting info on CI", error); } } - + try { // update the local container with the sync data - await browser.contextualIdentities - .update(localCookieStoreID, identityInfo); - return; + await browser.contextualIdentities + .update(localCookieStoreID, identityInfo); + return; + } catch (error) { + // If this fails, sync info is off. + console.error("Error udpating CI", error); + } } async function ifNoMatch(syncIdentity){ @@ -351,34 +377,43 @@ async function reconcileSiteAssignments() { for(const urlKey of Object.keys(assignedSitesFromSync)) { const assignedSite = assignedSitesFromSync[urlKey]; - const syncUUID = - await lookupSyncSiteAssigmentIdentityUUID( - assignedSite, cookieStoreIDmap, urlKey - ); - if (syncUUID) { + try{ + const syncUUID = + await lookupSyncSiteAssigmentIdentityUUID( + assignedSite, cookieStoreIDmap, urlKey + ); + if (syncUUID) { // Sync is truth. // Not even looking it up. Just overwrite - console.log("new assignment ", assignedSite, ": ", - assignedSite.userContextId); - const newUUID = cookieStoreIDmap[ - "firefox-container-" + assignedSite.userContextId - ]; - await setAssignmentWithUUID(newUUID, assignedSite, urlKey); - continue; - } + console.log("new assignment ", assignedSite, ": ", + assignedSite.userContextId); + const newUUID = cookieStoreIDmap[ + "firefox-container-" + assignedSite.userContextId + ]; - // if there's no syncUUID, something is wrong, since these site - // assignments are from sync - throw new Error("Sync storage not aligned"); + await setAssignmentWithUUID(newUUID, assignedSite, urlKey); + + continue; + } + + } catch (error) { + // this is probably old or incorrect site info in Sync + // skip and move on. + //console.error("Error assigning site", error); + + } } async function lookupSyncSiteAssigmentIdentityUUID( assignedSite, cookieStoreIDmap, + urlKey ){ const syncCookieStoreId = "firefox-container-" + assignedSite.userContextId; - return cookieStoreIDmap[syncCookieStoreId]; + const uuid = cookieStoreIDmap[syncCookieStoreId]; + if (!uuid) throw new Error (`No syncUUID found for : ${urlKey}`); + return uuid; } } @@ -414,4 +449,13 @@ function removeContextualIdentityListeners(listenerList) { browser.contextualIdentities.onCreated.removeListener(listenerList[0]); browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); -} \ No newline at end of file +} + +async function hasContextualIdentityListeners(listenerList) { + if(!listenerList) listenerList = syncCIListenerList; + return ( + await browser.contextualIdentities.onCreated.hasListener(listenerList[0]) && + await browser.contextualIdentities.onRemoved.hasListener(listenerList[1]) && + await browser.contextualIdentities.onUpdated.hasListener(listenerList[2]) + ); +} diff --git a/src/js/background/test.js b/src/js/background/test.js index b1d19b1..bc05fbe 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -1,16 +1,32 @@ browser.tests = { async runAll() { await this.testIdentityStateCleanup(); - await this.test1(); + await this.testReconcileSiteAssignments(); + await this.testInitialSync(); await this.test2(); await this.dupeTest(); }, + // more unit tests + // if site assignment has no valid cookieStoreId, delete on local + + async resetForManualTests() { + await browser.tests.stopSyncListeners(); + console.log("reset"); + await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); + }, async testIdentityStateCleanup() { await browser.tests.stopSyncListeners(); console.log("Testing the cleanup of local storage"); - await this.setState({}, LOCAL_DATA, TEST_CONTAINERS); + await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); + + await browser.storage.local.set({ + "identitiesState@@_firefox-container-5": { + "hiddenTabs": [] + } + }); + console.log("local storage set: ", await browser.storage.local.get()); await identityState.storageArea.cleanup(); @@ -28,11 +44,76 @@ browser.tests = { } console.log("Finished!"); }, - async test1() { + + async testAssignManagerCleanup() { + await browser.tests.stopSyncListeners(); + console.log("Testing the cleanup of local storage"); + + await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); + + await browser.storage.local.set({ + "siteContainerMap@@_www.goop.com": { + "userContextId": "5", + "neverAsk": true, + "hostname": "www.goop.com" + } + }); + console.log("local storage set: ", await browser.storage.local.get()); + + await assignManager.storageArea.cleanup(); + + await browser.storage.local.set({ + "identitiesState@@_firefox-container-5": { + "hiddenTabs": [] + } + }); + + const macConfigs = await browser.storage.local.get(); + const assignments = []; + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("siteContainerMap@@_")) { + assignments.push(configKey); + } + } + + console.assert(assignments.length === 0, "There should be 0 identity entries"); + + console.log("Finished!"); + }, + + async testReconcileSiteAssignments() { + await browser.tests.stopSyncListeners(); + console.log("Testing reconciling Site Assignments"); + + const newSyncData = DUPE_TEST_SYNC; + // add some bad data. + newSyncData.assignedSites["siteContainerMap@@_www.linkedin.com"] = { + "userContextId": "1", + "neverAsk": true, + "hostname": "www.linkedin.com" + }; + + newSyncData.deletedSiteList = ["siteContainerMap@@_www.google.com"]; + + await this.setState( + newSyncData, + LOCAL_DATA, + TEST_CONTAINERS, + SITE_ASSIGNMENT_TEST + ); + + await sync.runSync(); + + const assignedSites = await assignManager.storageArea.getAssignedSites(); + console.assert(Object.keys(assignedSites).length === 5, "There should be 5 assigned sites"); + console.log("Finished!"); + }, + + async testInitialSync() { await browser.tests.stopSyncListeners(); console.log("Testing new install with no sync"); - await this.setState({}, LOCAL_DATA, TEST_CONTAINERS); + await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); await sync.runSync(); @@ -106,7 +187,7 @@ browser.tests = { async dupeTest() { await browser.tests.stopSyncListeners(); - console.log("Test state from duped sync"); + console.log("Test state from sync that duped everything initially"); await this.setState( DUPE_TEST_SYNC, @@ -176,30 +257,42 @@ browser.tests = { } return false; }, - async setState(syncData, localData, indentityData, assignmentData){ + + /* + * Sets the state of sync storage, local storage, and the identities. + * SyncDat and localData (without identities or site assignments) get + * set to sync and local storage respectively. IdentityData creates + * new identities (after all have been removed), and assignmentData + * is used along with the new identities' cookieStoreIds to create + * site assignments in local storage. + */ + async setState(syncData, localData, identityData, assignmentData){ await this.removeAllContainers(); await browser.storage.sync.clear(); await browser.storage.sync.set(syncData); await browser.storage.local.clear(); - for (let i=0; i < indentityData.length; i++) { + await browser.storage.local.set(localData); + for (let i=0; i < identityData.length; i++) { //build identities const newIdentity = - await browser.contextualIdentities.create(indentityData[i]); + await browser.contextualIdentities.create(identityData[i]); // fill identies with site assignments if (assignmentData && assignmentData[i]) { - localData[assignmentData[i]] = { + const data = { "userContextId": String( newIdentity.cookieStoreId.replace(/^firefox-container-/, "") ), "neverAsk": true }; + + await browser.storage.local.set({[assignmentData[i]]: data}); } } - await browser.storage.local.set(localData); console.log("local storage set: ", await browser.storage.local.get()); return; }, + async removeAllContainers() { const identities = await browser.contextualIdentities.query({}); for (const identity of identities) { @@ -254,6 +347,7 @@ const TEST_ASSIGNMENTS = [ "siteContainerMap@@_www.linkedin.com", "siteContainerMap@@_reddit.com" ]; + const LOCAL_DATA = { "browserActionBadgesClicked": [ "6.1.1" ], "containerTabsOpened": 7, @@ -313,23 +407,6 @@ const SYNC_DATA = { }, "assignedSites": {} }; -browser.resetMAC2 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.tests.stopSyncListeners(); - - // sync state after FF1 (default + 1) - await browser.storage.sync.clear(); - const syncData = {"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26"},"assignedSites":{"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"}]}; - browser.storage.sync.set(syncData); - - // FF2 (intial sync w/ default 4 + 1 with some changes) - browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); - browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); - browser.storage.local.clear(); - const localData = {"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[]},"identitiesState@@_firefox-container-2":{"hiddenTabs":[]},"identitiesState@@_firefox-container-3":{"hiddenTabs":[]},"identitiesState@@_firefox-container-4":{"hiddenTabs":[]},"identitiesState@@_firefox-container-6":{"hiddenTabs":[]},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - -}; const DUPE_TEST_SYNC = { "identities": [ @@ -439,6 +516,13 @@ const DUPE_TEST_ASSIGNMENTS = [ "siteContainerMap@@_www.linkedin.com" ]; +const SITE_ASSIGNMENT_TEST = [ + "siteContainerMap@@_developer.mozilla.org", + "siteContainerMap@@_www.facebook.com", + "siteContainerMap@@_www.google.com", + "siteContainerMap@@_bugzilla.mozilla.org" +]; + const DUPE_TEST_IDENTS = [ { "name": "Personal", @@ -471,38 +555,3 @@ const DUPE_TEST_IDENTS = [ "color": "yellow", } ]; -browser.resetMAC3 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.tests.stopSyncListeners(); - - // sync state after FF2 synced - await browser.storage.sync.clear(); - const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; - browser.storage.sync.set(syncData); - - // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) - browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); - //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); - browser.storage.local.clear(); - const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - -}; - -browser.resetMAC4 = async function () { - // for debugging and testing: remove all containers except the default 4 and the first one created - browser.tests.stopSyncListeners(); - - // sync state after FF2 synced - await browser.storage.sync.clear(); - const syncData = {"assignedSites":{"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1,"hostname":"developer.mozilla.org"},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0,"hostname":"twitter.com"},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0,"hostname":"www.facebook.com"},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1,"hostname":"www.linkedin.com"},"siteContainerMap@@_reddit.com": {"userContextId": "7","neverAsk": true}},"cookieStoreIDmap":{"firefox-container-1":"4dc76734-5b71-4f2e-85d0-1cb199ae3821","firefox-container-2":"30308b8d-393c-4375-b9a1-afc59f0dea79","firefox-container-3":"7419c94d-85d7-4d76-94c0-bacef1de722f","firefox-container-4":"2b9fe881-e552-4df9-8cab-922f4688bb68","firefox-container-6":"db7f622e-682b-4556-968a-6e2542ff3b26","firefox-container-7":"ceb06672-76c0-48c4-959e-f3a3ee8358b6"},"identities":[{"name":"Personal","icon":"fingerprint","iconUrl":"resource://usercontext-content/fingerprint.svg","color":"blue","colorCode":"#37adff","cookieStoreId":"firefox-container-1"},{"name":"Work","icon":"briefcase","iconUrl":"resource://usercontext-content/briefcase.svg","color":"orange","colorCode":"#ff9f00","cookieStoreId":"firefox-container-2"},{"name":"Banking","icon":"dollar","iconUrl":"resource://usercontext-content/dollar.svg","color":"purple","colorCode":"#af51f5","cookieStoreId":"firefox-container-3"},{"name":"Shopping","icon":"cart","iconUrl":"resource://usercontext-content/cart.svg","color":"pink","colorCode":"#ff4bda","cookieStoreId":"firefox-container-4"},{"name":"Container #01","icon":"chill","iconUrl":"resource://usercontext-content/chill.svg","color":"green","colorCode":"#51cd00","cookieStoreId":"firefox-container-6"},{"name":"Container #02","icon":"vacation","iconUrl":"resource://usercontext-content/vacation.svg","color":"yellow","colorCode":"#ffcb00","cookieStoreId":"firefox-container-7"}]}; - browser.storage.sync.set(syncData); - - // FF1 with updates from FF2 (intial sync w/ default 4 + 1 with some changes) - browser.contextualIdentities.update("firefox-container-3", {color:"purple", icon:"fruit"}); - //browser.contextualIdentities.create({name: "Container #02", icon: "vacation", color: "yellow"}); - browser.storage.local.clear(); - const localData = {"beenSynced":!0,"browserActionBadgesClicked":["6.1.1"],"containerTabsOpened":7,"identitiesState@@_firefox-container-1":{"hiddenTabs":[],"macAddonUUID":"4dc76734-5b71-4f2e-85d0-1cb199ae3821"},"identitiesState@@_firefox-container-2":{"hiddenTabs":[],"macAddonUUID":"30308b8d-393c-4375-b9a1-afc59f0dea79"},"identitiesState@@_firefox-container-3":{"hiddenTabs":[],"macAddonUUID":"7419c94d-85d7-4d76-94c0-bacef1de722f"},"identitiesState@@_firefox-container-4":{"hiddenTabs":[],"macAddonUUID":"2b9fe881-e552-4df9-8cab-922f4688bb68"},"identitiesState@@_firefox-container-6":{"hiddenTabs":[],"macAddonUUID":"db7f622e-682b-4556-968a-6e2542ff3b26"},"identitiesState@@_firefox-default":{"hiddenTabs":[]},"onboarding-stage":5,"siteContainerMap@@_developer.mozilla.org":{"userContextId":"6","neverAsk":!1},"siteContainerMap@@_twitter.com":{"userContextId":"1","neverAsk":!0},"siteContainerMap@@_www.facebook.com":{"userContextId":"2","neverAsk":!0},"siteContainerMap@@_www.linkedin.com":{"userContextId":"4","neverAsk":!1}}; - browser.storage.local.set(localData); - -}; \ No newline at end of file diff --git a/src/js/popup.js b/src/js/popup.js index b539816..d4ec8c9 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -724,8 +724,12 @@ Logic.registerPanel(P_CONTAINERS_LIST, { however it allows us to have a tabindex before the first selected item */ const focusHandler = () => { - list.querySelector("tr .clickable").focus(); - document.removeEventListener("focus", focusHandler); + const identityList = list.querySelector("tr .clickable"); + if (identityList) { + // otherwise this throws an error when there are no containers present. + identityList.focus(); + document.removeEventListener("focus", focusHandler); + } }; document.addEventListener("focus", focusHandler); /* If the user mousedown's first then remove the focus handler */ From 10d08f2ac9078108da845e9bf9dbf9e12eaa0651 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 10 Jan 2020 15:43:23 -0600 Subject: [PATCH 32/60] changed confusing language on sync data check --- src/js/background/sync.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/js/background/sync.js b/src/js/background/sync.js index b56a634..f12eaed 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -128,16 +128,15 @@ const sync = { sync.storageArea.backup({uuid: deletedUUID}); }, - async checkSyncForMismatches() { + async dataIsReliable() { const cookieStoreIDmap = await this.getCookieStoreIDMap(); const identities = await this.getIdentities(); for (const cookieStoreId of Object.keys(cookieStoreIDmap)) { const match = identities.find(identity => identity.cookieStoreId === cookieStoreId ); - if (!match) return false; // if one has no match, this is bad data. - console.log("Bad Data, skipping"); + if (!match) return false; } return !(Object.entries(cookieStoreIDmap).length === 0); } @@ -202,7 +201,7 @@ const sync = { await assignManager.storageArea.cleanup(); const hasSyncStorage = await sync.storageArea.hasSyncStorage(); - const dataIsReliable = await sync.storageArea.checkSyncForMismatches(); + const dataIsReliable = await sync.storageArea.dataIsReliable(); if (hasSyncStorage && dataIsReliable) await restore(); await sync.storageArea.backup(); From 33909d147a74cc1915c6b41425d178aea7bb3eaf Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 13 Jan 2020 14:16:24 -0600 Subject: [PATCH 33/60] fixed cookiestoreIDmap --- src/js/background/identityState.js | 11 +- src/js/background/sync.js | 61 +++++----- src/js/background/test.js | 187 +++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+), 35 deletions(-) diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index d032790..f4fb282 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -79,13 +79,10 @@ const identityState = { async getCookieStoreIDuuidMap() { const containers = {}; - const containerInfo = await identityState.storageArea.area.get(); - for(const configKey of Object.keys(containerInfo)) { - if (configKey.includes("identitiesState@@_")) { - const container = containerInfo[configKey]; - const cookieStoreId = configKey.replace(/^identitiesState@@_/, ""); - containers[cookieStoreId] = container.macAddonUUID; - } + const identities = await browser.contextualIdentities.query({}); + for(const identity of identities) { + const containerInfo = await this.storageArea.get(identity.cookieStoreId); + containers[identity.cookieStoreId] = containerInfo.macAddonUUID; } return containers; }, diff --git a/src/js/background/sync.js b/src/js/background/sync.js index f12eaed..5a418eb 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -62,14 +62,14 @@ const sync = { await addToDeletedSitesList(options.siteStoreKey); if (options && options.undelete) await removeFromDeletedSitesList(options.undelete); - if (SYNC_DEBUG) { - const storage = await sync.storageArea.get(); - console.log("inSync: ", storage); - const localStorage = await browser.storage.local.get(); - console.log("inLocal:", localStorage); - console.log("idents: ", await browser.contextualIdentities.query({})); - } - + // if (SYNC_DEBUG) { + // const storage = await sync.storageArea.get(); + // console.log("inSync: ", storage); + // const localStorage = await browser.storage.local.get(); + // console.log("inLocal:", localStorage); + // console.log("idents: ", await browser.contextualIdentities.query({})); + // } + console.log("Backed up!"); await sync.checkForListenersMaybeAdd(); async function updateSyncIdentities() { @@ -159,12 +159,14 @@ const sync = { await browser.storage.onChanged.hasListener( sync.storageArea.onChangedListener ); + + const hasCIListener = await hasContextualIdentityListeners(); - if (! await hasContextualIdentityListeners()) { + if (!hasCIListener) { addContextualIdentityListeners(); } - if (! hasStorageListener) { + if (!hasStorageListener) { browser.storage.onChanged.addListener( sync.storageArea.onChangedListener); } @@ -175,8 +177,10 @@ const sync = { await browser.storage.onChanged.hasListener( sync.storageArea.onChangedListener ); - - if (await hasContextualIdentityListeners()) { + + const hasCIListener = await hasContextualIdentityListeners(); + + if (hasCIListener) { removeContextualIdentityListeners(); } @@ -190,9 +194,8 @@ const sync = { if (SYNC_DEBUG) { const syncInfo = await sync.storageArea.get(); const localInfo = await browser.storage.local.get(); - console.log("inSync: ", syncInfo); - console.log("inLocal: ", localInfo); - console.log("indents: ", await browser.contextualIdentities.query({})); + const idents = await browser.contextualIdentities.query({}); + console.log("Initial State:", {syncInfo, localInfo, idents}); } await sync.checkForListenersMaybeRemove(); console.log("runSync"); @@ -252,22 +255,25 @@ async function reconcileIdentities(){ // now compare all containers for matching names. for (const syncIdentity of syncIdentities) { syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; - const localMatch = localIdentities.find( - localIdentity => localIdentity.name === syncIdentity.name - ); - if (!localMatch) { - // if there's no name match found, check on uuid, - const localCookieStoreID = - await identityState.lookupCookieStoreId(syncIdentity.macAddonUUID); - if (localCookieStoreID) { - await ifUUIDMatch(syncIdentity, localCookieStoreID); + if (syncIdentity.macAddonUUID){ + const localMatch = localIdentities.find( + localIdentity => localIdentity.name === syncIdentity.name + ); + if (!localMatch) { + // if there's no name match found, check on uuid, + const localCookieStoreID = + await identityState.lookupCookieStoreId(syncIdentity.macAddonUUID); + if (localCookieStoreID) { + await ifUUIDMatch(syncIdentity, localCookieStoreID); + continue; + } + await ifNoMatch(syncIdentity); continue; } - await ifNoMatch(syncIdentity); + await ifNamesMatch(syncIdentity, localMatch); continue; } - await ifNamesMatch(syncIdentity, localMatch); - continue; + // if no macAddonUUID, there is a problem with the sync info and it needs to be ignored. } } @@ -291,7 +297,6 @@ async function ifNamesMatch(syncIdentity, localMatch) { } } } - // Sync is truth. If all is the same, update the local uuid to match sync await identityState.updateUUID( localMatch.cookieStoreId, diff --git a/src/js/background/test.js b/src/js/background/test.js index bc05fbe..1634f3f 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -243,6 +243,64 @@ browser.tests = { console.log("Finished!"); }, + async CIerrorTest() { + await browser.tests.stopSyncListeners(); + console.log("Test state from sync that duped everything initially"); + + await this.setState( + CI_ERROR_TEST_SYNC, + CI_ERROR_TEST_LOCAL, + CI_ERROR_TEST_IDENTS, + CI_ERROR_TEST_SITES + ); + + await sync.runSync(); + + const getSync = await browser.storage.sync.get(); + const getAssignedSites = + await assignManager.storageArea.getAssignedSites(); + + const identities = await browser.contextualIdentities.query({}); + + const localCookieStoreIDmap = + await identityState.getCookieStoreIDuuidMap(); + + console.assert( + Object.keys(getSync.cookieStoreIDmap).length === 7, + "cookieStoreIDmap should have 7 entries" + ); + + console.assert( + Object.keys(localCookieStoreIDmap).length === 8, + "localCookieStoreIDmap should have 8 entries" + ); + + console.assert( + identities.length === 7, + "There should be 7 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 5, + "There should be 5 site assignments" + ); + + const personalContainer = + this.lookupIdentityBy(identities, {name: "Personal"}); + console.log(personalContainer); + console.assert( + personalContainer.color === "red", + "Personal Container should be red" + ); + const mozillaContainer = + this.lookupIdentityBy(identities, {name: "Mozilla"}); + console.assert( + mozillaContainer.icon === "pet", + "Mozilla Container should be pet" + ); + console.log("Finished!"); + }, + lookupIdentityBy(identities, options) { for (const identity of identities) { if (options && options.name) { @@ -555,3 +613,132 @@ const DUPE_TEST_IDENTS = [ "color": "yellow", } ]; + +const CI_ERROR_TEST_SYNC = { + "identities": [ + { + "name": "Personal", + "icon": "fingerprint", + "iconUrl": "resource://usercontext-content/fingerprint.svg", + "color": "blue", + "colorCode": "#37adff", + "cookieStoreId": "firefox-container-6" + }, + { + "name": "Mozilla", + "icon": "fruit", + "iconUrl": "resource://usercontext-content/fruit.svg", + "color": "purple", + "colorCode": "#af51f5", + "cookieStoreId": "firefox-container-8" + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "iconUrl": "resource://usercontext-content/cart.svg", + "color": "yellow", + "colorCode": "#ffcb00", + "cookieStoreId": "firefox-container-9" + }, + { + "name": "Facebook", + "icon": "circle", + "iconUrl": "resource://usercontext-content/circle.svg", + "color": "blue", + "colorCode": "#37adff", + "cookieStoreId": "firefox-container-10" + }, + { + "name": "Work", + "icon": "briefcase", + "iconUrl": "resource://usercontext-content/briefcase.svg", + "color": "orange", + "colorCode": "#ff9f00", + "cookieStoreId": "firefox-container-11" + }, + { + "name": "Greg's container", + "icon": "vacation", + "iconUrl": "resource://usercontext-content/vacation.svg", + "color": "yellow", + "colorCode": "#ffcb00", + "cookieStoreId": "firefox-container-14" + } + ], + "deletedIdentityList": [ + "8098140e-d406-4321-b4f5-24763b4f9513", + "73aebc7a-286f-408a-9a94-a06d29b288e0", + "8f153224-bbe8-4664-ba02-0293ddec3e78" + ], + "cookieStoreIDmap": { + "firefox-container-10": "58956e95-43fb-44af-95c0-1ec8d83e1e13", + "firefox-container-11": "0269558d-6be7-487b-beb1-b720b346d09b", + "firefox-container-14": "e48d04cf-6277-4236-8f3d-611287d0caf2", + "firefox-container-6": "869a7563-030d-4a63-8a84-209270561d3c", + "firefox-container-8": "73aebc7a-286f-408a-9a94-a06d29b288e0", + "firefox-container-9": "4831fef4-6f43-47fb-a578-ccdc3ee7f883" + }, + "assignedSites": { + "siteContainerMap@@_bugzilla.mozilla.org": { + "userContextId": "11", + "neverAsk": true, + "hostname": "bugzilla.mozilla.org" + }, + "siteContainerMap@@_www.amazon.com": { + "userContextId": "14", + "neverAsk": false, + "hostname": "www.amazon.com" + } + }, + "deletedSiteList": [ + "siteContainerMap@@_www.facebook.com" + ] +}; + +const CI_ERROR_TEST_LOCAL = { + "browserActionBadgesClicked": [ + "6.1.1" + ], + "containerTabsOpened": 6, + "onboarding-stage": 5, +}; + +const CI_ERROR_TEST_SITES = [ + "siteContainerMap@@_bugzilla.mozilla.org", + "siteContainerMap@@_www.bankofoklahoma.com", + "siteContainerMap@@_www.mozilla.org", + "siteContainerMap@@_www.reddit.com" +]; + +const CI_ERROR_TEST_IDENTS = [ + { + "name": "Personal", + "icon": "fingerprint", + "color": "blue", + }, + { + "name": "Work", + "icon": "briefcase", + "color": "orange", + }, + { + "name": "Banking", + "icon": "dollar", + "color": "green", + }, + { + "name": "Mozilla", + "icon": "fruit", + "color": "purple", + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "color": "yellow", + }, + { + "name": "Facebook", + "icon": "circle", + "color": "blue", + } +]; From 26028cac20eb67ebd776fa1a39e92930bafacddc Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 13 Jan 2020 17:27:29 -0600 Subject: [PATCH 34/60] added UUIDs of containers to site assignments --- src/js/background/assignManager.js | 50 ++++--- src/js/background/identityState.js | 11 +- src/js/background/sync.js | 96 ++++++------ src/js/background/test.js | 150 ++++++++++--------- test/features/external-webextensions.test.js | 8 +- 5 files changed, 168 insertions(+), 147 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 096ebf1..5c3f33e 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -9,8 +9,9 @@ const assignManager = { area: browser.storage.local, exemptedTabs: {}, - getSiteStoreKey(pageUrl) { - const url = new window.URL(pageUrl); + getSiteStoreKey(pageUrlorUrlKey) { + if (pageUrlorUrlKey.includes("siteContainerMap@@_")) return pageUrlorUrlKey; + const url = new window.URL(pageUrlorUrlKey); const storagePrefix = "siteContainerMap@@_"; if (url.port === "80" || url.port === "443") { return `${storagePrefix}${url.hostname}`; @@ -19,29 +20,29 @@ const assignManager = { } }, - setExempted(pageUrl, tabId) { - const siteStoreKey = this.getSiteStoreKey(pageUrl); + setExempted(pageUrlorUrlKey, tabId) { + const siteStoreKey = this.getSiteStoreKey(pageUrlorUrlKey); if (!(siteStoreKey in this.exemptedTabs)) { this.exemptedTabs[siteStoreKey] = []; } this.exemptedTabs[siteStoreKey].push(tabId); }, - removeExempted(pageUrl) { - const siteStoreKey = this.getSiteStoreKey(pageUrl); + removeExempted(pageUrlorUrlKey) { + const siteStoreKey = this.getSiteStoreKey(pageUrlorUrlKey); this.exemptedTabs[siteStoreKey] = []; }, - isExempted(pageUrl, tabId) { - const siteStoreKey = this.getSiteStoreKey(pageUrl); + isExempted(pageUrlorUrlKey, tabId) { + const siteStoreKey = this.getSiteStoreKey(pageUrlorUrlKey); if (!(siteStoreKey in this.exemptedTabs)) { return false; } return this.exemptedTabs[siteStoreKey].includes(tabId); }, - get(pageUrl) { - const siteStoreKey = this.getSiteStoreKey(pageUrl); + get(pageUrlorUrlKey) { + const siteStoreKey = this.getSiteStoreKey(pageUrlorUrlKey); return this.getByUrlKey(siteStoreKey); }, @@ -58,24 +59,26 @@ const assignManager = { }); }, - async set(pageUrl, data, exemptedTabIds) { - const siteStoreKey = this.getSiteStoreKey(pageUrl); + async set(pageUrlorUrlKey, data, exemptedTabIds, backup = true) { + const siteStoreKey = this.getSiteStoreKey(pageUrlorUrlKey); if (exemptedTabIds) { exemptedTabIds.forEach((tabId) => { - this.setExempted(pageUrl, tabId); + this.setExempted(pageUrlorUrlKey, tabId); }); } + data.identityMacAddonUUID = + await identityState.lookupMACaddonUUID(data.userContextId); await this.area.set({ [siteStoreKey]: data }); - await sync.storageArea.backup({undelete: siteStoreKey}); + if (backup) await sync.storageArea.backup({undelete: siteStoreKey}); return; }, - async remove(pageUrl) { - const siteStoreKey = this.getSiteStoreKey(pageUrl); + async remove(pageUrlorUrlKey) { + const siteStoreKey = this.getSiteStoreKey(pageUrlorUrlKey); // When we remove an assignment we should clear all the exemptions - this.removeExempted(pageUrl); + this.removeExempted(pageUrlorUrlKey); await this.area.remove([siteStoreKey]); await sync.storageArea.backup({siteStoreKey}); return; @@ -108,12 +111,14 @@ const assignManager = { return sites; }, + // TODOkmw: Change site assignment UUID + /* * Looks for abandoned site assignments. If there is no identity with * the site assignment's userContextId (cookieStoreId), then the assignment * is removed. */ - async cleanup() { + async upgradeData() { const identitiesList = await browser.contextualIdentities.query({}); const macConfigs = await this.area.get(); for(const configKey of Object.keys(macConfigs)) { @@ -127,6 +132,15 @@ const assignManager = { await this.remove(configKey.replace(/^siteContainerMap@@_/, "https://")); continue; } + const updatedSideAssignment = macConfigs[configKey]; + if (!macConfigs[configKey].identityMacAddonUUID) { + await this.set( + configKey.replace(/^siteContainerMap@@_/, "https://"), + updatedSideAssignment, + false, + false + ); + } } } diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index f4fb282..d260ca5 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -41,11 +41,11 @@ const identityState = { }, /* - * Looks for abandoned identities keys in local storage, and makes sure all + * Looks for abandoned identity keys in local storage, and makes sure all * identities registered in the browser are also in local storage. (this * appears to not always be the case based on how this.get() is written) */ - async cleanup() { + async upgradeData() { const identitiesList = await browser.contextualIdentities.query({}); const macConfigs = await this.area.get(); for(const configKey of Object.keys(macConfigs)) { @@ -120,10 +120,13 @@ const identityState = { }, async lookupMACaddonUUID(cookieStoreId) { - console.log(cookieStoreId); + // This stays a lookup, because if the cookieStoreId doesn't + // exist, this.get() will create it, which is not what we want. + const cookieStoreIdKey = cookieStoreId.includes("firefox-container-") ? + cookieStoreId : "firefox-container-" + cookieStoreId; const macConfigs = await this.storageArea.area.get(); for(const configKey of Object.keys(macConfigs)) { - if (configKey === "identitiesState@@_" + cookieStoreId) { + if (configKey === "identitiesState@@_" + cookieStoreIdKey) { return macConfigs[configKey].macAddonUUID; } } diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 5a418eb..f4959eb 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -150,7 +150,7 @@ const sync = { async errorHandledRunSync () { sync.runSync().catch(async (error)=> { console.error("Error from runSync", error); - sync.checkForListenersMaybeAdd(); + await sync.checkForListenersMaybeAdd(); }); }, @@ -161,13 +161,13 @@ const sync = { ); const hasCIListener = await hasContextualIdentityListeners(); - + if (!hasCIListener) { - addContextualIdentityListeners(); + await addContextualIdentityListeners(); } if (!hasStorageListener) { - browser.storage.onChanged.addListener( + await browser.storage.onChanged.addListener( sync.storageArea.onChangedListener); } }, @@ -177,15 +177,15 @@ const sync = { await browser.storage.onChanged.hasListener( sync.storageArea.onChangedListener ); - + const hasCIListener = await hasContextualIdentityListeners(); if (hasCIListener) { - removeContextualIdentityListeners(); + await removeContextualIdentityListeners(); } if (hasStorageListener) { - browser.storage.onChanged.removeListener( + await browser.storage.onChanged.removeListener( sync.storageArea.onChangedListener); } }, @@ -200,8 +200,8 @@ const sync = { await sync.checkForListenersMaybeRemove(); console.log("runSync"); - await identityState.storageArea.cleanup(); - await assignManager.storageArea.cleanup(); + await identityState.storageArea.upgradeData(); + await assignManager.storageArea.upgradeData(); const hasSyncStorage = await sync.storageArea.hasSyncStorage(); const dataIsReliable = await sync.storageArea.dataIsReliable(); @@ -275,6 +275,15 @@ async function reconcileIdentities(){ } // if no macAddonUUID, there is a problem with the sync info and it needs to be ignored. } + + await updateSiteAssignmentUUIDs(); + + async function updateSiteAssignmentUUIDs(){ + const sites = assignManager.storageArea.getAssignedSites(); + for (const siteKey of Object.keys(sites)) { + await assignManager.storageArea.set(siteKey, sites[siteKey]); + } + } } async function ifNamesMatch(syncIdentity, localMatch) { @@ -302,10 +311,12 @@ async function ifNamesMatch(syncIdentity, localMatch) { localMatch.cookieStoreId, syncIdentity.macAddonUUID ); + + // TODOkmw: update any site assignment UUIDs } async function ifUUIDMatch(syncIdentity, localCookieStoreID) { - // if there's a local uuid, it's the same container. Sync is truth + // if there's an identical local uuid, it's the same container. Sync is truth const identityInfo = { name: syncIdentity.name, color: syncIdentity.color, @@ -376,63 +387,46 @@ async function reconcileSiteAssignments() { .remove(siteStoreKey.replace(/^siteContainerMap@@_/, "https://")); } } - const cookieStoreIDmap = - await sync.storageArea.getCookieStoreIDMap(); for(const urlKey of Object.keys(assignedSitesFromSync)) { const assignedSite = assignedSitesFromSync[urlKey]; try{ - const syncUUID = - await lookupSyncSiteAssigmentIdentityUUID( - assignedSite, cookieStoreIDmap, urlKey - ); - if (syncUUID) { + const syncUUID = assignedSite.identityMacAddonUUID; + console.log("syncUUID, ", syncUUID); + if (assignedSite.identityMacAddonUUID) { // Sync is truth. // Not even looking it up. Just overwrite - console.log("new assignment ", assignedSite, ": ", - assignedSite.userContextId); - const newUUID = cookieStoreIDmap[ - "firefox-container-" + assignedSite.userContextId - ]; - - await setAssignmentWithUUID(newUUID, assignedSite, urlKey); + if (SYNC_DEBUG){ + const isInStorage = await assignManager.storageArea.getByUrlKey(urlKey); + if (!isInStorage) + console.log("new assignment ", assignedSite); + } + await setAssignmentWithUUID(assignedSite, urlKey); continue; } - } catch (error) { // this is probably old or incorrect site info in Sync // skip and move on. - //console.error("Error assigning site", error); - } } - - async function lookupSyncSiteAssigmentIdentityUUID( - assignedSite, - cookieStoreIDmap, - urlKey - ){ - const syncCookieStoreId = - "firefox-container-" + assignedSite.userContextId; - const uuid = cookieStoreIDmap[syncCookieStoreId]; - if (!uuid) throw new Error (`No syncUUID found for : ${urlKey}`); - return uuid; - } } -async function setAssignmentWithUUID (newUUID, assignedSite, urlKey) { - const cookieStoreId = await identityState.lookupCookieStoreId(newUUID); +async function setAssignmentWithUUID (assignedSite, urlKey) { + const uuid = assignedSite.identityMacAddonUUID; + const cookieStoreId = await identityState.lookupCookieStoreId(uuid); if (cookieStoreId) { assignedSite.userContextId = cookieStoreId .replace(/^firefox-container-/, ""); await assignManager.storageArea.set( urlKey.replace(/^siteContainerMap@@_/, "https://"), - assignedSite + assignedSite, + false, + false ); return; } - throw new Error (`No cookieStoreId found for: ${newUUID}, ${urlKey}`); + throw new Error (`No cookieStoreId found for: ${uuid}, ${urlKey}`); } const syncCIListenerList = [ @@ -441,18 +435,18 @@ const syncCIListenerList = [ sync.storageArea.backup ]; -function addContextualIdentityListeners(listenerList) { +async function addContextualIdentityListeners(listenerList) { if(!listenerList) listenerList = syncCIListenerList; - browser.contextualIdentities.onCreated.addListener(listenerList[0]); - browser.contextualIdentities.onRemoved.addListener(listenerList[1]); - browser.contextualIdentities.onUpdated.addListener(listenerList[2]); + await browser.contextualIdentities.onCreated.addListener(listenerList[0]); + await browser.contextualIdentities.onRemoved.addListener(listenerList[1]); + await browser.contextualIdentities.onUpdated.addListener(listenerList[2]); } -function removeContextualIdentityListeners(listenerList) { +async function removeContextualIdentityListeners(listenerList) { if(!listenerList) listenerList = syncCIListenerList; - browser.contextualIdentities.onCreated.removeListener(listenerList[0]); - browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); - browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); + await browser.contextualIdentities.onCreated.removeListener(listenerList[0]); + await browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); + await browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); } async function hasContextualIdentityListeners(listenerList) { diff --git a/src/js/background/test.js b/src/js/background/test.js index 1634f3f..0f1c58f 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -1,6 +1,7 @@ browser.tests = { async runAll() { await this.testIdentityStateCleanup(); + await this.testAssignManagerCleanup(); await this.testReconcileSiteAssignments(); await this.testInitialSync(); await this.test2(); @@ -28,7 +29,7 @@ browser.tests = { }); console.log("local storage set: ", await browser.storage.local.get()); - await identityState.storageArea.cleanup(); + await identityState.storageArea.upgradeData(); const macConfigs = await browser.storage.local.get(); const identities = []; @@ -42,71 +43,106 @@ browser.tests = { for (const identity of identities) { console.assert(!!identity.macAddonUUID, `${identity.name} should have a uuid`); } - console.log("Finished!"); + console.log("!!!Finished!!!"); }, async testAssignManagerCleanup() { await browser.tests.stopSyncListeners(); console.log("Testing the cleanup of local storage"); - await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); + await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); await browser.storage.local.set({ "siteContainerMap@@_www.goop.com": { - "userContextId": "5", + "userContextId": "6", "neverAsk": true, "hostname": "www.goop.com" } }); console.log("local storage set: ", await browser.storage.local.get()); - await assignManager.storageArea.cleanup(); - - await browser.storage.local.set({ - "identitiesState@@_firefox-container-5": { - "hiddenTabs": [] - } - }); + await identityState.storageArea.upgradeData(); + await assignManager.storageArea.upgradeData(); const macConfigs = await browser.storage.local.get(); const assignments = []; for(const configKey of Object.keys(macConfigs)) { if (configKey.includes("siteContainerMap@@_")) { - assignments.push(configKey); + macConfigs[configKey].configKey = configKey; + assignments.push(macConfigs[configKey]); } } - console.assert(assignments.length === 0, "There should be 0 identity entries"); - - console.log("Finished!"); + console.assert(assignments.length === 5, "There should be 5 identity entries"); + for (const assignment of assignments) { + console.log(assignment); + console.assert(!!assignment.identityMacAddonUUID, `${assignment.configKey} should have a uuid`); + } + console.log("!!!Finished!!!"); }, async testReconcileSiteAssignments() { await browser.tests.stopSyncListeners(); console.log("Testing reconciling Site Assignments"); - const newSyncData = DUPE_TEST_SYNC; - // add some bad data. - newSyncData.assignedSites["siteContainerMap@@_www.linkedin.com"] = { - "userContextId": "1", - "neverAsk": true, - "hostname": "www.linkedin.com" - }; - - newSyncData.deletedSiteList = ["siteContainerMap@@_www.google.com"]; - await this.setState( - newSyncData, + DUPE_TEST_SYNC, LOCAL_DATA, TEST_CONTAINERS, SITE_ASSIGNMENT_TEST ); + // add 200ok (bad data). + await browser.storage.sync.set({ + "assignedSites": { + "siteContainerMap@@_developer.mozilla.org": { + "userContextId": "588", + "neverAsk": true, + "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", + "hostname": "developer.mozilla.org" + }, + "siteContainerMap@@_reddit.com": { + "userContextId": "592", + "neverAsk": true, + "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", + "hostname": "reddit.com" + }, + "siteContainerMap@@_twitter.com": { + "userContextId": "589", + "neverAsk": true, + "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", + "hostname": "twitter.com" + }, + "siteContainerMap@@_www.facebook.com": { + "userContextId": "590", + "neverAsk": true, + "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", + "hostname": "www.facebook.com" + }, + "siteContainerMap@@_www.linkedin.com": { + "userContextId": "591", + "neverAsk": true, + "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", + "hostname": "www.linkedin.com" + }, + "siteContainerMap@@_200ok.us": { + "userContextId": "1", + "neverAsk": true, + "identityMacAddonUUID": "b5f5f794-b37e-4cec-9f4e-6490df620336", + "hostname": "www.linkedin.com" + } + } + }); + + await browser.storage.sync.set({ + deletedSiteList: ["siteContainerMap@@_www.google.com"] + }); + await sync.runSync(); const assignedSites = await assignManager.storageArea.getAssignedSites(); - console.assert(Object.keys(assignedSites).length === 5, "There should be 5 assigned sites"); - console.log("Finished!"); + console.assert(Object.keys(assignedSites).length === 6, "There should be 6 assigned sites"); + console.log("!!!Finished!!!"); }, async testInitialSync() { @@ -121,19 +157,12 @@ browser.tests = { const getAssignedSites = await assignManager.storageArea.getAssignedSites(); const identities = await browser.contextualIdentities.query({}); - const localCookieStoreIDmap = - await identityState.getCookieStoreIDuuidMap(); console.assert( Object.keys(getSync.cookieStoreIDmap).length === 5, "cookieStoreIDmap should have 5 entries" ); - console.assert( - Object.keys(localCookieStoreIDmap).length === 6, - "localCookieStoreIDmap should have 6 entries" - ); - console.assert( identities.length === 5, "There should be 5 identities" @@ -143,7 +172,7 @@ browser.tests = { Object.keys(getAssignedSites).length === 0, "There should be no site assignments" ); - console.log("Finished!"); + console.log("!!!Finished!!!"); }, async test2() { @@ -160,19 +189,11 @@ browser.tests = { const identities = await browser.contextualIdentities.query({}); - const localCookieStoreIDmap = - await identityState.getCookieStoreIDuuidMap(); - console.assert( Object.keys(getSync.cookieStoreIDmap).length === 6, "cookieStoreIDmap should have 6 entries" ); - console.assert( - Object.keys(localCookieStoreIDmap).length === 7, - "localCookieStoreIDmap should have 7 entries" - ); - console.assert( identities.length === 6, "There should be 6 identities" @@ -182,7 +203,7 @@ browser.tests = { Object.keys(getAssignedSites).length === 5, "There should be 5 site assignments" ); - console.log("Finished!"); + console.log("!!!Finished!!!"); }, async dupeTest() { @@ -204,19 +225,11 @@ browser.tests = { const identities = await browser.contextualIdentities.query({}); - const localCookieStoreIDmap = - await identityState.getCookieStoreIDuuidMap(); - console.assert( Object.keys(getSync.cookieStoreIDmap).length === 7, "cookieStoreIDmap should have 7 entries" ); - console.assert( - Object.keys(localCookieStoreIDmap).length === 8, - "localCookieStoreIDmap should have 8 entries" - ); - console.assert( identities.length === 7, "There should be 7 identities" @@ -240,7 +253,7 @@ browser.tests = { mozillaContainer.icon === "pet", "Mozilla Container should be pet" ); - console.log("Finished!"); + console.log("!!!Finished!!!"); }, async CIerrorTest() { @@ -262,19 +275,11 @@ browser.tests = { const identities = await browser.contextualIdentities.query({}); - const localCookieStoreIDmap = - await identityState.getCookieStoreIDuuidMap(); - console.assert( Object.keys(getSync.cookieStoreIDmap).length === 7, "cookieStoreIDmap should have 7 entries" ); - console.assert( - Object.keys(localCookieStoreIDmap).length === 8, - "localCookieStoreIDmap should have 8 entries" - ); - console.assert( identities.length === 7, "There should be 7 identities" @@ -298,7 +303,7 @@ browser.tests = { mozillaContainer.icon === "pet", "Mozilla Container should be pet" ); - console.log("Finished!"); + console.log("!!!Finished!!!"); }, lookupIdentityBy(identities, options) { @@ -358,14 +363,14 @@ browser.tests = { } }, - stopSyncListeners() { - browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - removeContextualIdentityListeners(); + async stopSyncListeners() { + await browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); + await removeContextualIdentityListeners(); }, - startListeners() { - browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); - addContextualIdentityListeners(); + async startListeners() { + await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); + await addContextualIdentityListeners(); }, }; @@ -529,26 +534,31 @@ const DUPE_TEST_SYNC = { "siteContainerMap@@_developer.mozilla.org": { "userContextId": "588", "neverAsk": true, + "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", "hostname": "developer.mozilla.org" }, "siteContainerMap@@_reddit.com": { "userContextId": "592", "neverAsk": true, + "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", "hostname": "reddit.com" }, "siteContainerMap@@_twitter.com": { "userContextId": "589", "neverAsk": true, + "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", "hostname": "twitter.com" }, "siteContainerMap@@_www.facebook.com": { "userContextId": "590", "neverAsk": true, + "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", "hostname": "www.facebook.com" }, "siteContainerMap@@_www.linkedin.com": { "userContextId": "591", "neverAsk": true, + "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", "hostname": "www.linkedin.com" } } @@ -682,11 +692,13 @@ const CI_ERROR_TEST_SYNC = { "siteContainerMap@@_bugzilla.mozilla.org": { "userContextId": "11", "neverAsk": true, + "identityMacAddonUUID": "0269558d-6be7-487b-beb1-b720b346d09b", "hostname": "bugzilla.mozilla.org" }, "siteContainerMap@@_www.amazon.com": { "userContextId": "14", "neverAsk": false, + "identityMacAddonUUID": "e48d04cf-6277-4236-8f3d-611287d0caf2", "hostname": "www.amazon.com" } }, diff --git a/test/features/external-webextensions.test.js b/test/features/external-webextensions.test.js index 04ebb99..485005c 100644 --- a/test/features/external-webextensions.test.js +++ b/test/features/external-webextensions.test.js @@ -25,11 +25,9 @@ describe("External Webextensions", () => { const [promise] = background.browser.runtime.onMessageExternal.addListener.yield(message, sender); const answer = await promise; - expect(answer).to.deep.equal({ - hostname: "example.com", - userContextId: "1", - neverAsk: false - }); + expect(answer.userContextId === "1").to.be.true; + expect(answer.neverAsk === false).to.be.true; + expect(answer.hasOwnProperty("identityMacAddonUUID")).to.be.true; }); }); From a7d3d6d8489b9d0e70d8185a1a65f0f46439994c Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 14 Jan 2020 10:37:47 -0600 Subject: [PATCH 35/60] fixed linting --- src/js/.eslintrc.js | 3 +- src/js/background/assignManager.js | 3 +- src/js/background/index.html | 2 +- src/js/background/sync.js | 58 ++++++++++---------- src/js/background/test.js | 4 +- test/features/external-webextensions.test.js | 4 +- test/features/sync.test.js | 3 - 7 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/js/.eslintrc.js b/src/js/.eslintrc.js index f78079f..11cd71a 100644 --- a/src/js/.eslintrc.js +++ b/src/js/.eslintrc.js @@ -7,6 +7,7 @@ module.exports = { "badge": true, "backgroundLogic": true, "identityState": true, - "messageHandler": true + "messageHandler": true, + "sync": true } }; diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 5c3f33e..8e82678 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -66,6 +66,7 @@ const assignManager = { this.setExempted(pageUrlorUrlKey, tabId); }); } + // eslint-disable-next-line require-atomic-updates data.identityMacAddonUUID = await identityState.lookupMACaddonUUID(data.userContextId); await this.area.set({ @@ -124,7 +125,7 @@ const assignManager = { for(const configKey of Object.keys(macConfigs)) { if (configKey.includes("siteContainerMap@@_")) { const cookieStoreId = - "firefox-container-" + macConfigs[configKey].userContextId; + "firefox-container-" + macConfigs[configKey].userContextId; const match = identitiesList.find( localIdentity => localIdentity.cookieStoreId === cookieStoreId ); diff --git a/src/js/background/index.html b/src/js/background/index.html index 78dbe21..c5c7889 100644 --- a/src/js/background/index.html +++ b/src/js/background/index.html @@ -14,11 +14,11 @@ ] --> + - diff --git a/src/js/background/sync.js b/src/js/background/sync.js index f4959eb..48a6270 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -160,10 +160,10 @@ const sync = { sync.storageArea.onChangedListener ); - const hasCIListener = await hasContextualIdentityListeners(); + const hasCIListener = await sync.hasContextualIdentityListeners(); if (!hasCIListener) { - await addContextualIdentityListeners(); + await sync.addContextualIdentityListeners(); } if (!hasStorageListener) { @@ -178,10 +178,10 @@ const sync = { sync.storageArea.onChangedListener ); - const hasCIListener = await hasContextualIdentityListeners(); + const hasCIListener = await sync.hasContextualIdentityListeners(); if (hasCIListener) { - await removeContextualIdentityListeners(); + await sync.removeContextualIdentityListeners(); } if (hasStorageListener) { @@ -210,6 +210,30 @@ const sync = { await sync.storageArea.backup(); return; }, + + async addContextualIdentityListeners(listenerList) { + if(!listenerList) listenerList = syncCIListenerList; + await browser.contextualIdentities.onCreated.addListener(listenerList[0]); + await browser.contextualIdentities.onRemoved.addListener(listenerList[1]); + await browser.contextualIdentities.onUpdated.addListener(listenerList[2]); + }, + + async removeContextualIdentityListeners(listenerList) { + if(!listenerList) listenerList = syncCIListenerList; + await browser.contextualIdentities.onCreated.removeListener(listenerList[0]); + await browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); + await browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); + }, + + async hasContextualIdentityListeners(listenerList) { + if(!listenerList) listenerList = syncCIListenerList; + return ( + await browser.contextualIdentities.onCreated.hasListener(listenerList[0]) && + await browser.contextualIdentities.onRemoved.hasListener(listenerList[1]) && + await browser.contextualIdentities.onUpdated.hasListener(listenerList[2]) + ); + } + }; sync.init(); @@ -381,7 +405,7 @@ async function reconcileSiteAssignments() { const deletedSiteList = await sync.storageArea.getDeletedSiteList(); for(const siteStoreKey of deletedSiteList) { - if (assignedSitesLocal.hasOwnProperty(siteStoreKey)) { + if (Object.prototype.hasOwnProperty.call(assignedSitesLocal,siteStoreKey)) { assignManager .storageArea .remove(siteStoreKey.replace(/^siteContainerMap@@_/, "https://")); @@ -416,6 +440,7 @@ async function setAssignmentWithUUID (assignedSite, urlKey) { const uuid = assignedSite.identityMacAddonUUID; const cookieStoreId = await identityState.lookupCookieStoreId(uuid); if (cookieStoreId) { + // eslint-disable-next-line require-atomic-updates assignedSite.userContextId = cookieStoreId .replace(/^firefox-container-/, ""); await assignManager.storageArea.set( @@ -434,26 +459,3 @@ const syncCIListenerList = [ sync.storageArea.addToDeletedList, sync.storageArea.backup ]; - -async function addContextualIdentityListeners(listenerList) { - if(!listenerList) listenerList = syncCIListenerList; - await browser.contextualIdentities.onCreated.addListener(listenerList[0]); - await browser.contextualIdentities.onRemoved.addListener(listenerList[1]); - await browser.contextualIdentities.onUpdated.addListener(listenerList[2]); -} - -async function removeContextualIdentityListeners(listenerList) { - if(!listenerList) listenerList = syncCIListenerList; - await browser.contextualIdentities.onCreated.removeListener(listenerList[0]); - await browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); - await browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); -} - -async function hasContextualIdentityListeners(listenerList) { - if(!listenerList) listenerList = syncCIListenerList; - return ( - await browser.contextualIdentities.onCreated.hasListener(listenerList[0]) && - await browser.contextualIdentities.onRemoved.hasListener(listenerList[1]) && - await browser.contextualIdentities.onUpdated.hasListener(listenerList[2]) - ); -} diff --git a/src/js/background/test.js b/src/js/background/test.js index 0f1c58f..166d0e8 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -365,12 +365,12 @@ browser.tests = { async stopSyncListeners() { await browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - await removeContextualIdentityListeners(); + await sync.removeContextualIdentityListeners(); }, async startListeners() { await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); - await addContextualIdentityListeners(); + await sync.addContextualIdentityListeners(); }, }; diff --git a/test/features/external-webextensions.test.js b/test/features/external-webextensions.test.js index 485005c..76db303 100644 --- a/test/features/external-webextensions.test.js +++ b/test/features/external-webextensions.test.js @@ -27,7 +27,9 @@ describe("External Webextensions", () => { const answer = await promise; expect(answer.userContextId === "1").to.be.true; expect(answer.neverAsk === false).to.be.true; - expect(answer.hasOwnProperty("identityMacAddonUUID")).to.be.true; + expect( + Object.prototype.hasOwnProperty.call( + answer, "identityMacAddonUUID")).to.be.true; }); }); diff --git a/test/features/sync.test.js b/test/features/sync.test.js index 72656fa..61915e1 100644 --- a/test/features/sync.test.js +++ b/test/features/sync.test.js @@ -1,7 +1,6 @@ describe("Sync", () => { it("should init sync on startup", async () => { - console.log("!!!a") const tab = await helper.browser.initializeWithTab(); console.log(await background.browser.storage.local.get()); const mozContainer = await background.browser.contextualIdentities.create({ @@ -54,7 +53,6 @@ describe("Sync", () => { }); } })); - console.log("!!!c"); await background.browser.runtime.onStartup.addListener.yield(); await nextTick(); @@ -62,7 +60,6 @@ describe("Sync", () => { console.log(await background.browser.storage.local.get()); expect(sync.identities.length).to.equal(5); - console.log("!!!b"); }); }); \ No newline at end of file From d7c0a3d9e187d7a2dbac252cb4df72d8da5209b0 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Tue, 14 Jan 2020 16:05:46 -0600 Subject: [PATCH 36/60] Fixed infinite loop in updating uuid for identities. --- src/js/background/identityState.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index d260ca5..e1b281f 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -12,11 +12,13 @@ const identityState = { const storageResponse = await this.area.get([storeKey]); if (storageResponse && storeKey in storageResponse) { if (!storageResponse[storeKey].macAddonUUID){ - await identityState.addUUID(cookieStoreId); - return this.get(cookieStoreId); + storageResponse[storeKey].macAddonUUID = uuidv4(); + await this.set(cookieStoreId, storageResponse[cookieStoreId]); } return storageResponse[storeKey]; } + // If local storage doesn't have an entry, look it up to make sure it's + // an in-use identity. const identities = await browser.contextualIdentities.query({}); const match = identities.find( (identity) => identity.cookieStoreId === cookieStoreId); @@ -60,15 +62,14 @@ const identityState = { continue; } if (!macConfigs[configKey].macAddonUUID) { - await identityState.addUUID(cookieStoreId); + await identityState.storageArea.get(cookieStoreId); } } } for (const identity of identitiesList) { // ensure all identities have an entry in local storage - const data = await this.get(identity.cookieStoreId); - await this.set(identity.cookieStoreId, data); + await identityState.addUUID(identity.cookieStoreId); } } }, @@ -116,7 +117,7 @@ const identityState = { }, async addUUID(cookieStoreId) { - return await this.updateUUID(cookieStoreId, uuidv4()); + await this.storageArea.get(cookieStoreId); }, async lookupMACaddonUUID(cookieStoreId) { From 60bfdffdd65f764e88091d2dbbf7a7f2fe9163d0 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 15 Jan 2020 14:46:52 -0600 Subject: [PATCH 37/60] fixed race condition while upgrading containers and site assignments. --- src/js/background/assignManager.js | 22 ++++++++++------------ src/js/background/identityState.js | 2 +- src/js/background/sync.js | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 8e82678..2655768 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -112,8 +112,6 @@ const assignManager = { return sites; }, - // TODOkmw: Change site assignment UUID - /* * Looks for abandoned site assignments. If there is no identity with * the site assignment's userContextId (cookieStoreId), then the assignment @@ -133,15 +131,15 @@ const assignManager = { await this.remove(configKey.replace(/^siteContainerMap@@_/, "https://")); continue; } - const updatedSideAssignment = macConfigs[configKey]; - if (!macConfigs[configKey].identityMacAddonUUID) { - await this.set( - configKey.replace(/^siteContainerMap@@_/, "https://"), - updatedSideAssignment, - false, - false - ); - } + const updatedSiteAssignment = macConfigs[configKey]; + updatedSiteAssignment.identityMacAddonUUID = + await identityState.lookupMACaddonUUID(match.cookieStoreId); + await this.set( + configKey, + updatedSiteAssignment, + false, + false + ); } } @@ -168,7 +166,7 @@ const assignManager = { // We return here so the confirm page can load the tab when exempted async _exemptTab(m) { const pageUrl = m.pageUrl; - this.storageArea.setExempted(pageUrl, m.tabId); + await this.storageArea.setExempted(pageUrl, m.tabId); return true; }, diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index e1b281f..9ae8403 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -58,7 +58,7 @@ const identityState = { ); if (cookieStoreId === "firefox-default") continue; if (!match) { - this.remove(cookieStoreId); + await this.remove(cookieStoreId); continue; } if (!macConfigs[configKey].macAddonUUID) { diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 48a6270..e33bf2c 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -148,7 +148,7 @@ const sync = { }, async errorHandledRunSync () { - sync.runSync().catch(async (error)=> { + await sync.runSync().catch( async (error)=> { console.error("Error from runSync", error); await sync.checkForListenersMaybeAdd(); }); From 361e49d553bdd6bf1dbaec0c838db625a0f87dfb Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 16 Jan 2020 10:04:28 -0600 Subject: [PATCH 38/60] bumped version for beta --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a2d979..2e36b25 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "testpilot-containers", "title": "Multi-Account Containers", "description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", - "version": "6.1.1", + "version": "6.1.2", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/multi-account-containers/issues" From d7b66eca525c2094ddc56d1a1a049ca6c3479275 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 22 Jan 2020 10:57:27 -0600 Subject: [PATCH 39/60] added key to sync for each install of MAC. Keeps a list of installed identities and site assignments of reach MAC install --- src/js/background/assignManager.js | 2 +- src/js/background/sync.js | 95 ++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 2655768..d986456 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -72,7 +72,7 @@ const assignManager = { await this.area.set({ [siteStoreKey]: data }); - if (backup) await sync.storageArea.backup({undelete: siteStoreKey}); + if (backup) await sync.storageArea.backup({undeleteSiteStoreKey: siteStoreKey}); return; }, diff --git a/src/js/background/sync.js b/src/js/background/sync.js index e33bf2c..27243f8 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -44,6 +44,16 @@ const sync = { return false; }, + async getAllInstanceInfo() { + const instanceList = {}; + const allSyncInfo = await this.get(); + for (const objectKey of Object.keys(allSyncInfo)) { + if (objectKey.includes("MACinstance")) { + instanceList[objectKey] = allSyncInfo[objectKey]; } + } + return instanceList; + }, + async hasSyncStorage(){ const inSync = await this.get(); return !(Object.entries(inSync).length === 0); @@ -53,15 +63,18 @@ const sync = { // remove listeners to avoid an infinite loop! await sync.checkForListenersMaybeRemove(); - await updateSyncIdentities(); + const identities = await updateSyncIdentities(); await updateCookieStoreIdMap(); - await updateSyncSiteAssignments(); + const siteAssignments = await updateSyncSiteAssignments(); + await updateInstanceInfo(identities, siteAssignments); if (options && options.uuid) await updateDeletedIdentityList(options.uuid); + if (options && options.undeleteUUID) + await removeFromDeletedIdentityList(options.undeleteUUID); if (options && options.siteStoreKey) await addToDeletedSitesList(options.siteStoreKey); - if (options && options.undelete) - await removeFromDeletedSitesList(options.undelete); + if (options && options.undeleteSiteStoreKey) + await removeFromDeletedSitesList(options.undeleteSiteStoreKey); // if (SYNC_DEBUG) { // const storage = await sync.storageArea.get(); // console.log("inSync: ", storage); @@ -74,7 +87,14 @@ const sync = { async function updateSyncIdentities() { const identities = await browser.contextualIdentities.query({}); + + for (const identity of identities) { + delete identity.colorCode; + delete identity.iconUrl; + identity.macAddonUUID = await identityState.lookupMACaddonUUID(identity.cookieStoreId); + } await sync.storageArea.set({ identities }); + return identities; } async function updateCookieStoreIdMap() { @@ -87,6 +107,22 @@ const sync = { const assignedSites = await assignManager.storageArea.getAssignedSites(); await sync.storageArea.set({ assignedSites }); + return assignedSites; + } + + async function updateInstanceInfo(identitiesInput, siteAssignmentsInput) { + const installUUID = browser.runtime.getURL("") + .replace(/moz-extension:\/\//, "MACinstance:") + .replace(/\//, ""); + const identities = []; + const siteAssignments = []; + for (const identity of identitiesInput) { + identities.push(identity.macAddonUUID); + } + for (const siteAssignmentKey of Object.keys(siteAssignmentsInput)) { + siteAssignments.push(siteAssignmentKey); + } + await sync.storageArea.set({ [installUUID]: { identities, siteAssignments } }); } async function updateDeletedIdentityList(deletedIdentityUUID) { @@ -99,6 +135,14 @@ const sync = { await sync.storageArea.set({ deletedIdentityList }); } + async function removeFromDeletedIdentityList(identityUUID) { + const deletedIdentityList = + await sync.storageArea.getDeletedIdentityList(); + const newDeletedIdentityList = deletedIdentityList + .filter(element => element !== identityUUID); + await sync.storageArea.set({ deletedIdentityList: newDeletedIdentityList }); + } + async function addToDeletedSitesList(siteStoreKey) { const deletedSiteList = await sync.storageArea.getDeletedSiteList(); @@ -143,8 +187,12 @@ const sync = { }, init() { - browser.runtime.onInstalled.addListener(this.errorHandledRunSync); - browser.runtime.onStartup.addListener(this.errorHandledRunSync); + // Add listener to sync storage and containers. + // Works for all installs that have any sync storage. + // Waits for sync storage change before kicking off the restore/backup + // initial sync must be kicked off by user. + this.checkForListenersMaybeAdd(); + }, async errorHandledRunSync () { @@ -208,7 +256,8 @@ const sync = { if (hasSyncStorage && dataIsReliable) await restore(); await sync.storageArea.backup(); - return; + await removeOldDeletedItems(); + return; }, async addContextualIdentityListeners(listenerList) { @@ -232,7 +281,7 @@ const sync = { await browser.contextualIdentities.onRemoved.hasListener(listenerList[1]) && await browser.contextualIdentities.onUpdated.hasListener(listenerList[2]) ); - } + }, }; @@ -415,8 +464,6 @@ async function reconcileSiteAssignments() { for(const urlKey of Object.keys(assignedSitesFromSync)) { const assignedSite = assignedSitesFromSync[urlKey]; try{ - const syncUUID = assignedSite.identityMacAddonUUID; - console.log("syncUUID, ", syncUUID); if (assignedSite.identityMacAddonUUID) { // Sync is truth. // Not even looking it up. Just overwrite @@ -436,6 +483,34 @@ async function reconcileSiteAssignments() { } } +async function removeOldDeletedItems() { + const instanceList = await sync.storageArea.getAllInstanceInfo(); + const deletedSiteList = await sync.storageArea.getDeletedSiteList(); + const deletedIdentityList = await sync.storageArea.getDeletedIdentityList(); + for (const siteStoreKey of deletedSiteList) { + let hasMatch = false; + for (const instance of Object.values(instanceList)) { + const match = instance.siteAssignments.find(element => element === siteStoreKey); + if (!match) continue; + hasMatch = true; + } + if (!hasMatch) { + await sync.storageArea.backup({undeleteSiteStoreKey: siteStoreKey}); + } + } + for (const identityUUID of deletedIdentityList) { + let hasMatch = false; + for (const instance of Object.values(instanceList)) { + const match = instance.identities.find(element => element === identityUUID); + if (!match) continue; + hasMatch = true; + } + if (!hasMatch) { + await sync.storageArea.backup({undeleteUUID: identityUUID}); + } + } +} + async function setAssignmentWithUUID (assignedSite, urlKey) { const uuid = assignedSite.identityMacAddonUUID; const cookieStoreId = await identityState.lookupCookieStoreId(uuid); From 3aa2902cdef0af6c5af703f60b66c985e435ef4a Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 22 Jan 2020 16:43:10 -0600 Subject: [PATCH 40/60] added on/off switch and expiration date on instanceKeys in sync on/off is in settings. when instanceKey date is 30 days old, it is deleted fixed bug --- src/js/background/assignManager.js | 11 +- src/js/background/index.html | 2 +- src/js/background/messageHandler.js | 3 + src/js/background/sync.js | 175 ++++++++++++++++------------ src/js/options.js | 21 +++- src/options.html | 5 + 6 files changed, 139 insertions(+), 78 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index d986456..a9493c0 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -46,6 +46,11 @@ const assignManager = { return this.getByUrlKey(siteStoreKey); }, + async getSyncEnabled() { + const { syncEnabled } = await browser.storage.local.get("syncEnabled"); + return !!syncEnabled; + }, + getByUrlKey(siteStoreKey) { return new Promise((resolve, reject) => { this.area.get([siteStoreKey]).then((storageResponse) => { @@ -72,7 +77,8 @@ const assignManager = { await this.area.set({ [siteStoreKey]: data }); - if (backup) await sync.storageArea.backup({undeleteSiteStoreKey: siteStoreKey}); + const syncEnabled = await this.getSyncEnabled(); + if (backup && syncEnabled) await sync.storageArea.backup({undeleteSiteStoreKey: siteStoreKey}); return; }, @@ -81,7 +87,8 @@ const assignManager = { // When we remove an assignment we should clear all the exemptions this.removeExempted(pageUrlorUrlKey); await this.area.remove([siteStoreKey]); - await sync.storageArea.backup({siteStoreKey}); + const syncEnabled = await this.getSyncEnabled(); + if (syncEnabled) await sync.storageArea.backup({siteStoreKey}); return; }, diff --git a/src/js/background/index.html b/src/js/background/index.html index c5c7889..3bb1a79 100644 --- a/src/js/background/index.html +++ b/src/js/background/index.html @@ -14,11 +14,11 @@ ] --> - + diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index 9578e6e..f4236f1 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -10,6 +10,9 @@ const messageHandler = { let response; switch (m.method) { + case "resetSync": + response = sync.resetSync(); + break; case "resetBookmarksContext": response = assignManager.resetBookmarksMenuItem(); break; diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 27243f8..2cfddc7 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -12,14 +12,40 @@ const sync = { return await this.area.set(options); }, + async deleteIdentity(deletedIdentityUUID) { + const deletedIdentityList = + await sync.storageArea.getDeletedIdentityList(); + if ( + deletedIdentityList.find(element => element === deletedIdentityUUID) + ) return; + deletedIdentityList.push(deletedIdentityUUID); + await sync.storageArea.set({ deletedIdentityList }); + await sync.storageArea.area.remove( "identity@@_" + deletedIdentityUUID); + }, + + async deleteSite(siteStoreKey) { + const deletedSiteList = + await sync.storageArea.getDeletedSiteList(); + if (deletedSiteList.find(element => element === siteStoreKey)) return; + deletedSiteList.push(siteStoreKey); + await sync.storageArea.set({ deletedSiteList }); + await sync.storageArea.area.remove(siteStoreKey); + }, + async getDeletedIdentityList() { const storedArray = await this.getStoredItem("deletedIdentityList"); return (storedArray) ? storedArray : []; }, async getIdentities() { - const storedArray = await this.getStoredItem("identities"); - return (storedArray) ? storedArray : []; + const allSyncStorage = await this.get(); + const identities = []; + for (const storageKey of Object.keys(allSyncStorage)) { + if (storageKey.includes("identity@@_")) { + identities.push(allSyncStorage[storageKey]); + } + } + return identities; }, async getDeletedSiteList() { @@ -27,14 +53,15 @@ const sync = { return (storedArray) ? storedArray : []; }, - async getCookieStoreIDMap() { - const storedArray = await this.getStoredItem("cookieStoreIDmap"); - return (storedArray) ? storedArray : {}; - }, - async getAssignedSites() { - const storedArray = await this.getStoredItem("assignedSites"); - return (storedArray) ? storedArray : {}; + const allSyncStorage = await this.get(); + const sites = {}; + for (const storageKey of Object.keys(allSyncStorage)) { + if (storageKey.includes("siteContainerMap@@_")) { + sites[storageKey] = allSyncStorage[storageKey]; + } + } + return sites; }, async getStoredItem(objectKey) { @@ -54,6 +81,23 @@ const sync = { return instanceList; }, + getInstanceKey() { + return browser.runtime.getURL("") + .replace(/moz-extension:\/\//, "MACinstance:") + .replace(/\//, ""); + }, + async removeInstance(installUUID) { + console.log("removing", installUUID); + await this.area.remove(installUUID); + return; + }, + + async removeThisInstanceFromSync() { + const installUUID = this.getInstanceKey(); + await this.removeInstance(installUUID); + return; + }, + async hasSyncStorage(){ const inSync = await this.get(); return !(Object.entries(inSync).length === 0); @@ -64,24 +108,16 @@ const sync = { await sync.checkForListenersMaybeRemove(); const identities = await updateSyncIdentities(); - await updateCookieStoreIdMap(); const siteAssignments = await updateSyncSiteAssignments(); await updateInstanceInfo(identities, siteAssignments); if (options && options.uuid) - await updateDeletedIdentityList(options.uuid); + await this.deleteIdentity(options.uuid); if (options && options.undeleteUUID) await removeFromDeletedIdentityList(options.undeleteUUID); if (options && options.siteStoreKey) - await addToDeletedSitesList(options.siteStoreKey); + await this.deleteSite(options.siteStoreKey); if (options && options.undeleteSiteStoreKey) await removeFromDeletedSitesList(options.undeleteSiteStoreKey); - // if (SYNC_DEBUG) { - // const storage = await sync.storageArea.get(); - // console.log("inSync: ", storage); - // const localStorage = await browser.storage.local.get(); - // console.log("inLocal:", localStorage); - // console.log("idents: ", await browser.contextualIdentities.query({})); - // } console.log("Backed up!"); await sync.checkForListenersMaybeAdd(); @@ -92,28 +128,29 @@ const sync = { delete identity.colorCode; delete identity.iconUrl; identity.macAddonUUID = await identityState.lookupMACaddonUUID(identity.cookieStoreId); + if(identity.macAddonUUID) { + const storageKey = "identity@@_" + identity.macAddonUUID; + await sync.storageArea.set({ [storageKey]: identity }); + } } - await sync.storageArea.set({ identities }); + //await sync.storageArea.set({ identities }); return identities; } - async function updateCookieStoreIdMap() { - const cookieStoreIDmap = - await identityState.getCookieStoreIDuuidMap(); - await sync.storageArea.set({ cookieStoreIDmap }); - } - async function updateSyncSiteAssignments() { const assignedSites = await assignManager.storageArea.getAssignedSites(); - await sync.storageArea.set({ assignedSites }); + for (const siteKey of Object.keys(assignedSites)) { + await sync.storageArea.set({ [siteKey]: assignedSites[siteKey] }); + } return assignedSites; } async function updateInstanceInfo(identitiesInput, siteAssignmentsInput) { - const installUUID = browser.runtime.getURL("") - .replace(/moz-extension:\/\//, "MACinstance:") - .replace(/\//, ""); + const date = new Date(); + const timestamp = date.getTime(); + const installUUID = sync.storageArea.getInstanceKey(); + console.log("adding", installUUID); const identities = []; const siteAssignments = []; for (const identity of identitiesInput) { @@ -122,17 +159,7 @@ const sync = { for (const siteAssignmentKey of Object.keys(siteAssignmentsInput)) { siteAssignments.push(siteAssignmentKey); } - await sync.storageArea.set({ [installUUID]: { identities, siteAssignments } }); - } - - async function updateDeletedIdentityList(deletedIdentityUUID) { - const deletedIdentityList = - await sync.storageArea.getDeletedIdentityList(); - if ( - deletedIdentityList.find(element => element === deletedIdentityUUID) - ) return; - deletedIdentityList.push(deletedIdentityUUID); - await sync.storageArea.set({ deletedIdentityList }); + await sync.storageArea.set({ [installUUID]: { timestamp, identities, siteAssignments } }); } async function removeFromDeletedIdentityList(identityUUID) { @@ -143,14 +170,6 @@ const sync = { await sync.storageArea.set({ deletedIdentityList: newDeletedIdentityList }); } - async function addToDeletedSitesList(siteStoreKey) { - const deletedSiteList = - await sync.storageArea.getDeletedSiteList(); - if (deletedSiteList.find(element => element === siteStoreKey)) return; - deletedSiteList.push(siteStoreKey); - await sync.storageArea.set({ deletedSiteList }); - } - async function removeFromDeletedSitesList(siteStoreKey) { const deletedSiteList = await sync.storageArea.getDeletedSiteList(); @@ -170,28 +189,20 @@ const sync = { await identityState.lookupMACaddonUUID(identity.cookieStoreId); await identityState.storageArea.remove(identity.cookieStoreId); sync.storageArea.backup({uuid: deletedUUID}); - }, - - async dataIsReliable() { - const cookieStoreIDmap = await this.getCookieStoreIDMap(); - const identities = await this.getIdentities(); - for (const cookieStoreId of Object.keys(cookieStoreIDmap)) { - const match = identities.find(identity => - identity.cookieStoreId === cookieStoreId - ); - // if one has no match, this is bad data. - if (!match) return false; - } - return !(Object.entries(cookieStoreIDmap).length === 0); } }, - init() { - // Add listener to sync storage and containers. - // Works for all installs that have any sync storage. - // Waits for sync storage change before kicking off the restore/backup - // initial sync must be kicked off by user. - this.checkForListenersMaybeAdd(); + async init() { + const syncEnabled = await assignManager.storageArea.getSyncEnabled(); + if (syncEnabled) { + // Add listener to sync storage and containers. + // Works for all installs that have any sync storage. + // Waits for sync storage change before kicking off the restore/backup + // initial sync must be kicked off by user. + this.checkForListenersMaybeAdd(); + return; + } + this.checkForListenersMaybeRemove(); }, @@ -252,8 +263,7 @@ const sync = { await assignManager.storageArea.upgradeData(); const hasSyncStorage = await sync.storageArea.hasSyncStorage(); - const dataIsReliable = await sync.storageArea.dataIsReliable(); - if (hasSyncStorage && dataIsReliable) await restore(); + if (hasSyncStorage) await restore(); await sync.storageArea.backup(); await removeOldDeletedItems(); @@ -283,6 +293,16 @@ const sync = { ); }, + async resetSync() { + const syncEnabled = await assignManager.storageArea.getSyncEnabled(); + if (syncEnabled) { + this.errorHandledRunSync(); + return; + } + await this.checkForListenersMaybeRemove(); + await this.storageArea.removeThisInstanceFromSync(); + } + }; sync.init(); @@ -323,11 +343,8 @@ async function reconcileIdentities(){ const localIdentities = await browser.contextualIdentities.query({}); const syncIdentities = await sync.storageArea.getIdentities(); - const cookieStoreIDmap = - await sync.storageArea.getCookieStoreIDMap(); // now compare all containers for matching names. for (const syncIdentity of syncIdentities) { - syncIdentity.macAddonUUID = cookieStoreIDmap[syncIdentity.cookieStoreId]; if (syncIdentity.macAddonUUID){ const localMatch = localIdentities.find( localIdentity => localIdentity.name === syncIdentity.name @@ -483,10 +500,22 @@ async function reconcileSiteAssignments() { } } +const MILISECONDS_IN_THIRTY_DAYS = 2592000000; + async function removeOldDeletedItems() { const instanceList = await sync.storageArea.getAllInstanceInfo(); const deletedSiteList = await sync.storageArea.getDeletedSiteList(); const deletedIdentityList = await sync.storageArea.getDeletedIdentityList(); + + for (const instanceKey of Object.keys(instanceList)) { + const date = new Date(); + const currentTimestamp = date.getTime(); + if (instanceList[instanceKey].timestamp < currentTimestamp - MILISECONDS_IN_THIRTY_DAYS) { + delete instanceList[instanceKey]; + sync.storageArea.removeInstance(instanceKey); + continue; + } + } for (const siteStoreKey of deletedSiteList) { let hasMatch = false; for (const instance of Object.values(instanceList)) { diff --git a/src/js/options.js b/src/js/options.js index 222a5b0..2f3fa32 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -1,4 +1,3 @@ - async function requestPermissions() { const checkbox = document.querySelector("#bookmarksPermissions"); if (checkbox.checked) { @@ -13,13 +12,31 @@ async function requestPermissions() { browser.runtime.sendMessage({ method: "resetBookmarksContext" }); } +async function enableDisableSync() { + const checkbox = document.querySelector("#syncCheck"); + if (checkbox.checked) { + await browser.storage.local.set({syncEnabled: true}); + } else { + await browser.storage.local.set({syncEnabled: false}); + } + browser.runtime.sendMessage({ method: "resetSync" }); +} + async function restoreOptions() { const hasPermission = await browser.permissions.contains({permissions: ["bookmarks"]}); + const { syncEnabled } = await browser.storage.local.get("syncEnabled"); + console.log(syncEnabled); if (hasPermission) { document.querySelector("#bookmarksPermissions").checked = true; } + if (syncEnabled) { + document.querySelector("#syncCheck").checked = true; + } else { + document.querySelector("#syncCheck").checked = false; + } } document.addEventListener("DOMContentLoaded", restoreOptions); -document.querySelector("#bookmarksPermissions").addEventListener( "change", requestPermissions); \ No newline at end of file +document.querySelector("#bookmarksPermissions").addEventListener( "change", requestPermissions); +document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync); diff --git a/src/options.html b/src/options.html index 1dcdd9b..31a567e 100644 --- a/src/options.html +++ b/src/options.html @@ -12,6 +12,11 @@ Enable Bookmark Menus

This setting allows you to open a bookmark or folder of bookmarks in a container.

+ +

This setting allows you to sync your containers and site assignments across devices.

From 61b5c2e4b23cde2e8c5e262916fcfb0bffe38be2 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 22 Jan 2020 23:50:19 -0600 Subject: [PATCH 41/60] updated tests to match new formatting" --- src/js/background/test.js | 341 ++++++++++++++++---------------------- 1 file changed, 146 insertions(+), 195 deletions(-) diff --git a/src/js/background/test.js b/src/js/background/test.js index 166d0e8..fada4f9 100644 --- a/src/js/background/test.js +++ b/src/js/background/test.js @@ -93,51 +93,53 @@ browser.tests = { ); // add 200ok (bad data). - await browser.storage.sync.set({ - "assignedSites": { - "siteContainerMap@@_developer.mozilla.org": { - "userContextId": "588", - "neverAsk": true, - "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", - "hostname": "developer.mozilla.org" - }, - "siteContainerMap@@_reddit.com": { - "userContextId": "592", - "neverAsk": true, - "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", - "hostname": "reddit.com" - }, - "siteContainerMap@@_twitter.com": { - "userContextId": "589", - "neverAsk": true, - "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", - "hostname": "twitter.com" - }, - "siteContainerMap@@_www.facebook.com": { - "userContextId": "590", - "neverAsk": true, - "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", - "hostname": "www.facebook.com" - }, - "siteContainerMap@@_www.linkedin.com": { - "userContextId": "591", - "neverAsk": true, - "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", - "hostname": "www.linkedin.com" - }, - "siteContainerMap@@_200ok.us": { - "userContextId": "1", - "neverAsk": true, - "identityMacAddonUUID": "b5f5f794-b37e-4cec-9f4e-6490df620336", - "hostname": "www.linkedin.com" - } + const testSites = { + "siteContainerMap@@_developer.mozilla.org": { + "userContextId": "588", + "neverAsk": true, + "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", + "hostname": "developer.mozilla.org" + }, + "siteContainerMap@@_reddit.com": { + "userContextId": "592", + "neverAsk": true, + "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", + "hostname": "reddit.com" + }, + "siteContainerMap@@_twitter.com": { + "userContextId": "589", + "neverAsk": true, + "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", + "hostname": "twitter.com" + }, + "siteContainerMap@@_www.facebook.com": { + "userContextId": "590", + "neverAsk": true, + "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", + "hostname": "www.facebook.com" + }, + "siteContainerMap@@_www.linkedin.com": { + "userContextId": "591", + "neverAsk": true, + "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", + "hostname": "www.linkedin.com" + }, + "siteContainerMap@@_200ok.us": { + "userContextId": "1", + "neverAsk": true, + "identityMacAddonUUID": "b5f5f794-b37e-4cec-9f4e-6490df620336", + "hostname": "www.linkedin.com" } - }); + }; + + for (const site of Object.keys(testSites)) { + await browser.storage.sync.set({[site]:testSites[site]}); + } await browser.storage.sync.set({ deletedSiteList: ["siteContainerMap@@_www.google.com"] }); - + console.log(await browser.storage.sync.get()); await sync.runSync(); const assignedSites = await assignManager.storageArea.getAssignedSites(); @@ -153,16 +155,10 @@ browser.tests = { await sync.runSync(); - const getSync = await browser.storage.sync.get(); const getAssignedSites = await assignManager.storageArea.getAssignedSites(); const identities = await browser.contextualIdentities.query({}); - console.assert( - Object.keys(getSync.cookieStoreIDmap).length === 5, - "cookieStoreIDmap should have 5 entries" - ); - console.assert( identities.length === 5, "There should be 5 identities" @@ -183,17 +179,11 @@ browser.tests = { await sync.runSync(); - const getSync = await browser.storage.sync.get(); const getAssignedSites = await assignManager.storageArea.getAssignedSites(); const identities = await browser.contextualIdentities.query({}); - console.assert( - Object.keys(getSync.cookieStoreIDmap).length === 6, - "cookieStoreIDmap should have 6 entries" - ); - console.assert( identities.length === 6, "There should be 6 identities" @@ -219,17 +209,11 @@ browser.tests = { await sync.runSync(); - const getSync = await browser.storage.sync.get(); const getAssignedSites = await assignManager.storageArea.getAssignedSites(); const identities = await browser.contextualIdentities.query({}); - console.assert( - Object.keys(getSync.cookieStoreIDmap).length === 7, - "cookieStoreIDmap should have 7 entries" - ); - console.assert( identities.length === 7, "There should be 7 identities" @@ -419,148 +403,115 @@ const LOCAL_DATA = { }; const SYNC_DATA = { - "identities": [ - { - "name": "Personal", - "icon": "fingerprint", - "iconUrl": "resource://usercontext-content/fingerprint.svg", - "color": "red", - "colorCode": "#37adff", - "cookieStoreId": "firefox-container-146" - }, - { - "name": "Oscar", - "icon": "dollar", - "iconUrl": "resource://usercontext-content/dollar.svg", - "color": "green", - "colorCode": "#51cd00", - "cookieStoreId": "firefox-container-147" - }, - { - "name": "Mozilla", - "icon": "pet", - "iconUrl": "resource://usercontext-content/briefcase.svg", - "color": "red", - "colorCode": "#ff613d", - "cookieStoreId": "firefox-container-148" - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "iconUrl": "resource://usercontext-content/cart.svg", - "color": "pink", - "colorCode": "#ffcb00", - "cookieStoreId": "firefox-container-149" - }, - { - "name": "Facebook", - "icon": "fence", - "iconUrl": "resource://usercontext-content/fence.svg", - "color": "toolbar", - "colorCode": "#7c7c7d", - "cookieStoreId": "firefox-container-150" - } - ], - "cookieStoreIDmap": { - "firefox-container-146": "22ded543-5173-44a5-a47a-8813535945ca", - "firefox-container-147": "63e5212f-0858-418e-b5a3-09c2dea61fcd", - "firefox-container-148": "71335417-158e-4d74-a55b-e9e9081601ec", - "firefox-container-149": "59c4e5f7-fe3b-435a-ae60-1340db31a91b", - "firefox-container-150": "3dc916fb-8c0a-4538-9758-73ef819a45f7" + "identity@@_22ded543-5173-44a5-a47a-8813535945ca": { + "name": "Personal", + "icon": "fingerprint", + "color": "red", + "cookieStoreId": "firefox-container-146", + "macAddonUUID": "22ded543-5173-44a5-a47a-8813535945ca" }, - "assignedSites": {} + "identity@@_63e5212f-0858-418e-b5a3-09c2dea61fcd": { + "name": "Oscar", + "icon": "dollar", + "color": "green", + "cookieStoreId": "firefox-container-147", + "macAddonUUID": "3e5212f-0858-418e-b5a3-09c2dea61fcd" + }, + "identity@@_71335417-158e-4d74-a55b-e9e9081601ec": { + "name": "Mozilla", + "icon": "pet", + "color": "red", + "cookieStoreId": "firefox-container-148", + "macAddonUUID": "71335417-158e-4d74-a55b-e9e9081601ec" + }, + "identity@@_59c4e5f7-fe3b-435a-ae60-1340db31a91b": { + "name": "Groceries, obviously", + "icon": "cart", + "color": "pink", + "cookieStoreId": "firefox-container-149", + "macAddonUUID": "59c4e5f7-fe3b-435a-ae60-1340db31a91b" + }, + "identity@@_3dc916fb-8c0a-4538-9758-73ef819a45f7": { + "name": "Facebook", + "icon": "fence", + "color": "toolbar", + "cookieStoreId": "firefox-container-150", + "macAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7" + } }; const DUPE_TEST_SYNC = { - "identities": [ - { - "name": "Personal", - "icon": "fingerprint", - "iconUrl": "resource://usercontext-content/fingerprint.svg", - "color": "red", - "colorCode": "#ff613d", - "cookieStoreId": "firefox-container-588" - }, - { - "name": "Banking", - "icon": "dollar", - "iconUrl": "resource://usercontext-content/dollar.svg", - "color": "green", - "colorCode": "#51cd00", - "cookieStoreId": "firefox-container-589" - }, - { - "name": "Mozilla", - "icon": "pet", - "iconUrl": "resource://usercontext-content/pet.svg", - "color": "red", - "colorCode": "#ff613d", - "cookieStoreId": "firefox-container-590" - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "iconUrl": "resource://usercontext-content/cart.svg", - "color": "pink", - "colorCode": "#ff4bda", - "cookieStoreId": "firefox-container-591" - }, - { - "name": "Facebook", - "icon": "fence", - "iconUrl": "resource://usercontext-content/fence.svg", - "color": "toolbar", - "colorCode": "#7c7c7d", - "cookieStoreId": "firefox-container-592" - }, - { - "name": "Oscar", - "icon": "dollar", - "iconUrl": "resource://usercontext-content/dollar.svg", - "color": "green", - "colorCode": "#51cd00", - "cookieStoreId": "firefox-container-593" - } - ], - "cookieStoreIDmap": { - "firefox-container-588": "d20d7af2-9866-468e-bb43-541efe8c2c2e", - "firefox-container-589": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", - "firefox-container-590": "32cc4a9b-05ed-4e54-8e11-732468de62f4", - "firefox-container-591": "9ff381e3-4c11-420d-8e12-e352a3318be1", - "firefox-container-592": "3dc916fb-8c0a-4538-9758-73ef819a45f7", - "firefox-container-593": "63e5212f-0858-418e-b5a3-09c2dea61fcd" + "identity@@_d20d7af2-9866-468e-bb43-541efe8c2c2e": { + "name": "Personal", + "icon": "fingerprint", + "color": "red", + "cookieStoreId": "firefox-container-588", + "macAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e" }, - "assignedSites": { - "siteContainerMap@@_developer.mozilla.org": { - "userContextId": "588", - "neverAsk": true, - "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", - "hostname": "developer.mozilla.org" - }, - "siteContainerMap@@_reddit.com": { - "userContextId": "592", - "neverAsk": true, - "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", - "hostname": "reddit.com" - }, - "siteContainerMap@@_twitter.com": { - "userContextId": "589", - "neverAsk": true, - "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", - "hostname": "twitter.com" - }, - "siteContainerMap@@_www.facebook.com": { - "userContextId": "590", - "neverAsk": true, - "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", - "hostname": "www.facebook.com" - }, - "siteContainerMap@@_www.linkedin.com": { - "userContextId": "591", - "neverAsk": true, - "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", - "hostname": "www.linkedin.com" - } + "identity@@_cdd73c20-c26a-4c06-9b17-735c1f5e9187": { + "name": "Big Bird", + "icon": "pet", + "color": "yellow", + "cookieStoreId": "firefox-container-589", + "macAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187" + }, + "identity@@_32cc4a9b-05ed-4e54-8e11-732468de62f4": { + "name": "Mozilla", + "icon": "pet", + "color": "red", + "cookieStoreId": "firefox-container-590", + "macAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4" + }, + "identity@@_9ff381e3-4c11-420d-8e12-e352a3318be1": { + "name": "Groceries, obviously", + "icon": "cart", + "color": "pink", + "cookieStoreId": "firefox-container-591", + "macAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1" + }, + "identity@@_3dc916fb-8c0a-4538-9758-73ef819a45f7": { + "name": "Facebook", + "icon": "fence", + "color": "toolbar", + "cookieStoreId": "firefox-container-592", + "macAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7" + }, + "identity@@_63e5212f-0858-418e-b5a3-09c2dea61fcd": { + "name": "Oscar", + "icon": "dollar", + "color": "green", + "cookieStoreId": "firefox-container-593", + "macAddonUUID": "63e5212f-0858-418e-b5a3-09c2dea61fcd" + }, + "siteContainerMap@@_developer.mozilla.org": { + "userContextId": "588", + "neverAsk": true, + "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", + "hostname": "developer.mozilla.org" + }, + "siteContainerMap@@_reddit.com": { + "userContextId": "592", + "neverAsk": true, + "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", + "hostname": "reddit.com" + }, + "siteContainerMap@@_twitter.com": { + "userContextId": "589", + "neverAsk": true, + "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", + "hostname": "twitter.com" + }, + "siteContainerMap@@_www.facebook.com": { + "userContextId": "590", + "neverAsk": true, + "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", + "hostname": "www.facebook.com" + }, + "siteContainerMap@@_www.linkedin.com": { + "userContextId": "591", + "neverAsk": true, + "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", + "hostname": "www.linkedin.com" } }; From 268c638508d4c77c1f5a0be8392083b9a50519f6 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 23 Jan 2020 00:27:05 -0600 Subject: [PATCH 42/60] added onboarding panel --- src/css/popup.css | 6 ++++++ src/js/popup.js | 39 ++++++++++++++++++++++++++++++++++++++- src/popup.html | 10 +++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/css/popup.css b/src/css/popup.css index d5f3295..f18294f 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -974,3 +974,9 @@ span ~ .panel-header-text { .amo-rate-cta { background: #0f1126; } + +.no-sync { + margin-left: 160px; + line-height: 0px; + text-decoration: underline; +} \ No newline at end of file diff --git a/src/js/popup.js b/src/js/popup.js index d4ec8c9..9fd9e2e 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -17,6 +17,7 @@ const P_ONBOARDING_2 = "onboarding2"; const P_ONBOARDING_3 = "onboarding3"; const P_ONBOARDING_4 = "onboarding4"; const P_ONBOARDING_5 = "onboarding5"; +const P_ONBOARDING_6 = "onboarding6"; const P_CONTAINERS_LIST = "containersList"; const P_CONTAINERS_EDIT = "containersEdit"; const P_CONTAINER_INFO = "containerInfo"; @@ -99,9 +100,12 @@ const Logic = { } switch (onboarded) { - case 5: + case 6: this.showAchievementOrContainersListPanel(); break; + case 5: + this.showPanel(P_ONBOARDING_6); + break; case 4: this.showPanel(P_ONBOARDING_5); break; @@ -503,6 +507,39 @@ Logic.registerPanel(P_ONBOARDING_5, { // Let's move to the containers list panel. Logic.addEnterHandler(document.querySelector("#onboarding-longpress-button"), async () => { await Logic.setOnboardingStage(5); + Logic.showPanel(P_ONBOARDING_6); + }); + }, + + // This method is called when the panel is shown. + prepare() { + return Promise.resolve(null); + }, +}); + +// P_ONBOARDING_6: Sixth page for Onboarding: new tab long-press behavior +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_ONBOARDING_6, { + panelSelector: ".onboarding-panel-6", + + // This method is called when the object is registered. + initialize() { + // Let's move to the containers list panel. + Logic.addEnterHandler(document.querySelector("#start-sync-button"), async () => { + await Logic.setOnboardingStage(6); + await browser.storage.local.set({syncEnabled: true}); + await browser.runtime.sendMessage({ + method: "resetSync" + }); + Logic.showPanel(P_CONTAINERS_LIST); + }); + Logic.addEnterHandler(document.querySelector("#no-sync"), async () => { + await Logic.setOnboardingStage(6); + await browser.storage.local.set({syncEnabled: false}); + await browser.runtime.sendMessage({ + method: "resetSync" + }); Logic.showPanel(P_CONTAINERS_LIST); }); }, diff --git a/src/popup.html b/src/popup.html index cf9878f..8f438c6 100644 --- a/src/popup.html +++ b/src/popup.html @@ -64,7 +64,15 @@ Long-press the New Tab button to create a new container tab.

Container tabs when you need them.

Long-press the New Tab button to create a new container tab.

- Done + Next + + +
+ Click below to start syncing +

Container and site assignments everywhere.

+

Now containers will sync between installs of the add-on.

+ Start Syncing +
From 85c403bef5c8853a786ff6df443564b219547013 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 23 Jan 2020 10:08:12 -0600 Subject: [PATCH 43/60] made some suggested changes --- package.json | 2 +- src/css/popup.css | 4 ++-- src/js/background/assignManager.js | 4 ++-- src/js/background/backgroundLogic.js | 2 +- src/js/background/identityState.js | 16 ++++++++-------- src/js/background/sync.js | 22 +++++++++++----------- src/js/popup.js | 12 ++++++------ src/manifest.json | 2 +- test/features/sync.test.js | 9 ++++----- test/helper.js | 10 ++++++---- 10 files changed, 42 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 2e36b25..d4493b3 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "dependencies": {}, "devDependencies": { "addons-linter": "^1.3.2", - "ajv": "^6.6.2", + "ajv": "^6.6.3", "chai": "^4.2.0", "eslint": "^6.6.0", "eslint-plugin-no-unsanitized": "^2.0.0", diff --git a/src/css/popup.css b/src/css/popup.css index f18294f..4de07a9 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -976,7 +976,7 @@ span ~ .panel-header-text { } .no-sync { + line-height: 0; margin-left: 160px; - line-height: 0px; text-decoration: underline; -} \ No newline at end of file +} diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index a9493c0..a8f22e3 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -418,7 +418,7 @@ const assignManager = { const [bookmarkTreeNode] = await browser.bookmarks.get(info.bookmarkId); if (bookmarkTreeNode.type === "folder") { - return await browser.bookmarks.getChildren(bookmarkTreeNode.id); + return browser.bookmarks.getChildren(bookmarkTreeNode.id); } return [bookmarkTreeNode]; } @@ -515,7 +515,7 @@ const assignManager = { // Ensure we have a cookieStore to assign to if (cookieStore && this.isTabPermittedAssign(tab)) { - return await this.storageArea.get(tab.url); + return this.storageArea.get(tab.url); } return false; }, diff --git a/src/js/background/backgroundLogic.js b/src/js/background/backgroundLogic.js index 5d71fec..96e7939 100644 --- a/src/js/background/backgroundLogic.js +++ b/src/js/background/backgroundLogic.js @@ -324,7 +324,7 @@ const backgroundLogic = { containerState.hiddenTabs = []; await Promise.all(promises); - return await identityState.storageArea.set(options.cookieStoreId, containerState); + return identityState.storageArea.set(options.cookieStoreId, containerState); }, cookieStoreId(userContextId) { diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 9ae8403..f985e17 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -39,7 +39,7 @@ const identityState = { async remove(cookieStoreId) { const storeKey = this.getContainerStoreKey(cookieStoreId); - return await this.area.remove([storeKey]); + return this.area.remove([storeKey]); }, /* @@ -107,13 +107,13 @@ const identityState = { }, async updateUUID(cookieStoreId, uuid) { - if (cookieStoreId && uuid) { - const containerState = await this.storageArea.get(cookieStoreId); - containerState.macAddonUUID = uuid; - await this.storageArea.set(cookieStoreId, containerState); - return uuid; - } - throw new Error ("cookieStoreId or uuid missing"); + if (!cookieStoreId || !uuid) { + throw new Error ("cookieStoreId or uuid missing"); + } + const containerState = await this.storageArea.get(cookieStoreId); + containerState.macAddonUUID = uuid; + await this.storageArea.set(cookieStoreId, containerState); + return uuid; }, async addUUID(cookieStoreId) { diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 2cfddc7..8855aff 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -5,11 +5,11 @@ const sync = { area: browser.storage.sync, async get(){ - return await this.area.get(); + return this.area.get(); }, async set(options) { - return await this.area.set(options); + return this.area.set(options); }, async deleteIdentity(deletedIdentityUUID) { @@ -87,7 +87,7 @@ const sync = { .replace(/\//, ""); }, async removeInstance(installUUID) { - console.log("removing", installUUID); + if (SYNC_DEBUG) console.log("removing", installUUID); await this.area.remove(installUUID); return; }, @@ -118,7 +118,7 @@ const sync = { await this.deleteSite(options.siteStoreKey); if (options && options.undeleteSiteStoreKey) await removeFromDeletedSitesList(options.undeleteSiteStoreKey); - console.log("Backed up!"); + if (SYNC_DEBUG) console.log("Backed up!"); await sync.checkForListenersMaybeAdd(); async function updateSyncIdentities() { @@ -150,7 +150,7 @@ const sync = { const date = new Date(); const timestamp = date.getTime(); const installUUID = sync.storageArea.getInstanceKey(); - console.log("adding", installUUID); + if (SYNC_DEBUG) console.log("adding", installUUID); const identities = []; const siteAssignments = []; for (const identity of identitiesInput) { @@ -208,7 +208,7 @@ const sync = { async errorHandledRunSync () { await sync.runSync().catch( async (error)=> { - console.error("Error from runSync", error); + if (SYNC_DEBUG) console.error("Error from runSync", error); await sync.checkForListenersMaybeAdd(); }); }, @@ -257,7 +257,7 @@ const sync = { console.log("Initial State:", {syncInfo, localInfo, idents}); } await sync.checkForListenersMaybeRemove(); - console.log("runSync"); + if (SYNC_DEBUG) console.log("runSync"); await identityState.storageArea.upgradeData(); await assignManager.storageArea.upgradeData(); @@ -308,7 +308,7 @@ const sync = { sync.init(); async function restore() { - console.log("restore"); + if (SYNC_DEBUG) console.log("restore"); await reconcileIdentities(); await reconcileSiteAssignments(); return; @@ -320,7 +320,7 @@ async function restore() { * different. */ async function reconcileIdentities(){ - console.log("reconcileIdentities"); + if (SYNC_DEBUG) console.log("reconcileIdentities"); // first delete any from the deleted list const deletedIdentityList = @@ -443,7 +443,7 @@ async function ifUUIDMatch(syncIdentity, localCookieStoreID) { async function ifNoMatch(syncIdentity){ // if no uuid match either, make new identity - console.log("create new ident: ", syncIdentity.name); + if (SYNC_DEBUG) console.log("create new ident: ", syncIdentity.name); const newIdentity = await browser.contextualIdentities.create({ name: syncIdentity.name, @@ -463,7 +463,7 @@ async function ifNoMatch(syncIdentity){ * If it does not exist, it is created. */ async function reconcileSiteAssignments() { - console.log("reconcileSiteAssignments"); + if (SYNC_DEBUG) console.log("reconcileSiteAssignments"); const assignedSitesLocal = await assignManager.storageArea.getAssignedSites(); const assignedSitesFromSync = diff --git a/src/js/popup.js b/src/js/popup.js index 9fd9e2e..09611c3 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -187,7 +187,7 @@ const Logic = { }; // Handle old style rejection with null and also Promise.reject new style try { - return await browser.contextualIdentities.get(cookieStoreId) || defaultContainer; + return browser.contextualIdentities.get(cookieStoreId) || defaultContainer; } catch (e) { return defaultContainer; } @@ -357,12 +357,12 @@ const Logic = { getAssignmentObjectByContainer(userContextId) { if (userContextId) { - return browser.runtime.sendMessage({ - method: "getAssignmentObjectByContainer", - message: { userContextId } - }); + return {}; } - return {}; + return browser.runtime.sendMessage({ + method: "getAssignmentObjectByContainer", + message: { userContextId } + }); }, setOrRemoveAssignment(tabId, url, userContextId, value) { diff --git a/src/manifest.json b/src/manifest.json index 285388d..92fa1e2 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Firefox Multi-Account Containers", - "version": "6.1.1", + "version": "6.1.3", "incognito": "not_allowed", "description": "Multi-Account Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", "icons": { diff --git a/test/features/sync.test.js b/test/features/sync.test.js index 61915e1..fdfa1b8 100644 --- a/test/features/sync.test.js +++ b/test/features/sync.test.js @@ -8,7 +8,6 @@ describe("Sync", () => { color: "red", icon: "briefcase", }); - await background.browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); await background.browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); @@ -53,13 +52,13 @@ describe("Sync", () => { }); } })); - await background.browser.runtime.onStartup.addListener.yield(); + + // await background.browser.storage.onChanged.addListener.yield(); await nextTick(); const sync = await background.browser.storage.sync.get(); - console.log(await background.browser.storage.local.get()); - - expect(sync.identities.length).to.equal(5); + console.log("sync", sync); + // expect(sync.length).to.equal(4); }); }); \ No newline at end of file diff --git a/test/helper.js b/test/helper.js index f14ed81..24363a6 100644 --- a/test/helper.js +++ b/test/helper.js @@ -15,8 +15,9 @@ module.exports = { beforeParse(window) { window.browser.storage.local.set({ "browserActionBadgesClicked": [], - "onboarding-stage": 5, - "achievements": [] + "onboarding-stage": 6, + "achievements": [], + "syncEnabled": true }); window.browser.storage.local.set.resetHistory(); window.browser.storage.sync.clear(); @@ -37,8 +38,9 @@ module.exports = { if (!details.localStorage) { details.localStorage = { "browserActionBadgesClicked": [], - "onboarding-stage": 5, - "achievements": [] + "onboarding-stage": 6, + "achievements": [], + "syncEnabled": true }; } if (!details.syncStorage) details.syncStorage = {}; From f98120092180d58f41026f47cd1fb449c7def12b Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 23 Jan 2020 10:23:07 -0600 Subject: [PATCH 44/60] Update src/js/background/identityState.js Co-Authored-By: Jonathan Kingston --- src/js/background/identityState.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index f985e17..673c0a2 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -127,7 +127,7 @@ const identityState = { cookieStoreId : "firefox-container-" + cookieStoreId; const macConfigs = await this.storageArea.area.get(); for(const configKey of Object.keys(macConfigs)) { - if (configKey === "identitiesState@@_" + cookieStoreIdKey) { + if (configKey === this.getContainerStoreKey(cookieStoreIdKey)) { return macConfigs[configKey].macAddonUUID; } } From d35712e9f9367a8b9555e8f044c04b0210cf48e9 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 23 Jan 2020 10:23:17 -0600 Subject: [PATCH 45/60] Update src/js/background/sync.js Co-Authored-By: Jonathan Kingston --- src/js/background/sync.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 8855aff..1b72b31 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -34,7 +34,7 @@ const sync = { async getDeletedIdentityList() { const storedArray = await this.getStoredItem("deletedIdentityList"); - return (storedArray) ? storedArray : []; + return storedArray || []; }, async getIdentities() { From 5b8cfa14ae53df5102491e7d58656bfc5b1d6c5d Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 23 Jan 2020 10:29:37 -0600 Subject: [PATCH 46/60] Update src/js/background/sync.js Co-Authored-By: Jonathan Kingston --- src/js/background/sync.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 1b72b31..d79c16b 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -540,7 +540,7 @@ async function removeOldDeletedItems() { } } -async function setAssignmentWithUUID (assignedSite, urlKey) { +async function setAssignmentWithUUID(assignedSite, urlKey) { const uuid = assignedSite.identityMacAddonUUID; const cookieStoreId = await identityState.lookupCookieStoreId(uuid); if (cookieStoreId) { From 0447e54b1c07ba1e456b44efc83feaa83853262d Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 23 Jan 2020 13:47:19 -0600 Subject: [PATCH 47/60] review fedback --- src/js/background/assignManager.js | 6 ++-- src/js/background/identityState.js | 14 ++++++---- src/js/background/sync.js | 44 +++++++++++++----------------- src/js/options.js | 1 - src/js/popup.js | 4 +-- 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index a8f22e3..91ff8e6 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -78,7 +78,9 @@ const assignManager = { [siteStoreKey]: data }); const syncEnabled = await this.getSyncEnabled(); - if (backup && syncEnabled) await sync.storageArea.backup({undeleteSiteStoreKey: siteStoreKey}); + if (backup && syncEnabled) { + await sync.storageArea.backup({undeleteSiteStoreKey: siteStoreKey}); + } return; }, @@ -135,7 +137,7 @@ const assignManager = { localIdentity => localIdentity.cookieStoreId === cookieStoreId ); if (!match) { - await this.remove(configKey.replace(/^siteContainerMap@@_/, "https://")); + await this.remove(configKey); continue; } const updatedSiteAssignment = macConfigs[configKey]; diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 673c0a2..9ff2bb2 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -49,6 +49,12 @@ const identityState = { */ async upgradeData() { const identitiesList = await browser.contextualIdentities.query({}); + + for (const identity of identitiesList) { + // ensure all identities have an entry in local storage + await identityState.addUUID(identity.cookieStoreId); + } + const macConfigs = await this.area.get(); for(const configKey of Object.keys(macConfigs)) { if (configKey.includes("identitiesState@@_")) { @@ -61,16 +67,12 @@ const identityState = { await this.remove(cookieStoreId); continue; } + console.log(macConfigs, configKey); if (!macConfigs[configKey].macAddonUUID) { await identityState.storageArea.get(cookieStoreId); } } } - - for (const identity of identitiesList) { - // ensure all identities have an entry in local storage - await identityState.addUUID(identity.cookieStoreId); - } } }, @@ -127,7 +129,7 @@ const identityState = { cookieStoreId : "firefox-container-" + cookieStoreId; const macConfigs = await this.storageArea.area.get(); for(const configKey of Object.keys(macConfigs)) { - if (configKey === this.getContainerStoreKey(cookieStoreIdKey)) { + if (configKey === this.storageArea.getContainerStoreKey(cookieStoreIdKey)) { return macConfigs[configKey].macAddonUUID; } } diff --git a/src/js/background/sync.js b/src/js/background/sync.js index d79c16b..9546d7c 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -118,6 +118,7 @@ const sync = { await this.deleteSite(options.siteStoreKey); if (options && options.undeleteSiteStoreKey) await removeFromDeletedSitesList(options.undeleteSiteStoreKey); + if (SYNC_DEBUG) console.log("Backed up!"); await sync.checkForListenersMaybeAdd(); @@ -270,26 +271,23 @@ const sync = { return; }, - async addContextualIdentityListeners(listenerList) { - if(!listenerList) listenerList = syncCIListenerList; - await browser.contextualIdentities.onCreated.addListener(listenerList[0]); - await browser.contextualIdentities.onRemoved.addListener(listenerList[1]); - await browser.contextualIdentities.onUpdated.addListener(listenerList[2]); + async addContextualIdentityListeners() { + await browser.contextualIdentities.onCreated.addListener(sync.storageArea.backup); + await browser.contextualIdentities.onRemoved.addListener(sync.storageArea.addToDeletedList); + await browser.contextualIdentities.onUpdated.addListener(sync.storageArea.backup); }, - async removeContextualIdentityListeners(listenerList) { - if(!listenerList) listenerList = syncCIListenerList; - await browser.contextualIdentities.onCreated.removeListener(listenerList[0]); - await browser.contextualIdentities.onRemoved.removeListener(listenerList[1]); - await browser.contextualIdentities.onUpdated.removeListener(listenerList[2]); + async removeContextualIdentityListeners() { + await browser.contextualIdentities.onCreated.removeListener(sync.storageArea.backup); + await browser.contextualIdentities.onRemoved.removeListener(sync.storageArea.addToDeletedList); + await browser.contextualIdentities.onUpdated.removeListener(sync.storageArea.backup); }, - async hasContextualIdentityListeners(listenerList) { - if(!listenerList) listenerList = syncCIListenerList; + async hasContextualIdentityListeners() { return ( - await browser.contextualIdentities.onCreated.hasListener(listenerList[0]) && - await browser.contextualIdentities.onRemoved.hasListener(listenerList[1]) && - await browser.contextualIdentities.onUpdated.hasListener(listenerList[2]) + await browser.contextualIdentities.onCreated.hasListener(sync.storageArea.backup) && + await browser.contextualIdentities.onRemoved.hasListener(sync.storageArea.addToDeletedList) && + await browser.contextualIdentities.onUpdated.hasListener(sync.storageArea.backup) ); }, @@ -360,7 +358,9 @@ async function reconcileIdentities(){ await ifNoMatch(syncIdentity); continue; } - await ifNamesMatch(syncIdentity, localMatch); + + // Names match, so use the info from Sync + await updateIdentityWithSyncInfo(syncIdentity, localMatch); continue; } // if no macAddonUUID, there is a problem with the sync info and it needs to be ignored. @@ -376,7 +376,7 @@ async function reconcileIdentities(){ } } -async function ifNamesMatch(syncIdentity, localMatch) { +async function updateIdentityWithSyncInfo(syncIdentity, localMatch) { // Sync is truth. if there is a match, compare data and update as needed if (syncIdentity.color !== localMatch.color || syncIdentity.icon !== localMatch.icon) { @@ -474,7 +474,7 @@ async function reconcileSiteAssignments() { if (Object.prototype.hasOwnProperty.call(assignedSitesLocal,siteStoreKey)) { assignManager .storageArea - .remove(siteStoreKey.replace(/^siteContainerMap@@_/, "https://")); + .remove(siteStoreKey); } } @@ -548,7 +548,7 @@ async function setAssignmentWithUUID(assignedSite, urlKey) { assignedSite.userContextId = cookieStoreId .replace(/^firefox-container-/, ""); await assignManager.storageArea.set( - urlKey.replace(/^siteContainerMap@@_/, "https://"), + urlKey, assignedSite, false, false @@ -557,9 +557,3 @@ async function setAssignmentWithUUID(assignedSite, urlKey) { } throw new Error (`No cookieStoreId found for: ${uuid}, ${urlKey}`); } - -const syncCIListenerList = [ - sync.storageArea.backup, - sync.storageArea.addToDeletedList, - sync.storageArea.backup -]; diff --git a/src/js/options.js b/src/js/options.js index 2f3fa32..c225e63 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -25,7 +25,6 @@ async function enableDisableSync() { async function restoreOptions() { const hasPermission = await browser.permissions.contains({permissions: ["bookmarks"]}); const { syncEnabled } = await browser.storage.local.get("syncEnabled"); - console.log(syncEnabled); if (hasPermission) { document.querySelector("#bookmarksPermissions").checked = true; } diff --git a/src/js/popup.js b/src/js/popup.js index 09611c3..208b18b 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -187,7 +187,7 @@ const Logic = { }; // Handle old style rejection with null and also Promise.reject new style try { - return browser.contextualIdentities.get(cookieStoreId) || defaultContainer; + return await browser.contextualIdentities.get(cookieStoreId) || defaultContainer; } catch (e) { return defaultContainer; } @@ -356,7 +356,7 @@ const Logic = { }, getAssignmentObjectByContainer(userContextId) { - if (userContextId) { + if (!userContextId) { return {}; } return browser.runtime.sendMessage({ From 53baee1d5c9265c8bdcc32d87e176027c7ea4d67 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 24 Jan 2020 17:02:29 -0600 Subject: [PATCH 48/60] swapped cookieStoreId and storekey --- src/js/background/identityState.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 9ff2bb2..2525f57 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -13,7 +13,7 @@ const identityState = { if (storageResponse && storeKey in storageResponse) { if (!storageResponse[storeKey].macAddonUUID){ storageResponse[storeKey].macAddonUUID = uuidv4(); - await this.set(cookieStoreId, storageResponse[cookieStoreId]); + await this.set(cookieStoreId, storageResponse[storeKey]); } return storageResponse[storeKey]; } @@ -67,7 +67,6 @@ const identityState = { await this.remove(cookieStoreId); continue; } - console.log(macConfigs, configKey); if (!macConfigs[configKey].macAddonUUID) { await identityState.storageArea.get(cookieStoreId); } From d7b1e7274f65957d1453563b64f9bd5c71494ed7 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 24 Jan 2020 17:18:31 -0600 Subject: [PATCH 49/60] verison bump for beta --- package.json | 2 +- src/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d4493b3..2375323 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "testpilot-containers", "title": "Multi-Account Containers", "description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", - "version": "6.1.2", + "version": "6.1.4", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/multi-account-containers/issues" diff --git a/src/manifest.json b/src/manifest.json index 92fa1e2..7d36ec0 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Firefox Multi-Account Containers", - "version": "6.1.3", + "version": "6.1.4", "incognito": "not_allowed", "description": "Multi-Account Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", "icons": { From 405e605ba3812a6b6b47a9d8323f2c4390c3dba6 Mon Sep 17 00:00:00 2001 From: stoically Date: Fri, 24 Jan 2020 08:16:15 +0100 Subject: [PATCH 50/60] Refactor tests to not rely on globals --- package.json | 11 +- test/.eslintrc.js | 12 +- test/{setup.js => common.js} | 70 +++++++--- test/features/assignment.test.js | 51 +++---- test/features/containers.test.js | 38 ++--- test/features/external-webextensions.test.js | 31 +++-- test/features/sync.test.js | 64 --------- test/helper.js | 81 ----------- test/issues/1168.test.js | 28 ++-- test/issues/940.test.js | 138 ++++++++++--------- 10 files changed, 213 insertions(+), 311 deletions(-) rename test/{setup.js => common.js} (51%) delete mode 100644 test/features/sync.test.js delete mode 100644 test/helper.js diff --git a/package.json b/package.json index d4493b3..ecd32c5 100644 --- a/package.json +++ b/package.json @@ -19,14 +19,14 @@ "json": "^9.0.6", "mocha": "^6.2.2", "npm-run-all": "^4.0.0", - "nyc": "^14.1.1", + "nyc": "^15.0.0", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", "stylelint": "^7.9.0", "stylelint-config-standard": "^16.0.0", "stylelint-order": "^0.3.0", "web-ext": "^2.9.3", - "webextensions-jsdom": "^1.1.0" + "webextensions-jsdom": "^1.2.1" }, "homepage": "https://github.com/mozilla/multi-account-containers#readme", "license": "MPL-2.0", @@ -44,9 +44,8 @@ "lint:js": "eslint .", "package": "rm -rf src/web-ext-artifacts && npm run build && mv src/web-ext-artifacts/firefox_multi-account_containers-*.zip addon.xpi", "test": "npm run lint && npm run coverage", - "mocha": "mocha ./test/setup.js test/**/*.test.js", - "mochaSingle": "mocha ./test/setup.js", - "test-watch": "mocha ./test/setup.js test/**/*.test.js --watch", - "coverage": "nyc --reporter=html --reporter=text mocha ./test/setup.js test/**/*.test.js --timeout 60000" + "test:once": "mocha test/**/*.test.js", + "test:watch": "npm run test:once -- --watch", + "coverage": "nyc --reporter=html --reporter=text mocha test/**/*.test.js --timeout 60000" } } diff --git a/test/.eslintrc.js b/test/.eslintrc.js index d32e265..6d733f0 100644 --- a/test/.eslintrc.js +++ b/test/.eslintrc.js @@ -6,15 +6,7 @@ module.exports = { "parserOptions": { "ecmaVersion": 2018 }, - globals: { - "sinon": false, - "expect": false, - "nextTick": false, - "buildDom": false, - "buildBackgroundDom": false, - "background": false, - "buildPopupDom": false, - "popup": false, - "helper": false + "rules": { + "no-restricted-globals": ["error", "browser"] } } diff --git a/test/setup.js b/test/common.js similarity index 51% rename from test/setup.js rename to test/common.js index b674ba0..b87fe1c 100644 --- a/test/setup.js +++ b/test/common.js @@ -2,15 +2,16 @@ if (!process.listenerCount("unhandledRejection")) { // eslint-disable-next-line no-console process.on("unhandledRejection", r => console.log(r)); } + const path = require("path"); const chai = require("chai"); const sinonChai = require("sinon-chai"); const crypto = require("crypto"); -global.sinon = require("sinon"); -global.expect = chai.expect; +const sinon = require("sinon"); +const expect = chai.expect; chai.should(); chai.use(sinonChai); -global.nextTick = () => { +const nextTick = () => { return new Promise(resolve => { setTimeout(() => { process.nextTick(resolve); @@ -18,12 +19,10 @@ global.nextTick = () => { }); }; -global.helper = require("./helper"); - const webExtensionsJSDOM = require("webextensions-jsdom"); const manifestPath = path.resolve(path.join(__dirname, "../src/manifest.json")); -global.buildDom = async ({background = {}, popup = {}}) => { +const buildDom = async ({background = {}, popup = {}}) => { background = { ...background, jsdom: { @@ -53,33 +52,60 @@ global.buildDom = async ({background = {}, popup = {}}) => { popup }); - // eslint-disable-next-line require-atomic-updates - global.background = webExtension.background; - // eslint-disable-next-line require-atomic-updates - global.popup = webExtension.popup; + webExtension.browser = webExtension.background.browser; + return webExtension; }; -global.buildBackgroundDom = async background => { - await global.buildDom({ +const buildBackgroundDom = background => { + return buildDom({ background, popup: false }); }; -global.buildPopupDom = async popup => { - await global.buildDom({ +const buildPopupDom = popup => { + return buildDom({ popup, background: false }); }; +const initializeWithTab = async (details = { + cookieStoreId: "firefox-default" +}) => { + let tab; + const webExtension = await buildDom({ + background: { + async afterBuild(background) { + tab = await background.browser.tabs._create(details); + } + }, + popup: { + jsdom: { + beforeParse(window) { + window.browser.storage.local.set({ + "browserActionBadgesClicked": [], + "onboarding-stage": 6, + "achievements": [], + "syncEnabled": true + }); + window.browser.storage.local.set.resetHistory(); + window.browser.storage.sync.clear(); + } + } + } + }); + webExtension.tab = tab; -global.afterEach(() => { - if (global.background) { - global.background.destroy(); - } + return webExtension; +}; - if (global.popup) { - global.popup.destroy(); - } -}); +module.exports = { + buildDom, + buildBackgroundDom, + buildPopupDom, + initializeWithTab, + sinon, + expect, + nextTick, +}; \ No newline at end of file diff --git a/test/features/assignment.test.js b/test/features/assignment.test.js index 43bb981..ca50f49 100644 --- a/test/features/assignment.test.js +++ b/test/features/assignment.test.js @@ -1,25 +1,30 @@ -describe("Assignment Feature", () => { +const {initializeWithTab} = require("../common"); + +describe("Assignment Feature", function () { const url = "http://example.com"; - let activeTab; - beforeEach(async () => { - activeTab = await helper.browser.initializeWithTab({ + beforeEach(async function () { + this.webExt = await initializeWithTab({ cookieStoreId: "firefox-container-1", url }); }); - describe("click the 'Always open in' checkbox in the popup", () => { - beforeEach(async () => { + afterEach(function () { + this.webExt.destroy(); + }); + + describe("click the 'Always open in' checkbox in the popup", function () { + beforeEach(async function () { // popup click to set assignment for activeTab.url - await helper.popup.clickElementById("container-page-assigned"); + await this.webExt.popup.helper.clickElementById("container-page-assigned"); }); - describe("open new Tab with the assigned URL in the default container", () => { + describe("open new Tab with the assigned URL in the default container", function () { let newTab; - beforeEach(async () => { + beforeEach(async function () { // new Tab opening activeTab.url in default container - newTab = await helper.browser.openNewTab({ + newTab = await this.webExt.background.browser.tabs._create({ cookieStoreId: "firefox-default", url }, { @@ -29,12 +34,12 @@ describe("Assignment Feature", () => { }); }); - it("should open the confirm page", async () => { + it("should open the confirm page", async function () { // should have created a new tab with the confirm page - background.browser.tabs.create.should.have.been.calledWithMatch({ + this.webExt.background.browser.tabs.create.should.have.been.calledWithMatch({ url: "moz-extension://fake/confirm-page.html?" + `url=${encodeURIComponent(url)}` + - `&cookieStoreId=${activeTab.cookieStoreId}`, + `&cookieStoreId=${this.webExt.tab.cookieStoreId}`, cookieStoreId: undefined, openerTabId: null, index: 2, @@ -42,29 +47,29 @@ describe("Assignment Feature", () => { }); }); - it("should remove the new Tab that got opened in the default container", () => { - background.browser.tabs.remove.should.have.been.calledWith(newTab.id); + it("should remove the new Tab that got opened in the default container", function () { + this.webExt.background.browser.tabs.remove.should.have.been.calledWith(newTab.id); }); }); - describe("click the 'Always open in' checkbox in the popup again", () => { - beforeEach(async () => { + describe("click the 'Always open in' checkbox in the popup again", function () { + beforeEach(async function () { // popup click to remove assignment for activeTab.url - await helper.popup.clickElementById("container-page-assigned"); + await this.webExt.popup.helper.clickElementById("container-page-assigned"); }); - describe("open new Tab with the no longer assigned URL in the default container", () => { - beforeEach(async () => { + describe("open new Tab with the no longer assigned URL in the default container", function () { + beforeEach(async function () { // new Tab opening activeTab.url in default container - await helper.browser.openNewTab({ + await this.webExt.background.browser.tabs._create({ cookieStoreId: "firefox-default", url }); }); - it("should not open the confirm page", async () => { + it("should not open the confirm page", async function () { // should not have created a new tab - background.browser.tabs.create.should.not.have.been.called; + this.webExt.background.browser.tabs.create.should.not.have.been.called; }); }); }); diff --git a/test/features/containers.test.js b/test/features/containers.test.js index ac5bccd..d50a6b8 100644 --- a/test/features/containers.test.js +++ b/test/features/containers.test.js @@ -1,27 +1,33 @@ -describe("Containers Management", () => { - beforeEach(async () => { - await helper.browser.initializeWithTab(); +const {initializeWithTab} = require("../common"); + +describe("Containers Management", function () { + beforeEach(async function () { + this.webExt = await initializeWithTab(); }); - describe("creating a new container", () => { - beforeEach(async () => { - await helper.popup.clickElementById("container-add-link"); - await helper.popup.clickElementById("edit-container-ok-link"); + afterEach(function () { + this.webExt.destroy(); + }); + + describe("creating a new container", function () { + beforeEach(async function () { + await this.webExt.popup.helper.clickElementById("container-add-link"); + await this.webExt.popup.helper.clickElementById("edit-container-ok-link"); }); - it("should create it in the browser as well", () => { - background.browser.contextualIdentities.create.should.have.been.calledOnce; + it("should create it in the browser as well", function () { + this.webExt.background.browser.contextualIdentities.create.should.have.been.calledOnce; }); - describe("removing it afterwards", () => { - beforeEach(async () => { - await helper.popup.clickElementById("edit-containers-link"); - await helper.popup.clickLastMatchingElementByQuerySelector(".delete-container-icon"); - await helper.popup.clickElementById("delete-container-ok-link"); + describe("removing it afterwards", function () { + beforeEach(async function () { + await this.webExt.popup.helper.clickElementById("edit-containers-link"); + await this.webExt.popup.helper.clickElementByQuerySelectorAll(".delete-container-icon", "last"); + await this.webExt.popup.helper.clickElementById("delete-container-ok-link"); }); - it("should remove it in the browser as well", () => { - background.browser.contextualIdentities.remove.should.have.been.calledOnce; + it("should remove it in the browser as well", function () { + this.webExt.background.browser.contextualIdentities.remove.should.have.been.calledOnce; }); }); }); diff --git a/test/features/external-webextensions.test.js b/test/features/external-webextensions.test.js index 76db303..f3c6810 100644 --- a/test/features/external-webextensions.test.js +++ b/test/features/external-webextensions.test.js @@ -1,17 +1,24 @@ -describe("External Webextensions", () => { +const {expect, initializeWithTab} = require("../common"); + +describe("External Webextensions", function () { const url = "http://example.com"; - beforeEach(async () => { - await helper.browser.initializeWithTab({ + beforeEach(async function () { + this.webExt = await initializeWithTab({ cookieStoreId: "firefox-container-1", url }); - await helper.popup.clickElementById("container-page-assigned"); + + await this.webExt.popup.helper.clickElementById("container-page-assigned"); }); - describe("with contextualIdentities permissions", () => { - it("should be able to get assignments", async () => { - background.browser.management.get.resolves({ + afterEach(function () { + this.webExt.destroy(); + }); + + describe("with contextualIdentities permissions", function () { + it("should be able to get assignments", async function () { + this.webExt.background.browser.management.get.resolves({ permissions: ["contextualIdentities"] }); @@ -23,7 +30,7 @@ describe("External Webextensions", () => { id: "external-webextension" }; - const [promise] = background.browser.runtime.onMessageExternal.addListener.yield(message, sender); + const [promise] = this.webExt.background.browser.runtime.onMessageExternal.addListener.yield(message, sender); const answer = await promise; expect(answer.userContextId === "1").to.be.true; expect(answer.neverAsk === false).to.be.true; @@ -33,9 +40,9 @@ describe("External Webextensions", () => { }); }); - describe("without contextualIdentities permissions", () => { - it("should throw an error", async () => { - background.browser.management.get.resolves({ + describe("without contextualIdentities permissions", function () { + it("should throw an error", async function () { + this.webExt.background.browser.management.get.resolves({ permissions: [] }); @@ -47,7 +54,7 @@ describe("External Webextensions", () => { id: "external-webextension" }; - const [promise] = background.browser.runtime.onMessageExternal.addListener.yield(message, sender); + const [promise] = this.webExt.background.browser.runtime.onMessageExternal.addListener.yield(message, sender); return promise.catch(error => { expect(error.message).to.equal("Missing contextualIdentities permission"); }); diff --git a/test/features/sync.test.js b/test/features/sync.test.js deleted file mode 100644 index fdfa1b8..0000000 --- a/test/features/sync.test.js +++ /dev/null @@ -1,64 +0,0 @@ -describe("Sync", () => { - - it("should init sync on startup", async () => { - const tab = await helper.browser.initializeWithTab(); - console.log(await background.browser.storage.local.get()); - const mozContainer = await background.browser.contextualIdentities.create({ - name: "Mozilla", - color: "red", - icon: "briefcase", - }); - await background.browser.contextualIdentities.update("firefox-container-2", {color:"purple"}); - await background.browser.contextualIdentities.update("firefox-container-4", {icon:"pet"}); - - await Promise.all([ - { - userContextId: "1", - url: "https://twitter.com", - }, - { - userContextId: "2", - url: "https://www.facebook.com", - }, - { - userContextId: "4", - url: "https://www.linkedin.com", - neverAsk: true, - }, - { - userContextId: mozContainer.cookieStoreId.replace("firefox-container-", ""), - url: "https://developer.mozilla.org", - neverAsk: true, - } - ].map(async (assign) => { - await background.browser.tabs.update(tab.id, { - cookieStoreId: `firefox-container-${assign.userContextId}` - }); - - await background.browser.runtime.onMessage.addListener.yield({ - method: "setOrRemoveAssignment", - tabId: tab.id, - url: assign.url, - userContextId: assign.userContextId, - value: !true - }); - - if (assign.neverAsk) { - await nextTick(); - await background.browser.runtime.onMessage.addListener.yield({ - method: "neverAsk", - neverAsk: true, - pageUrl: assign.url, - }); - } - })); - - // await background.browser.storage.onChanged.addListener.yield(); - await nextTick(); - - const sync = await background.browser.storage.sync.get(); - console.log("sync", sync); - // expect(sync.length).to.equal(4); - }); - -}); \ No newline at end of file diff --git a/test/helper.js b/test/helper.js deleted file mode 100644 index 24363a6..0000000 --- a/test/helper.js +++ /dev/null @@ -1,81 +0,0 @@ -module.exports = { - browser: { - async initializeWithTab(details = { - cookieStoreId: "firefox-default" - }) { - let tab; - await buildDom({ - background: { - async afterBuild(background) { - tab = await background.browser.tabs._create(details); - } - }, - popup: { - jsdom: { - beforeParse(window) { - window.browser.storage.local.set({ - "browserActionBadgesClicked": [], - "onboarding-stage": 6, - "achievements": [], - "syncEnabled": true - }); - window.browser.storage.local.set.resetHistory(); - window.browser.storage.sync.clear(); - } - } - } - }); - - return tab; - }, - - async openNewTab(tab, options = {}) { - return background.browser.tabs._create(tab, options); - }, - - async initSyncTest(details = {}) { - if (!details.cookieStoreId) details.cookieStoreId = "firefox-default"; - if (!details.localStorage) { - details.localStorage = { - "browserActionBadgesClicked": [], - "onboarding-stage": 6, - "achievements": [], - "syncEnabled": true - }; - } - if (!details.syncStorage) details.syncStorage = {}; - let tab; - await buildDom({ - background: { - async afterBuild(background) { - tab = await background.browser.tabs._create({ cookieStoreId: details.cookieStoreId }); - } - }, - popup: { - jsdom: { - beforeParse(window) { - window.browser.storage.clear(); - window.browser.storage.local.set(details.localStorage); - window.browser.storage.local.set.resetHistory(); - window.browser.storage.sync.clear(); - window.browser.storage.sync.set(details.syncStorage); - window.browser.storage.sync.set.resetHistory(); - } - }, - } - }); - - return tab; - }, - }, - - popup: { - async clickElementById(id) { - await popup.helper.clickElementById(id); - }, - - async clickLastMatchingElementByQuerySelector(querySelector) { - await popup.helper.clickElementByQuerySelectorAll(querySelector, "last"); - } - } -}; diff --git a/test/issues/1168.test.js b/test/issues/1168.test.js index 50f463a..45d87e6 100644 --- a/test/issues/1168.test.js +++ b/test/issues/1168.test.js @@ -1,16 +1,19 @@ -describe("#1168", () => { - describe("when navigation happens too slow after opening new tab to a page which then redirects", () => { - let clock, tab; +const {expect, sinon, initializeWithTab} = require("../common"); - beforeEach(async () => { - await helper.browser.initializeWithTab({ +describe("#1168", function () { + describe("when navigation happens too slow after opening new tab to a page which then redirects", function () { + let clock, tab, background; + + beforeEach(async function () { + this.webExt = await initializeWithTab({ cookieStoreId: "firefox-container-1", url: "https://bugzilla.mozilla.org" }); - await helper.popup.clickElementById("container-page-assigned"); + + await this.webExt.popup.helper.clickElementById("container-page-assigned"); clock = sinon.useFakeTimers(); - tab = await helper.browser.openNewTab({}); + tab = await this.webExt.browser.tabs._create({}); clock.tick(2000); @@ -20,15 +23,16 @@ describe("#1168", () => { ]); }); + afterEach(function () { + this.webExt.destroy(); + clock.restore(); + }); + // Not solved yet // See: https://github.com/mozilla/multi-account-containers/issues/1168#issuecomment-378394091 - it.skip("should remove the old tab", async () => { + it.skip("should remove the old tab", async function () { expect(background.browser.tabs.create).to.have.been.calledOnce; expect(background.browser.tabs.remove).to.have.been.calledWith(tab.id); }); - - afterEach(() => { - clock.restore(); - }); }); }); \ No newline at end of file diff --git a/test/issues/940.test.js b/test/issues/940.test.js index 4a7eb0e..bbe4a64 100644 --- a/test/issues/940.test.js +++ b/test/issues/940.test.js @@ -1,15 +1,18 @@ -describe("#940", () => { - describe("when other onBeforeRequestHandlers are faster and redirect with the same requestId", () => { - it("should not open two confirm pages", async () => { - await helper.browser.initializeWithTab({ +const {expect, sinon, initializeWithTab} = require("../common"); + +describe("#940", function () { + describe("when other onBeforeRequestHandlers are faster and redirect with the same requestId", function () { + it("should not open two confirm pages", async function () { + const webExtension = await initializeWithTab({ cookieStoreId: "firefox-container-1", url: "http://example.com" }); - await helper.popup.clickElementById("container-page-assigned"); + + await webExtension.popup.helper.clickElementById("container-page-assigned"); const responses = {}; - await helper.browser.openNewTab({ - url: "http://example.com" + await webExtension.background.browser.tabs._create({ + url: "https://example.com" }, { options: { webRequestRedirects: ["https://example.com"], @@ -23,46 +26,55 @@ describe("#940", () => { expect(result).to.deep.equal({ cancel: true }); - background.browser.tabs.create.should.have.been.calledOnce; + webExtension.browser.tabs.create.should.have.been.calledOnce; + + webExtension.destroy(); }); }); - describe("when redirects change requestId midflight", () => { - let newTab; - const newTabResponses = {}; - const redirectedRequest = async (options = {}) => { - global.clock = sinon.useFakeTimers(); - newTab = await helper.browser.openNewTab({ - url: "http://youtube.com" - }, { - options: Object.assign({ - webRequestRedirects: [ - "https://youtube.com", - "https://www.youtube.com", - { - url: "https://www.youtube.com", - webRequest: { - requestId: 2 - } - } - ], - webRequestError: true, - instantRedirects: true - }, options), - responses: newTabResponses - }); - }; - - beforeEach(async () => { - await helper.browser.initializeWithTab({ + describe("when redirects change requestId midflight", function () { + beforeEach(async function () { + + this.webExt = await initializeWithTab({ cookieStoreId: "firefox-container-1", url: "https://www.youtube.com" }); - await helper.popup.clickElementById("container-page-assigned"); + await this.webExt.popup.helper.clickElementById("container-page-assigned"); + + global.clock = sinon.useFakeTimers(); + this.redirectedRequest = async (options = {}) => { + const newTabResponses = {}; + const newTab = await this.webExt.browser.tabs._create({ + url: "http://youtube.com" + }, { + options: Object.assign({ + webRequestRedirects: [ + "https://youtube.com", + "https://www.youtube.com", + { + url: "https://www.youtube.com", + webRequest: { + requestId: 2 + } + } + ], + webRequestError: true, + instantRedirects: true + }, options), + responses: newTabResponses + }); + + return [newTabResponses, newTab]; + }; }); - it("should not open two confirm pages", async () => { - await redirectedRequest(); + afterEach(function () { + this.webExt.destroy(); + global.clock.restore(); + }); + + it("should not open two confirm pages", async function () { + const [newTabResponses] = await this.redirectedRequest(); // http://youtube.com is not assigned, no cancel, no reopening expect(await newTabResponses.webRequest.onBeforeRequest[0]).to.deep.equal({}); @@ -80,17 +92,17 @@ describe("#940", () => { cancel: true }); - background.browser.tabs.create.should.have.been.calledOnce; + this.webExt.background.browser.tabs.create.should.have.been.calledOnce; }); - it("should uncancel after webRequest.onCompleted", async () => { - await redirectedRequest(); + it("should uncancel after webRequest.onCompleted", async function () { + const [newTabResponses, newTab] = await this.redirectedRequest(); // remove onCompleted listeners because in the real world this request would never complete // and thus might trigger unexpected behavior because the tab gets removed when reopening - background.browser.webRequest.onCompleted.addListener = sinon.stub(); - background.browser.tabs.create.resetHistory(); + this.webExt.background.browser.webRequest.onCompleted.addListener = sinon.stub(); + this.webExt.background.browser.tabs.create.resetHistory(); // we create a tab with the same id and use the same request id to see if uncanceled - await helper.browser.openNewTab({ + await this.webExt.browser.tabs._create({ id: newTab.id, url: "https://www.youtube.com" }, { @@ -101,14 +113,14 @@ describe("#940", () => { } }); - background.browser.tabs.create.should.have.been.calledOnce; + this.webExt.background.browser.tabs.create.should.have.been.calledOnce; }); - it("should uncancel after webRequest.onErrorOccurred", async () => { - await redirectedRequest(); - background.browser.tabs.create.resetHistory(); + it("should uncancel after webRequest.onErrorOccurred", async function () { + const [newTabResponses, newTab] = await this.redirectedRequest(); + this.webExt.background.browser.tabs.create.resetHistory(); // we create a tab with the same id and use the same request id to see if uncanceled - await helper.browser.openNewTab({ + await this.webExt.browser.tabs._create({ id: newTab.id, url: "https://www.youtube.com" }, { @@ -120,18 +132,18 @@ describe("#940", () => { } }); - background.browser.tabs.create.should.have.been.calledOnce; + this.webExt.background.browser.tabs.create.should.have.been.calledOnce; }); - it("should uncancel after 2 seconds", async () => { - await redirectedRequest({ + it("should uncancel after 2 seconds", async function () { + const [newTabResponses, newTab] = await this.redirectedRequest({ webRequestDontYield: ["onCompleted", "onErrorOccurred"] }); global.clock.tick(2000); - background.browser.tabs.create.resetHistory(); + this.webExt.background.browser.tabs.create.resetHistory(); // we create a tab with the same id and use the same request id to see if uncanceled - await helper.browser.openNewTab({ + await this.webExt.browser.tabs._create({ id: newTab.id, url: "https://www.youtube.com" }, { @@ -143,13 +155,13 @@ describe("#940", () => { } }); - background.browser.tabs.create.should.have.been.calledOnce; + this.webExt.background.browser.tabs.create.should.have.been.calledOnce; }); - it("should not influence the canceled url in other tabs", async () => { - await redirectedRequest(); - background.browser.tabs.create.resetHistory(); - await helper.browser.openNewTab({ + it("should not influence the canceled url in other tabs", async function () { + await this.redirectedRequest(); + this.webExt.background.browser.tabs.create.resetHistory(); + await this.webExt.browser.tabs._create({ cookieStoreId: "firefox-default", url: "https://www.youtube.com" }, { @@ -158,11 +170,7 @@ describe("#940", () => { } }); - background.browser.tabs.create.should.have.been.calledOnce; - }); - - afterEach(() => { - global.clock.restore(); + this.webExt.background.browser.tabs.create.should.have.been.calledOnce; }); }); }); From 419be23c9c835c305fcee37ab2fcdeabc7f581bb Mon Sep 17 00:00:00 2001 From: stoically Date: Fri, 24 Jan 2020 09:09:05 +0100 Subject: [PATCH 51/60] Add sync tests to mocha suite --- src/js/background/assignManager.js | 2 +- src/js/background/identityState.js | 2 +- src/js/background/sync.js | 2 +- test/features/sync.test.js | 695 +++++++++++++++++++++++++++++ 4 files changed, 698 insertions(+), 3 deletions(-) create mode 100644 test/features/sync.test.js diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 91ff8e6..9dd6e88 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -1,4 +1,4 @@ -const assignManager = { +window.assignManager = { MENU_ASSIGN_ID: "open-in-this-container", MENU_REMOVE_ID: "remove-open-in-this-container", MENU_SEPARATOR_ID: "separator", diff --git a/src/js/background/identityState.js b/src/js/background/identityState.js index 2525f57..8c01eb7 100644 --- a/src/js/background/identityState.js +++ b/src/js/background/identityState.js @@ -1,4 +1,4 @@ -const identityState = { +window.identityState = { storageArea: { area: browser.storage.local, diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 9546d7c..5dbde9e 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,6 +1,6 @@ const SYNC_DEBUG = true; -const sync = { +window.sync = { storageArea: { area: browser.storage.sync, diff --git a/test/features/sync.test.js b/test/features/sync.test.js new file mode 100644 index 0000000..bd6341b --- /dev/null +++ b/test/features/sync.test.js @@ -0,0 +1,695 @@ +const {initializeWithTab} = require("../common"); + +describe("Sync", function() { + beforeEach(async function() { + this.webExt = await initializeWithTab(); + this.syncHelper = new SyncTestHelper(this.webExt); + }); + + afterEach(function() { + this.webExt.destroy(); + delete this.syncHelper; + }); + + it("testIdentityStateCleanup", async function() { + await this.syncHelper.stopSyncListeners(); + console.log("Testing the cleanup of local storage"); + + await this.syncHelper.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); + + await this.webExt.browser.storage.local.set({ + "identitiesState@@_firefox-container-5": { + "hiddenTabs": [] + } + }); + console.log("local storage set: ", await this.webExt.browser.storage.local.get()); + + await this.webExt.background.window.identityState.storageArea.upgradeData(); + + const macConfigs = await this.webExt.browser.storage.local.get(); + const identities = []; + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("identitiesState@@_") && !configKey.includes("default")) { + identities.push(macConfigs[configKey]); + } + } + + console.assert(identities.length === 5, "There should be 5 identity entries"); + for (const identity of identities) { + console.assert(!!identity.macAddonUUID, `${identity.name} should have a uuid`); + } + console.log("!!!Finished!!!"); + }); + + it("testAssignManagerCleanup", async function() { + await this.syncHelper.stopSyncListeners(); + console.log("Testing the cleanup of local storage"); + + await this.syncHelper.setState({}, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); + + await this.webExt.browser.storage.local.set({ + "siteContainerMap@@_www.goop.com": { + "userContextId": "6", + "neverAsk": true, + "hostname": "www.goop.com" + } + }); + console.log("local storage set: ", await this.webExt.browser.storage.local.get()); + + await this.webExt.background.window.identityState.storageArea.upgradeData(); + await this.webExt.background.window.assignManager.storageArea.upgradeData(); + + const macConfigs = await this.webExt.browser.storage.local.get(); + const assignments = []; + for(const configKey of Object.keys(macConfigs)) { + if (configKey.includes("siteContainerMap@@_")) { + macConfigs[configKey].configKey = configKey; + assignments.push(macConfigs[configKey]); + } + } + + console.assert(assignments.length === 5, "There should be 5 identity entries"); + for (const assignment of assignments) { + console.log(assignment); + console.assert(!!assignment.identityMacAddonUUID, `${assignment.configKey} should have a uuid`); + } + console.log("!!!Finished!!!"); + }); + + it("testReconcileSiteAssignments", async function() { + await this.syncHelper.stopSyncListeners(); + console.log("Testing reconciling Site Assignments"); + + await this.syncHelper.setState( + DUPE_TEST_SYNC, + LOCAL_DATA, + TEST_CONTAINERS, + SITE_ASSIGNMENT_TEST + ); + + // add 200ok (bad data). + const testSites = { + "siteContainerMap@@_developer.mozilla.org": { + "userContextId": "588", + "neverAsk": true, + "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", + "hostname": "developer.mozilla.org" + }, + "siteContainerMap@@_reddit.com": { + "userContextId": "592", + "neverAsk": true, + "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", + "hostname": "reddit.com" + }, + "siteContainerMap@@_twitter.com": { + "userContextId": "589", + "neverAsk": true, + "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", + "hostname": "twitter.com" + }, + "siteContainerMap@@_www.facebook.com": { + "userContextId": "590", + "neverAsk": true, + "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", + "hostname": "www.facebook.com" + }, + "siteContainerMap@@_www.linkedin.com": { + "userContextId": "591", + "neverAsk": true, + "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", + "hostname": "www.linkedin.com" + }, + "siteContainerMap@@_200ok.us": { + "userContextId": "1", + "neverAsk": true, + "identityMacAddonUUID": "b5f5f794-b37e-4cec-9f4e-6490df620336", + "hostname": "www.linkedin.com" + } + }; + + for (const site of Object.keys(testSites)) { + await this.webExt.browser.storage.sync.set({[site]:testSites[site]}); + } + + await this.webExt.browser.storage.sync.set({ + deletedSiteList: ["siteContainerMap@@_www.google.com"] + }); + console.log(await this.webExt.browser.storage.sync.get()); + await this.webExt.background.window.sync.runSync(); + + const assignedSites = await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); + Object.keys(assignedSites).should.have.lengthOf(6); + console.log("!!!Finished!!!"); + }); + + it("testInitialSync", async function() { + await this.syncHelper.stopSyncListeners(); + console.log("Testing new install with no sync"); + + await this.syncHelper.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); + + await this.webExt.background.window.sync.runSync(); + + const getAssignedSites = + await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); + const identities = await this.webExt.browser.contextualIdentities.query({}); + + console.assert( + identities.length === 5, + "There should be 5 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 0, + "There should be no site assignments" + ); + console.log("!!!Finished!!!"); + }); + + it("test2", async function() { + await this.syncHelper.stopSyncListeners(); + console.log("Testing sync differing from local"); + + await this.syncHelper.setState(SYNC_DATA, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); + + await this.webExt.background.window.sync.runSync(); + + const getAssignedSites = + await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); + + const identities = await this.webExt.browser.contextualIdentities.query({}); + + console.assert( + identities.length === 6, + "There should be 6 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 5, + "There should be 5 site assignments" + ); + console.log("!!!Finished!!!"); + }); + + it("dupeTest", async function() { + await this.syncHelper.stopSyncListeners(); + console.log("Test state from sync that duped everything initially"); + + await this.syncHelper.setState( + DUPE_TEST_SYNC, + DUPE_TEST_LOCAL, + DUPE_TEST_IDENTS, + DUPE_TEST_ASSIGNMENTS + ); + + await this.webExt.background.window.sync.runSync(); + + const getAssignedSites = + await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); + + const identities = await this.webExt.browser.contextualIdentities.query({}); + + console.assert( + identities.length === 7, + "There should be 7 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 5, + "There should be 5 site assignments" + ); + + const personalContainer = + this.syncHelper.lookupIdentityBy(identities, {name: "Personal"}); + console.log(personalContainer); + console.assert( + personalContainer.color === "red", + "Personal Container should be red" + ); + const mozillaContainer = + this.syncHelper.lookupIdentityBy(identities, {name: "Mozilla"}); + console.assert( + mozillaContainer.icon === "pet", + "Mozilla Container should be pet" + ); + console.log("!!!Finished!!!"); + }); + + it("CIerrorTest", async function() { + await this.syncHelper.stopSyncListeners(); + console.log("Test state from sync that duped everything initially"); + + await this.syncHelper.setState( + CI_ERROR_TEST_SYNC, + CI_ERROR_TEST_LOCAL, + CI_ERROR_TEST_IDENTS, + CI_ERROR_TEST_SITES + ); + + await this.webExt.background.window.sync.runSync(); + + const getSync = await this.webExt.browser.storage.sync.get(); + const getAssignedSites = + await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); + + const identities = await this.webExt.browser.contextualIdentities.query({}); + + console.assert( + Object.keys(getSync.cookieStoreIDmap).length === 7, + "cookieStoreIDmap should have 7 entries" + ); + + console.assert( + identities.length === 7, + "There should be 7 identities" + ); + + console.assert( + Object.keys(getAssignedSites).length === 5, + "There should be 5 site assignments" + ); + + const personalContainer = + this.syncHelper.lookupIdentityBy(identities, {name: "Personal"}); + console.log(personalContainer); + console.assert( + personalContainer.color === "red", + "Personal Container should be red" + ); + const mozillaContainer = + this.syncHelper.lookupIdentityBy(identities, {name: "Mozilla"}); + console.assert( + mozillaContainer.icon === "pet", + "Mozilla Container should be pet" + ); + console.log("!!!Finished!!!"); + }); +}); + +class SyncTestHelper { + constructor(webExt) { + this.webExt = webExt; + } + + async stopSyncListeners() { + await this.webExt.browser.storage.onChanged.removeListener(this.webExt.background.window.sync.storageArea.onChangedListener); + await this.webExt.background.window.sync.removeContextualIdentityListeners(); + } + + async setState(syncData, localData, identityData, assignmentData){ + await this.removeAllContainers(); + await this.webExt.browser.storage.sync.clear(); + await this.webExt.browser.storage.sync.set(syncData); + await this.webExt.browser.storage.local.clear(); + await this.webExt.browser.storage.local.set(localData); + for (let i=0; i < identityData.length; i++) { + //build identities + const newIdentity = + await this.webExt.browser.contextualIdentities.create(identityData[i]); + // fill identies with site assignments + if (assignmentData && assignmentData[i]) { + const data = { + "userContextId": + String( + newIdentity.cookieStoreId.replace(/^firefox-container-/, "") + ), + "neverAsk": true + }; + + await this.webExt.browser.storage.local.set({[assignmentData[i]]: data}); + } + } + console.log("local storage set: ", await this.webExt.browser.storage.local.get()); + return; + } + + async removeAllContainers() { + const identities = await this.webExt.browser.contextualIdentities.query({}); + console.log(identities); + for (const identity of identities) { + await this.webExt.browser.contextualIdentities.remove(identity.cookieStoreId); + } + } + + lookupIdentityBy(identities, options) { + for (const identity of identities) { + if (options && options.name) { + if (identity.name === options.name) return identity; + } + if (options && options.color) { + if (identity.color === options.color) return identity; + } + if (options && options.color) { + if (identity.color === options.color) return identity; + } + } + return false; + } +} + +const TEST_CONTAINERS = [ + { + name: "Personal", + color: "blue", + icon: "fingerprint" + }, + { + name: "Banking", + color: "green", + icon: "dollar" + }, + { + name: "Mozilla", + color: "red", + icon: "briefcase" + }, + { + name: "Groceries, obviously", + color: "yellow", + icon: "cart" + }, + { + name: "Facebook", + color: "toolbar", + icon: "fence" + }, +]; + +const TEST_ASSIGNMENTS = [ + "siteContainerMap@@_developer.mozilla.org", + "siteContainerMap@@_twitter.com", + "siteContainerMap@@_www.facebook.com", + "siteContainerMap@@_www.linkedin.com", + "siteContainerMap@@_reddit.com" +]; + +const LOCAL_DATA = { + "browserActionBadgesClicked": [ "6.1.1" ], + "containerTabsOpened": 7, + "identitiesState@@_firefox-default": { "hiddenTabs": [] }, + "onboarding-stage": 5 +}; + +const SYNC_DATA = { + "identity@@_22ded543-5173-44a5-a47a-8813535945ca": { + "name": "Personal", + "icon": "fingerprint", + "color": "red", + "cookieStoreId": "firefox-container-146", + "macAddonUUID": "22ded543-5173-44a5-a47a-8813535945ca" + }, + "identity@@_63e5212f-0858-418e-b5a3-09c2dea61fcd": { + "name": "Oscar", + "icon": "dollar", + "color": "green", + "cookieStoreId": "firefox-container-147", + "macAddonUUID": "3e5212f-0858-418e-b5a3-09c2dea61fcd" + }, + "identity@@_71335417-158e-4d74-a55b-e9e9081601ec": { + "name": "Mozilla", + "icon": "pet", + "color": "red", + "cookieStoreId": "firefox-container-148", + "macAddonUUID": "71335417-158e-4d74-a55b-e9e9081601ec" + }, + "identity@@_59c4e5f7-fe3b-435a-ae60-1340db31a91b": { + "name": "Groceries, obviously", + "icon": "cart", + "color": "pink", + "cookieStoreId": "firefox-container-149", + "macAddonUUID": "59c4e5f7-fe3b-435a-ae60-1340db31a91b" + }, + "identity@@_3dc916fb-8c0a-4538-9758-73ef819a45f7": { + "name": "Facebook", + "icon": "fence", + "color": "toolbar", + "cookieStoreId": "firefox-container-150", + "macAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7" + } +}; + +const DUPE_TEST_SYNC = { + "identity@@_d20d7af2-9866-468e-bb43-541efe8c2c2e": { + "name": "Personal", + "icon": "fingerprint", + "color": "red", + "cookieStoreId": "firefox-container-588", + "macAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e" + }, + "identity@@_cdd73c20-c26a-4c06-9b17-735c1f5e9187": { + "name": "Big Bird", + "icon": "pet", + "color": "yellow", + "cookieStoreId": "firefox-container-589", + "macAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187" + }, + "identity@@_32cc4a9b-05ed-4e54-8e11-732468de62f4": { + "name": "Mozilla", + "icon": "pet", + "color": "red", + "cookieStoreId": "firefox-container-590", + "macAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4" + }, + "identity@@_9ff381e3-4c11-420d-8e12-e352a3318be1": { + "name": "Groceries, obviously", + "icon": "cart", + "color": "pink", + "cookieStoreId": "firefox-container-591", + "macAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1" + }, + "identity@@_3dc916fb-8c0a-4538-9758-73ef819a45f7": { + "name": "Facebook", + "icon": "fence", + "color": "toolbar", + "cookieStoreId": "firefox-container-592", + "macAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7" + }, + "identity@@_63e5212f-0858-418e-b5a3-09c2dea61fcd": { + "name": "Oscar", + "icon": "dollar", + "color": "green", + "cookieStoreId": "firefox-container-593", + "macAddonUUID": "63e5212f-0858-418e-b5a3-09c2dea61fcd" + }, + "siteContainerMap@@_developer.mozilla.org": { + "userContextId": "588", + "neverAsk": true, + "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", + "hostname": "developer.mozilla.org" + }, + "siteContainerMap@@_reddit.com": { + "userContextId": "592", + "neverAsk": true, + "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", + "hostname": "reddit.com" + }, + "siteContainerMap@@_twitter.com": { + "userContextId": "589", + "neverAsk": true, + "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", + "hostname": "twitter.com" + }, + "siteContainerMap@@_www.facebook.com": { + "userContextId": "590", + "neverAsk": true, + "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", + "hostname": "www.facebook.com" + }, + "siteContainerMap@@_www.linkedin.com": { + "userContextId": "591", + "neverAsk": true, + "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", + "hostname": "www.linkedin.com" + } +}; + +const DUPE_TEST_LOCAL = { + "beenSynced": true, + "browserActionBadgesClicked": [ + "6.1.1" + ], + "containerTabsOpened": 7, + "identitiesState@@_firefox-default": { + "hiddenTabs": [] + }, + "onboarding-stage": 5, +}; + +const DUPE_TEST_ASSIGNMENTS = [ + "siteContainerMap@@_developer.mozilla.org", + "siteContainerMap@@_reddit.com", + "siteContainerMap@@_twitter.com", + "siteContainerMap@@_www.facebook.com", + "siteContainerMap@@_www.linkedin.com" +]; + +const SITE_ASSIGNMENT_TEST = [ + "siteContainerMap@@_developer.mozilla.org", + "siteContainerMap@@_www.facebook.com", + "siteContainerMap@@_www.google.com", + "siteContainerMap@@_bugzilla.mozilla.org" +]; + +const DUPE_TEST_IDENTS = [ + { + "name": "Personal", + "icon": "fingerprint", + "color": "blue", + }, + { + "name": "Banking", + "icon": "pet", + "color": "green", + }, + { + "name": "Mozilla", + "icon": "briefcase", + "color": "red", + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "color": "orange", + }, + { + "name": "Facebook", + "icon": "fence", + "color": "toolbar", + }, + { + "name": "Big Bird", + "icon": "dollar", + "color": "yellow", + } +]; + +const CI_ERROR_TEST_SYNC = { + "identities": [ + { + "name": "Personal", + "icon": "fingerprint", + "iconUrl": "resource://usercontext-content/fingerprint.svg", + "color": "blue", + "colorCode": "#37adff", + "cookieStoreId": "firefox-container-6" + }, + { + "name": "Mozilla", + "icon": "fruit", + "iconUrl": "resource://usercontext-content/fruit.svg", + "color": "purple", + "colorCode": "#af51f5", + "cookieStoreId": "firefox-container-8" + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "iconUrl": "resource://usercontext-content/cart.svg", + "color": "yellow", + "colorCode": "#ffcb00", + "cookieStoreId": "firefox-container-9" + }, + { + "name": "Facebook", + "icon": "circle", + "iconUrl": "resource://usercontext-content/circle.svg", + "color": "blue", + "colorCode": "#37adff", + "cookieStoreId": "firefox-container-10" + }, + { + "name": "Work", + "icon": "briefcase", + "iconUrl": "resource://usercontext-content/briefcase.svg", + "color": "orange", + "colorCode": "#ff9f00", + "cookieStoreId": "firefox-container-11" + }, + { + "name": "Greg's container", + "icon": "vacation", + "iconUrl": "resource://usercontext-content/vacation.svg", + "color": "yellow", + "colorCode": "#ffcb00", + "cookieStoreId": "firefox-container-14" + } + ], + "deletedIdentityList": [ + "8098140e-d406-4321-b4f5-24763b4f9513", + "73aebc7a-286f-408a-9a94-a06d29b288e0", + "8f153224-bbe8-4664-ba02-0293ddec3e78" + ], + "cookieStoreIDmap": { + "firefox-container-10": "58956e95-43fb-44af-95c0-1ec8d83e1e13", + "firefox-container-11": "0269558d-6be7-487b-beb1-b720b346d09b", + "firefox-container-14": "e48d04cf-6277-4236-8f3d-611287d0caf2", + "firefox-container-6": "869a7563-030d-4a63-8a84-209270561d3c", + "firefox-container-8": "73aebc7a-286f-408a-9a94-a06d29b288e0", + "firefox-container-9": "4831fef4-6f43-47fb-a578-ccdc3ee7f883" + }, + "assignedSites": { + "siteContainerMap@@_bugzilla.mozilla.org": { + "userContextId": "11", + "neverAsk": true, + "identityMacAddonUUID": "0269558d-6be7-487b-beb1-b720b346d09b", + "hostname": "bugzilla.mozilla.org" + }, + "siteContainerMap@@_www.amazon.com": { + "userContextId": "14", + "neverAsk": false, + "identityMacAddonUUID": "e48d04cf-6277-4236-8f3d-611287d0caf2", + "hostname": "www.amazon.com" + } + }, + "deletedSiteList": [ + "siteContainerMap@@_www.facebook.com" + ] +}; + +const CI_ERROR_TEST_LOCAL = { + "browserActionBadgesClicked": [ + "6.1.1" + ], + "containerTabsOpened": 6, + "onboarding-stage": 5, +}; + +const CI_ERROR_TEST_SITES = [ + "siteContainerMap@@_bugzilla.mozilla.org", + "siteContainerMap@@_www.bankofoklahoma.com", + "siteContainerMap@@_www.mozilla.org", + "siteContainerMap@@_www.reddit.com" +]; + +const CI_ERROR_TEST_IDENTS = [ + { + "name": "Personal", + "icon": "fingerprint", + "color": "blue", + }, + { + "name": "Work", + "icon": "briefcase", + "color": "orange", + }, + { + "name": "Banking", + "icon": "dollar", + "color": "green", + }, + { + "name": "Mozilla", + "icon": "fruit", + "color": "purple", + }, + { + "name": "Groceries, obviously", + "icon": "cart", + "color": "yellow", + }, + { + "name": "Facebook", + "icon": "circle", + "color": "blue", + } +]; \ No newline at end of file From 88d8edce7eca0f844016eab2dcc5b7fd97b27a5d Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 29 Jan 2020 18:30:30 -0600 Subject: [PATCH 52/60] fixed initial container sync entry dupe --- package.json | 2 +- src/js/background/sync.js | 38 ++++++++++++++++++++++++++++---------- src/manifest.json | 2 +- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 2375323..39d2853 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "testpilot-containers", "title": "Multi-Account Containers", "description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", - "version": "6.1.4", + "version": "6.1.5", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/multi-account-containers/issues" diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 9546d7c..cc9b183 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -16,10 +16,15 @@ const sync = { const deletedIdentityList = await sync.storageArea.getDeletedIdentityList(); if ( - deletedIdentityList.find(element => element === deletedIdentityUUID) - ) return; - deletedIdentityList.push(deletedIdentityUUID); - await sync.storageArea.set({ deletedIdentityList }); + ! deletedIdentityList.find(element => element === deletedIdentityUUID) + ) { + deletedIdentityList.push(deletedIdentityUUID); + await sync.storageArea.set({ deletedIdentityList }); + } + await this.removeIdentityKeyFromSync(deletedIdentityUUID); + }, + + async removeIdentityKeyFromSync(deletedIdentityUUID) { await sync.storageArea.area.remove( "identity@@_" + deletedIdentityUUID); }, @@ -337,8 +342,20 @@ async function reconcileIdentities(){ } } } - const localIdentities = await browser.contextualIdentities.query({}); + const syncIdentitiesRemoveDupes = + await sync.storageArea.getIdentities(); + // find any local dupes created on sync storage and delete from sync storage + for (const localIdentity of localIdentities) { + const syncIdentitiesOfName = syncIdentitiesRemoveDupes + .filter(identity => identity.name === localIdentity.name); + if (syncIdentitiesOfName.length > 1) { + const identityMatchingContextId = syncIdentitiesOfName + .find(identity => identity.cookieStoreId === localIdentity.cookieStoreId); + if (identityMatchingContextId) + await sync.storageArea.removeIdentityKeyFromSync(identityMatchingContextId.macAddonUUID); + } + } const syncIdentities = await sync.storageArea.getIdentities(); // now compare all containers for matching names. @@ -397,11 +414,12 @@ async function updateIdentityWithSyncInfo(syncIdentity, localMatch) { } } // Sync is truth. If all is the same, update the local uuid to match sync - await identityState.updateUUID( - localMatch.cookieStoreId, - syncIdentity.macAddonUUID - ); - + if (localMatch.macAddonUUID !== syncIdentity.macAddonUUID) { + await identityState.updateUUID( + localMatch.cookieStoreId, + syncIdentity.macAddonUUID + ); + } // TODOkmw: update any site assignment UUIDs } diff --git a/src/manifest.json b/src/manifest.json index 7d36ec0..cd6d097 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Firefox Multi-Account Containers", - "version": "6.1.4", + "version": "6.1.5", "incognito": "not_allowed", "description": "Multi-Account Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", "icons": { From c3007519589ee6e25f99022bf6208b34eddca94f Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 6 Feb 2020 11:54:15 -0600 Subject: [PATCH 53/60] moved test to mocha tests --- src/js/background/index.html | 1 - src/js/background/sync.js | 2 +- src/js/background/test.js | 707 ----------------------------------- test/features/sync.test.js | 262 +------------ 4 files changed, 17 insertions(+), 955 deletions(-) delete mode 100644 src/js/background/test.js diff --git a/src/js/background/index.html b/src/js/background/index.html index 3bb1a79..da380ba 100644 --- a/src/js/background/index.html +++ b/src/js/background/index.html @@ -18,7 +18,6 @@ - diff --git a/src/js/background/sync.js b/src/js/background/sync.js index f95d122..847b7a1 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,4 +1,4 @@ -const SYNC_DEBUG = true; +const SYNC_DEBUG = false; window.sync = { storageArea: { diff --git a/src/js/background/test.js b/src/js/background/test.js deleted file mode 100644 index fada4f9..0000000 --- a/src/js/background/test.js +++ /dev/null @@ -1,707 +0,0 @@ -browser.tests = { - async runAll() { - await this.testIdentityStateCleanup(); - await this.testAssignManagerCleanup(); - await this.testReconcileSiteAssignments(); - await this.testInitialSync(); - await this.test2(); - await this.dupeTest(); - }, - // more unit tests - // if site assignment has no valid cookieStoreId, delete on local - - async resetForManualTests() { - await browser.tests.stopSyncListeners(); - console.log("reset"); - await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); - }, - - async testIdentityStateCleanup() { - await browser.tests.stopSyncListeners(); - console.log("Testing the cleanup of local storage"); - - await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); - - await browser.storage.local.set({ - "identitiesState@@_firefox-container-5": { - "hiddenTabs": [] - } - }); - console.log("local storage set: ", await browser.storage.local.get()); - - await identityState.storageArea.upgradeData(); - - const macConfigs = await browser.storage.local.get(); - const identities = []; - for(const configKey of Object.keys(macConfigs)) { - if (configKey.includes("identitiesState@@_") && !configKey.includes("default")) { - identities.push(macConfigs[configKey]); - } - } - - console.assert(identities.length === 5, "There should be 5 identity entries"); - for (const identity of identities) { - console.assert(!!identity.macAddonUUID, `${identity.name} should have a uuid`); - } - console.log("!!!Finished!!!"); - }, - - async testAssignManagerCleanup() { - await browser.tests.stopSyncListeners(); - console.log("Testing the cleanup of local storage"); - - await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); - - await browser.storage.local.set({ - "siteContainerMap@@_www.goop.com": { - "userContextId": "6", - "neverAsk": true, - "hostname": "www.goop.com" - } - }); - console.log("local storage set: ", await browser.storage.local.get()); - - await identityState.storageArea.upgradeData(); - await assignManager.storageArea.upgradeData(); - - const macConfigs = await browser.storage.local.get(); - const assignments = []; - for(const configKey of Object.keys(macConfigs)) { - if (configKey.includes("siteContainerMap@@_")) { - macConfigs[configKey].configKey = configKey; - assignments.push(macConfigs[configKey]); - } - } - - console.assert(assignments.length === 5, "There should be 5 identity entries"); - for (const assignment of assignments) { - console.log(assignment); - console.assert(!!assignment.identityMacAddonUUID, `${assignment.configKey} should have a uuid`); - } - console.log("!!!Finished!!!"); - }, - - async testReconcileSiteAssignments() { - await browser.tests.stopSyncListeners(); - console.log("Testing reconciling Site Assignments"); - - await this.setState( - DUPE_TEST_SYNC, - LOCAL_DATA, - TEST_CONTAINERS, - SITE_ASSIGNMENT_TEST - ); - - // add 200ok (bad data). - const testSites = { - "siteContainerMap@@_developer.mozilla.org": { - "userContextId": "588", - "neverAsk": true, - "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", - "hostname": "developer.mozilla.org" - }, - "siteContainerMap@@_reddit.com": { - "userContextId": "592", - "neverAsk": true, - "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", - "hostname": "reddit.com" - }, - "siteContainerMap@@_twitter.com": { - "userContextId": "589", - "neverAsk": true, - "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", - "hostname": "twitter.com" - }, - "siteContainerMap@@_www.facebook.com": { - "userContextId": "590", - "neverAsk": true, - "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", - "hostname": "www.facebook.com" - }, - "siteContainerMap@@_www.linkedin.com": { - "userContextId": "591", - "neverAsk": true, - "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", - "hostname": "www.linkedin.com" - }, - "siteContainerMap@@_200ok.us": { - "userContextId": "1", - "neverAsk": true, - "identityMacAddonUUID": "b5f5f794-b37e-4cec-9f4e-6490df620336", - "hostname": "www.linkedin.com" - } - }; - - for (const site of Object.keys(testSites)) { - await browser.storage.sync.set({[site]:testSites[site]}); - } - - await browser.storage.sync.set({ - deletedSiteList: ["siteContainerMap@@_www.google.com"] - }); - console.log(await browser.storage.sync.get()); - await sync.runSync(); - - const assignedSites = await assignManager.storageArea.getAssignedSites(); - console.assert(Object.keys(assignedSites).length === 6, "There should be 6 assigned sites"); - console.log("!!!Finished!!!"); - }, - - async testInitialSync() { - await browser.tests.stopSyncListeners(); - console.log("Testing new install with no sync"); - - await this.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); - - await sync.runSync(); - - const getAssignedSites = - await assignManager.storageArea.getAssignedSites(); - const identities = await browser.contextualIdentities.query({}); - - console.assert( - identities.length === 5, - "There should be 5 identities" - ); - - console.assert( - Object.keys(getAssignedSites).length === 0, - "There should be no site assignments" - ); - console.log("!!!Finished!!!"); - }, - - async test2() { - await browser.tests.stopSyncListeners(); - console.log("Testing sync differing from local"); - - await this.setState(SYNC_DATA, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); - - await sync.runSync(); - - const getAssignedSites = - await assignManager.storageArea.getAssignedSites(); - - const identities = await browser.contextualIdentities.query({}); - - console.assert( - identities.length === 6, - "There should be 6 identities" - ); - - console.assert( - Object.keys(getAssignedSites).length === 5, - "There should be 5 site assignments" - ); - console.log("!!!Finished!!!"); - }, - - async dupeTest() { - await browser.tests.stopSyncListeners(); - console.log("Test state from sync that duped everything initially"); - - await this.setState( - DUPE_TEST_SYNC, - DUPE_TEST_LOCAL, - DUPE_TEST_IDENTS, - DUPE_TEST_ASSIGNMENTS - ); - - await sync.runSync(); - - const getAssignedSites = - await assignManager.storageArea.getAssignedSites(); - - const identities = await browser.contextualIdentities.query({}); - - console.assert( - identities.length === 7, - "There should be 7 identities" - ); - - console.assert( - Object.keys(getAssignedSites).length === 5, - "There should be 5 site assignments" - ); - - const personalContainer = - this.lookupIdentityBy(identities, {name: "Personal"}); - console.log(personalContainer); - console.assert( - personalContainer.color === "red", - "Personal Container should be red" - ); - const mozillaContainer = - this.lookupIdentityBy(identities, {name: "Mozilla"}); - console.assert( - mozillaContainer.icon === "pet", - "Mozilla Container should be pet" - ); - console.log("!!!Finished!!!"); - }, - - async CIerrorTest() { - await browser.tests.stopSyncListeners(); - console.log("Test state from sync that duped everything initially"); - - await this.setState( - CI_ERROR_TEST_SYNC, - CI_ERROR_TEST_LOCAL, - CI_ERROR_TEST_IDENTS, - CI_ERROR_TEST_SITES - ); - - await sync.runSync(); - - const getSync = await browser.storage.sync.get(); - const getAssignedSites = - await assignManager.storageArea.getAssignedSites(); - - const identities = await browser.contextualIdentities.query({}); - - console.assert( - Object.keys(getSync.cookieStoreIDmap).length === 7, - "cookieStoreIDmap should have 7 entries" - ); - - console.assert( - identities.length === 7, - "There should be 7 identities" - ); - - console.assert( - Object.keys(getAssignedSites).length === 5, - "There should be 5 site assignments" - ); - - const personalContainer = - this.lookupIdentityBy(identities, {name: "Personal"}); - console.log(personalContainer); - console.assert( - personalContainer.color === "red", - "Personal Container should be red" - ); - const mozillaContainer = - this.lookupIdentityBy(identities, {name: "Mozilla"}); - console.assert( - mozillaContainer.icon === "pet", - "Mozilla Container should be pet" - ); - console.log("!!!Finished!!!"); - }, - - lookupIdentityBy(identities, options) { - for (const identity of identities) { - if (options && options.name) { - if (identity.name === options.name) return identity; - } - if (options && options.color) { - if (identity.color === options.color) return identity; - } - if (options && options.color) { - if (identity.color === options.color) return identity; - } - } - return false; - }, - - /* - * Sets the state of sync storage, local storage, and the identities. - * SyncDat and localData (without identities or site assignments) get - * set to sync and local storage respectively. IdentityData creates - * new identities (after all have been removed), and assignmentData - * is used along with the new identities' cookieStoreIds to create - * site assignments in local storage. - */ - async setState(syncData, localData, identityData, assignmentData){ - await this.removeAllContainers(); - await browser.storage.sync.clear(); - await browser.storage.sync.set(syncData); - await browser.storage.local.clear(); - await browser.storage.local.set(localData); - for (let i=0; i < identityData.length; i++) { - //build identities - const newIdentity = - await browser.contextualIdentities.create(identityData[i]); - // fill identies with site assignments - if (assignmentData && assignmentData[i]) { - const data = { - "userContextId": - String( - newIdentity.cookieStoreId.replace(/^firefox-container-/, "") - ), - "neverAsk": true - }; - - await browser.storage.local.set({[assignmentData[i]]: data}); - } - } - console.log("local storage set: ", await browser.storage.local.get()); - return; - }, - - async removeAllContainers() { - const identities = await browser.contextualIdentities.query({}); - for (const identity of identities) { - await browser.contextualIdentities.remove(identity.cookieStoreId); - } - }, - - async stopSyncListeners() { - await browser.storage.onChanged.removeListener(sync.storageArea.onChangedListener); - await sync.removeContextualIdentityListeners(); - }, - - async startListeners() { - await browser.storage.onChanged.addListener(sync.storageArea.onChangedListener); - await sync.addContextualIdentityListeners(); - }, - -}; - -const TEST_CONTAINERS = [ - { - name: "Personal", - color: "blue", - icon: "fingerprint" - }, - { - name: "Banking", - color: "green", - icon: "dollar" - }, - { - name: "Mozilla", - color: "red", - icon: "briefcase" - }, - { - name: "Groceries, obviously", - color: "yellow", - icon: "cart" - }, - { - name: "Facebook", - color: "toolbar", - icon: "fence" - }, -]; - -const TEST_ASSIGNMENTS = [ - "siteContainerMap@@_developer.mozilla.org", - "siteContainerMap@@_twitter.com", - "siteContainerMap@@_www.facebook.com", - "siteContainerMap@@_www.linkedin.com", - "siteContainerMap@@_reddit.com" -]; - -const LOCAL_DATA = { - "browserActionBadgesClicked": [ "6.1.1" ], - "containerTabsOpened": 7, - "identitiesState@@_firefox-default": { "hiddenTabs": [] }, - "onboarding-stage": 5 -}; - -const SYNC_DATA = { - "identity@@_22ded543-5173-44a5-a47a-8813535945ca": { - "name": "Personal", - "icon": "fingerprint", - "color": "red", - "cookieStoreId": "firefox-container-146", - "macAddonUUID": "22ded543-5173-44a5-a47a-8813535945ca" - }, - "identity@@_63e5212f-0858-418e-b5a3-09c2dea61fcd": { - "name": "Oscar", - "icon": "dollar", - "color": "green", - "cookieStoreId": "firefox-container-147", - "macAddonUUID": "3e5212f-0858-418e-b5a3-09c2dea61fcd" - }, - "identity@@_71335417-158e-4d74-a55b-e9e9081601ec": { - "name": "Mozilla", - "icon": "pet", - "color": "red", - "cookieStoreId": "firefox-container-148", - "macAddonUUID": "71335417-158e-4d74-a55b-e9e9081601ec" - }, - "identity@@_59c4e5f7-fe3b-435a-ae60-1340db31a91b": { - "name": "Groceries, obviously", - "icon": "cart", - "color": "pink", - "cookieStoreId": "firefox-container-149", - "macAddonUUID": "59c4e5f7-fe3b-435a-ae60-1340db31a91b" - }, - "identity@@_3dc916fb-8c0a-4538-9758-73ef819a45f7": { - "name": "Facebook", - "icon": "fence", - "color": "toolbar", - "cookieStoreId": "firefox-container-150", - "macAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7" - } -}; - -const DUPE_TEST_SYNC = { - "identity@@_d20d7af2-9866-468e-bb43-541efe8c2c2e": { - "name": "Personal", - "icon": "fingerprint", - "color": "red", - "cookieStoreId": "firefox-container-588", - "macAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e" - }, - "identity@@_cdd73c20-c26a-4c06-9b17-735c1f5e9187": { - "name": "Big Bird", - "icon": "pet", - "color": "yellow", - "cookieStoreId": "firefox-container-589", - "macAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187" - }, - "identity@@_32cc4a9b-05ed-4e54-8e11-732468de62f4": { - "name": "Mozilla", - "icon": "pet", - "color": "red", - "cookieStoreId": "firefox-container-590", - "macAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4" - }, - "identity@@_9ff381e3-4c11-420d-8e12-e352a3318be1": { - "name": "Groceries, obviously", - "icon": "cart", - "color": "pink", - "cookieStoreId": "firefox-container-591", - "macAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1" - }, - "identity@@_3dc916fb-8c0a-4538-9758-73ef819a45f7": { - "name": "Facebook", - "icon": "fence", - "color": "toolbar", - "cookieStoreId": "firefox-container-592", - "macAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7" - }, - "identity@@_63e5212f-0858-418e-b5a3-09c2dea61fcd": { - "name": "Oscar", - "icon": "dollar", - "color": "green", - "cookieStoreId": "firefox-container-593", - "macAddonUUID": "63e5212f-0858-418e-b5a3-09c2dea61fcd" - }, - "siteContainerMap@@_developer.mozilla.org": { - "userContextId": "588", - "neverAsk": true, - "identityMacAddonUUID": "d20d7af2-9866-468e-bb43-541efe8c2c2e", - "hostname": "developer.mozilla.org" - }, - "siteContainerMap@@_reddit.com": { - "userContextId": "592", - "neverAsk": true, - "identityMacAddonUUID": "3dc916fb-8c0a-4538-9758-73ef819a45f7", - "hostname": "reddit.com" - }, - "siteContainerMap@@_twitter.com": { - "userContextId": "589", - "neverAsk": true, - "identityMacAddonUUID": "cdd73c20-c26a-4c06-9b17-735c1f5e9187", - "hostname": "twitter.com" - }, - "siteContainerMap@@_www.facebook.com": { - "userContextId": "590", - "neverAsk": true, - "identityMacAddonUUID": "32cc4a9b-05ed-4e54-8e11-732468de62f4", - "hostname": "www.facebook.com" - }, - "siteContainerMap@@_www.linkedin.com": { - "userContextId": "591", - "neverAsk": true, - "identityMacAddonUUID": "9ff381e3-4c11-420d-8e12-e352a3318be1", - "hostname": "www.linkedin.com" - } -}; - -const DUPE_TEST_LOCAL = { - "beenSynced": true, - "browserActionBadgesClicked": [ - "6.1.1" - ], - "containerTabsOpened": 7, - "identitiesState@@_firefox-default": { - "hiddenTabs": [] - }, - "onboarding-stage": 5, -}; - -const DUPE_TEST_ASSIGNMENTS = [ - "siteContainerMap@@_developer.mozilla.org", - "siteContainerMap@@_reddit.com", - "siteContainerMap@@_twitter.com", - "siteContainerMap@@_www.facebook.com", - "siteContainerMap@@_www.linkedin.com" -]; - -const SITE_ASSIGNMENT_TEST = [ - "siteContainerMap@@_developer.mozilla.org", - "siteContainerMap@@_www.facebook.com", - "siteContainerMap@@_www.google.com", - "siteContainerMap@@_bugzilla.mozilla.org" -]; - -const DUPE_TEST_IDENTS = [ - { - "name": "Personal", - "icon": "fingerprint", - "color": "blue", - }, - { - "name": "Banking", - "icon": "pet", - "color": "green", - }, - { - "name": "Mozilla", - "icon": "briefcase", - "color": "red", - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "color": "orange", - }, - { - "name": "Facebook", - "icon": "fence", - "color": "toolbar", - }, - { - "name": "Big Bird", - "icon": "dollar", - "color": "yellow", - } -]; - -const CI_ERROR_TEST_SYNC = { - "identities": [ - { - "name": "Personal", - "icon": "fingerprint", - "iconUrl": "resource://usercontext-content/fingerprint.svg", - "color": "blue", - "colorCode": "#37adff", - "cookieStoreId": "firefox-container-6" - }, - { - "name": "Mozilla", - "icon": "fruit", - "iconUrl": "resource://usercontext-content/fruit.svg", - "color": "purple", - "colorCode": "#af51f5", - "cookieStoreId": "firefox-container-8" - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "iconUrl": "resource://usercontext-content/cart.svg", - "color": "yellow", - "colorCode": "#ffcb00", - "cookieStoreId": "firefox-container-9" - }, - { - "name": "Facebook", - "icon": "circle", - "iconUrl": "resource://usercontext-content/circle.svg", - "color": "blue", - "colorCode": "#37adff", - "cookieStoreId": "firefox-container-10" - }, - { - "name": "Work", - "icon": "briefcase", - "iconUrl": "resource://usercontext-content/briefcase.svg", - "color": "orange", - "colorCode": "#ff9f00", - "cookieStoreId": "firefox-container-11" - }, - { - "name": "Greg's container", - "icon": "vacation", - "iconUrl": "resource://usercontext-content/vacation.svg", - "color": "yellow", - "colorCode": "#ffcb00", - "cookieStoreId": "firefox-container-14" - } - ], - "deletedIdentityList": [ - "8098140e-d406-4321-b4f5-24763b4f9513", - "73aebc7a-286f-408a-9a94-a06d29b288e0", - "8f153224-bbe8-4664-ba02-0293ddec3e78" - ], - "cookieStoreIDmap": { - "firefox-container-10": "58956e95-43fb-44af-95c0-1ec8d83e1e13", - "firefox-container-11": "0269558d-6be7-487b-beb1-b720b346d09b", - "firefox-container-14": "e48d04cf-6277-4236-8f3d-611287d0caf2", - "firefox-container-6": "869a7563-030d-4a63-8a84-209270561d3c", - "firefox-container-8": "73aebc7a-286f-408a-9a94-a06d29b288e0", - "firefox-container-9": "4831fef4-6f43-47fb-a578-ccdc3ee7f883" - }, - "assignedSites": { - "siteContainerMap@@_bugzilla.mozilla.org": { - "userContextId": "11", - "neverAsk": true, - "identityMacAddonUUID": "0269558d-6be7-487b-beb1-b720b346d09b", - "hostname": "bugzilla.mozilla.org" - }, - "siteContainerMap@@_www.amazon.com": { - "userContextId": "14", - "neverAsk": false, - "identityMacAddonUUID": "e48d04cf-6277-4236-8f3d-611287d0caf2", - "hostname": "www.amazon.com" - } - }, - "deletedSiteList": [ - "siteContainerMap@@_www.facebook.com" - ] -}; - -const CI_ERROR_TEST_LOCAL = { - "browserActionBadgesClicked": [ - "6.1.1" - ], - "containerTabsOpened": 6, - "onboarding-stage": 5, -}; - -const CI_ERROR_TEST_SITES = [ - "siteContainerMap@@_bugzilla.mozilla.org", - "siteContainerMap@@_www.bankofoklahoma.com", - "siteContainerMap@@_www.mozilla.org", - "siteContainerMap@@_www.reddit.com" -]; - -const CI_ERROR_TEST_IDENTS = [ - { - "name": "Personal", - "icon": "fingerprint", - "color": "blue", - }, - { - "name": "Work", - "icon": "briefcase", - "color": "orange", - }, - { - "name": "Banking", - "icon": "dollar", - "color": "green", - }, - { - "name": "Mozilla", - "icon": "fruit", - "color": "purple", - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "color": "yellow", - }, - { - "name": "Facebook", - "icon": "circle", - "color": "blue", - } -]; diff --git a/test/features/sync.test.js b/test/features/sync.test.js index bd6341b..b646c71 100644 --- a/test/features/sync.test.js +++ b/test/features/sync.test.js @@ -13,7 +13,6 @@ describe("Sync", function() { it("testIdentityStateCleanup", async function() { await this.syncHelper.stopSyncListeners(); - console.log("Testing the cleanup of local storage"); await this.syncHelper.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); @@ -22,7 +21,6 @@ describe("Sync", function() { "hiddenTabs": [] } }); - console.log("local storage set: ", await this.webExt.browser.storage.local.get()); await this.webExt.background.window.identityState.storageArea.upgradeData(); @@ -34,31 +32,27 @@ describe("Sync", function() { } } - console.assert(identities.length === 5, "There should be 5 identity entries"); + identities.should.have.lengthOf(5, "There should be 5 identity entries"); for (const identity of identities) { - console.assert(!!identity.macAddonUUID, `${identity.name} should have a uuid`); + (!!identity.macAddonUUID).should.be.true; + } - console.log("!!!Finished!!!"); }); it("testAssignManagerCleanup", async function() { await this.syncHelper.stopSyncListeners(); - console.log("Testing the cleanup of local storage"); await this.syncHelper.setState({}, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); await this.webExt.browser.storage.local.set({ "siteContainerMap@@_www.goop.com": { - "userContextId": "6", - "neverAsk": true, - "hostname": "www.goop.com" + "userContextId": "999", + "neverAsk": true } }); - console.log("local storage set: ", await this.webExt.browser.storage.local.get()); await this.webExt.background.window.identityState.storageArea.upgradeData(); await this.webExt.background.window.assignManager.storageArea.upgradeData(); - const macConfigs = await this.webExt.browser.storage.local.get(); const assignments = []; for(const configKey of Object.keys(macConfigs)) { @@ -67,18 +61,14 @@ describe("Sync", function() { assignments.push(macConfigs[configKey]); } } - - console.assert(assignments.length === 5, "There should be 5 identity entries"); + assignments.should.have.lengthOf(5, "There should be 5 site assignments"); for (const assignment of assignments) { - console.log(assignment); - console.assert(!!assignment.identityMacAddonUUID, `${assignment.configKey} should have a uuid`); + (!!assignment.identityMacAddonUUID).should.be.true; } - console.log("!!!Finished!!!"); }); it("testReconcileSiteAssignments", async function() { await this.syncHelper.stopSyncListeners(); - console.log("Testing reconciling Site Assignments"); await this.syncHelper.setState( DUPE_TEST_SYNC, @@ -134,41 +124,27 @@ describe("Sync", function() { await this.webExt.browser.storage.sync.set({ deletedSiteList: ["siteContainerMap@@_www.google.com"] }); - console.log(await this.webExt.browser.storage.sync.get()); await this.webExt.background.window.sync.runSync(); const assignedSites = await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); Object.keys(assignedSites).should.have.lengthOf(6); - console.log("!!!Finished!!!"); }); it("testInitialSync", async function() { await this.syncHelper.stopSyncListeners(); - console.log("Testing new install with no sync"); - await this.syncHelper.setState({}, LOCAL_DATA, TEST_CONTAINERS, []); - await this.webExt.background.window.sync.runSync(); const getAssignedSites = await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); const identities = await this.webExt.browser.contextualIdentities.query({}); - console.assert( - identities.length === 5, - "There should be 5 identities" - ); - - console.assert( - Object.keys(getAssignedSites).length === 0, - "There should be no site assignments" - ); - console.log("!!!Finished!!!"); + identities.should.have.lengthOf(5, "There should be 5 identity entries"); + Object.keys(getAssignedSites).should.have.lengthOf(0, "There should be no site assignments"); }); it("test2", async function() { await this.syncHelper.stopSyncListeners(); - console.log("Testing sync differing from local"); await this.syncHelper.setState(SYNC_DATA, LOCAL_DATA, TEST_CONTAINERS, TEST_ASSIGNMENTS); @@ -179,22 +155,12 @@ describe("Sync", function() { const identities = await this.webExt.browser.contextualIdentities.query({}); - console.assert( - identities.length === 6, - "There should be 6 identities" - ); - - console.assert( - Object.keys(getAssignedSites).length === 5, - "There should be 5 site assignments" - ); - console.log("!!!Finished!!!"); + identities.should.have.lengthOf(6, "There should be 6 identity entries"); + Object.keys(getAssignedSites).should.have.lengthOf(5, "There should be 5 site assignments"); }); it("dupeTest", async function() { await this.syncHelper.stopSyncListeners(); - console.log("Test state from sync that duped everything initially"); - await this.syncHelper.setState( DUPE_TEST_SYNC, DUPE_TEST_LOCAL, @@ -209,80 +175,17 @@ describe("Sync", function() { const identities = await this.webExt.browser.contextualIdentities.query({}); - console.assert( - identities.length === 7, - "There should be 7 identities" - ); + identities.should.have.lengthOf(7, "There should be 7 identity entries"); - console.assert( - Object.keys(getAssignedSites).length === 5, - "There should be 5 site assignments" - ); + Object.keys(getAssignedSites).should.have.lengthOf(5, "There should be 5 identity entries"); const personalContainer = this.syncHelper.lookupIdentityBy(identities, {name: "Personal"}); - console.log(personalContainer); - console.assert( - personalContainer.color === "red", - "Personal Container should be red" - ); + (personalContainer.color === "red").should.be.true; + const mozillaContainer = this.syncHelper.lookupIdentityBy(identities, {name: "Mozilla"}); - console.assert( - mozillaContainer.icon === "pet", - "Mozilla Container should be pet" - ); - console.log("!!!Finished!!!"); - }); - - it("CIerrorTest", async function() { - await this.syncHelper.stopSyncListeners(); - console.log("Test state from sync that duped everything initially"); - - await this.syncHelper.setState( - CI_ERROR_TEST_SYNC, - CI_ERROR_TEST_LOCAL, - CI_ERROR_TEST_IDENTS, - CI_ERROR_TEST_SITES - ); - - await this.webExt.background.window.sync.runSync(); - - const getSync = await this.webExt.browser.storage.sync.get(); - const getAssignedSites = - await this.webExt.background.window.assignManager.storageArea.getAssignedSites(); - - const identities = await this.webExt.browser.contextualIdentities.query({}); - - console.assert( - Object.keys(getSync.cookieStoreIDmap).length === 7, - "cookieStoreIDmap should have 7 entries" - ); - - console.assert( - identities.length === 7, - "There should be 7 identities" - ); - - console.assert( - Object.keys(getAssignedSites).length === 5, - "There should be 5 site assignments" - ); - - const personalContainer = - this.syncHelper.lookupIdentityBy(identities, {name: "Personal"}); - console.log(personalContainer); - console.assert( - personalContainer.color === "red", - "Personal Container should be red" - ); - const mozillaContainer = - this.syncHelper.lookupIdentityBy(identities, {name: "Mozilla"}); - console.assert( - mozillaContainer.icon === "pet", - "Mozilla Container should be pet" - ); - console.log("!!!Finished!!!"); + (mozillaContainer.icon === "pet").should.be.true; }); }); @@ -319,13 +222,11 @@ class SyncTestHelper { await this.webExt.browser.storage.local.set({[assignmentData[i]]: data}); } } - console.log("local storage set: ", await this.webExt.browser.storage.local.get()); return; } async removeAllContainers() { const identities = await this.webExt.browser.contextualIdentities.query({}); - console.log(identities); for (const identity of identities) { await this.webExt.browser.contextualIdentities.remove(identity.cookieStoreId); } @@ -561,135 +462,4 @@ const DUPE_TEST_IDENTS = [ "icon": "dollar", "color": "yellow", } -]; - -const CI_ERROR_TEST_SYNC = { - "identities": [ - { - "name": "Personal", - "icon": "fingerprint", - "iconUrl": "resource://usercontext-content/fingerprint.svg", - "color": "blue", - "colorCode": "#37adff", - "cookieStoreId": "firefox-container-6" - }, - { - "name": "Mozilla", - "icon": "fruit", - "iconUrl": "resource://usercontext-content/fruit.svg", - "color": "purple", - "colorCode": "#af51f5", - "cookieStoreId": "firefox-container-8" - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "iconUrl": "resource://usercontext-content/cart.svg", - "color": "yellow", - "colorCode": "#ffcb00", - "cookieStoreId": "firefox-container-9" - }, - { - "name": "Facebook", - "icon": "circle", - "iconUrl": "resource://usercontext-content/circle.svg", - "color": "blue", - "colorCode": "#37adff", - "cookieStoreId": "firefox-container-10" - }, - { - "name": "Work", - "icon": "briefcase", - "iconUrl": "resource://usercontext-content/briefcase.svg", - "color": "orange", - "colorCode": "#ff9f00", - "cookieStoreId": "firefox-container-11" - }, - { - "name": "Greg's container", - "icon": "vacation", - "iconUrl": "resource://usercontext-content/vacation.svg", - "color": "yellow", - "colorCode": "#ffcb00", - "cookieStoreId": "firefox-container-14" - } - ], - "deletedIdentityList": [ - "8098140e-d406-4321-b4f5-24763b4f9513", - "73aebc7a-286f-408a-9a94-a06d29b288e0", - "8f153224-bbe8-4664-ba02-0293ddec3e78" - ], - "cookieStoreIDmap": { - "firefox-container-10": "58956e95-43fb-44af-95c0-1ec8d83e1e13", - "firefox-container-11": "0269558d-6be7-487b-beb1-b720b346d09b", - "firefox-container-14": "e48d04cf-6277-4236-8f3d-611287d0caf2", - "firefox-container-6": "869a7563-030d-4a63-8a84-209270561d3c", - "firefox-container-8": "73aebc7a-286f-408a-9a94-a06d29b288e0", - "firefox-container-9": "4831fef4-6f43-47fb-a578-ccdc3ee7f883" - }, - "assignedSites": { - "siteContainerMap@@_bugzilla.mozilla.org": { - "userContextId": "11", - "neverAsk": true, - "identityMacAddonUUID": "0269558d-6be7-487b-beb1-b720b346d09b", - "hostname": "bugzilla.mozilla.org" - }, - "siteContainerMap@@_www.amazon.com": { - "userContextId": "14", - "neverAsk": false, - "identityMacAddonUUID": "e48d04cf-6277-4236-8f3d-611287d0caf2", - "hostname": "www.amazon.com" - } - }, - "deletedSiteList": [ - "siteContainerMap@@_www.facebook.com" - ] -}; - -const CI_ERROR_TEST_LOCAL = { - "browserActionBadgesClicked": [ - "6.1.1" - ], - "containerTabsOpened": 6, - "onboarding-stage": 5, -}; - -const CI_ERROR_TEST_SITES = [ - "siteContainerMap@@_bugzilla.mozilla.org", - "siteContainerMap@@_www.bankofoklahoma.com", - "siteContainerMap@@_www.mozilla.org", - "siteContainerMap@@_www.reddit.com" -]; - -const CI_ERROR_TEST_IDENTS = [ - { - "name": "Personal", - "icon": "fingerprint", - "color": "blue", - }, - { - "name": "Work", - "icon": "briefcase", - "color": "orange", - }, - { - "name": "Banking", - "icon": "dollar", - "color": "green", - }, - { - "name": "Mozilla", - "icon": "fruit", - "color": "purple", - }, - { - "name": "Groceries, obviously", - "icon": "cart", - "color": "yellow", - }, - { - "name": "Facebook", - "icon": "circle", - "color": "blue", - } ]; \ No newline at end of file From 7ed5085f1099e9818085022c82ae14e3a2e5fdb4 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 10 Feb 2020 12:38:17 -0600 Subject: [PATCH 54/60] changed window attachment of sync to be more clear --- src/js/background/sync.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/js/background/sync.js b/src/js/background/sync.js index 847b7a1..b34ea00 100644 --- a/src/js/background/sync.js +++ b/src/js/background/sync.js @@ -1,6 +1,6 @@ const SYNC_DEBUG = false; -window.sync = { +const sync = { storageArea: { area: browser.storage.sync, @@ -308,6 +308,9 @@ window.sync = { }; +// attaching to window for use in mocha tests +window.sync = sync; + sync.init(); async function restore() { From 06b43c47c05e6e27f2351062958d2a28cf66c40a Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 10 Feb 2020 12:38:45 -0600 Subject: [PATCH 55/60] added new oboarding panel --- src/css/popup.css | 35 +++++++++++++++++++++++++++++------ src/popup.html | 10 ++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/css/popup.css b/src/css/popup.css index 4de07a9..2e54a23 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -356,6 +356,35 @@ table { transition: background-color 75ms; } +.half-button-wrapper { + width: 100%; + flex-direction: row; + display: flex; + align-items: center; + height: 44px; +} + +.half-onboarding-button { + align-items: center; + background-color: #0996f8; + border-radius: 3px; + color: white; + display: flex; + font-size: 14px; + inline-size: 50%; + justify-content: center; + text-decoration: none; + transition: background-color 75ms; + flex: 1 0 auto; + height: 44px; + margin: 0 4px 0 0; +} + +.grey-button { + background-color: #E3E3E3; + color: #000; +} + .onboarding-button:hover, .onboarding-button:active { background-color: #0675d3; @@ -974,9 +1003,3 @@ span ~ .panel-header-text { .amo-rate-cta { background: #0f1126; } - -.no-sync { - line-height: 0; - margin-left: 160px; - text-decoration: underline; -} diff --git a/src/popup.html b/src/popup.html index 8f438c6..27607a8 100644 --- a/src/popup.html +++ b/src/popup.html @@ -69,10 +69,12 @@
Click below to start syncing -

Container and site assignments everywhere.

-

Now containers will sync between installs of the add-on.

- Start Syncing - +

Syncing Containers is now Available!

+

Turn on Sync to share container and site assignments with any computer connected to your Firefox Account.

+
From beb027f1a128979dc646d1603a6f82460a33edc2 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 10 Feb 2020 12:38:57 -0600 Subject: [PATCH 56/60] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e85c870..47dce0c 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ For more info, see: ## Development 1. `npm install` -2. `./node_modules/.bin/web-ext run -s src/` +2. `./node_modules/web-ext/bin/web-ext run -s src/` ### Testing `npm run test` From 4bc6fad83aa27b8e547ec45d9a7da49fac2a64fa Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 10 Feb 2020 14:52:31 -0600 Subject: [PATCH 57/60] added second onboarding panel --- src/css/popup.css | 14 +++++++------- src/img/Account.svg | 1 + src/img/Sync.svg | 1 + src/js/popup.js | 37 ++++++++++++++++++++++++++++++++++--- src/popup.html | 16 +++++++++++++--- 5 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 src/img/Account.svg create mode 100644 src/img/Sync.svg diff --git a/src/css/popup.css b/src/css/popup.css index 2e54a23..2ffbce5 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -357,11 +357,11 @@ table { } .half-button-wrapper { - width: 100%; - flex-direction: row; - display: flex; align-items: center; + display: flex; + flex-direction: row; height: 44px; + inline-size: 100%; } .half-onboarding-button { @@ -370,18 +370,18 @@ table { border-radius: 3px; color: white; display: flex; + flex: 1 0 auto; font-size: 14px; + height: 44px; inline-size: 50%; justify-content: center; + margin-inline-end: 4px; text-decoration: none; transition: background-color 75ms; - flex: 1 0 auto; - height: 44px; - margin: 0 4px 0 0; } .grey-button { - background-color: #E3E3E3; + background-color: #e3e3e3; color: #000; } diff --git a/src/img/Account.svg b/src/img/Account.svg new file mode 100644 index 0000000..4d049d4 --- /dev/null +++ b/src/img/Account.svg @@ -0,0 +1 @@ +account \ No newline at end of file diff --git a/src/img/Sync.svg b/src/img/Sync.svg new file mode 100644 index 0000000..d52b768 --- /dev/null +++ b/src/img/Sync.svg @@ -0,0 +1 @@ +Sync \ No newline at end of file diff --git a/src/js/popup.js b/src/js/popup.js index 208b18b..8c1f4ab 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -18,6 +18,7 @@ const P_ONBOARDING_3 = "onboarding3"; const P_ONBOARDING_4 = "onboarding4"; const P_ONBOARDING_5 = "onboarding5"; const P_ONBOARDING_6 = "onboarding6"; +const P_ONBOARDING_7 = "onboarding7"; const P_CONTAINERS_LIST = "containersList"; const P_CONTAINERS_EDIT = "containersEdit"; const P_CONTAINER_INFO = "containerInfo"; @@ -100,9 +101,12 @@ const Logic = { } switch (onboarded) { - case 6: + case 7: this.showAchievementOrContainersListPanel(); break; + case 6: + this.showPanel(P_ONBOARDING_7); + break; case 5: this.showPanel(P_ONBOARDING_6); break; @@ -532,10 +536,10 @@ Logic.registerPanel(P_ONBOARDING_6, { await browser.runtime.sendMessage({ method: "resetSync" }); - Logic.showPanel(P_CONTAINERS_LIST); + Logic.showPanel(P_ONBOARDING_7); }); Logic.addEnterHandler(document.querySelector("#no-sync"), async () => { - await Logic.setOnboardingStage(6); + await Logic.setOnboardingStage(7); await browser.storage.local.set({syncEnabled: false}); await browser.runtime.sendMessage({ method: "resetSync" @@ -550,6 +554,33 @@ Logic.registerPanel(P_ONBOARDING_6, { }, }); +// P_ONBOARDING_6: Sixth page for Onboarding: new tab long-press behavior +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_ONBOARDING_7, { + panelSelector: ".onboarding-panel-7", + + // This method is called when the object is registered. + initialize() { + // Let's move to the containers list panel. + Logic.addEnterHandler(document.querySelector("#sign-in"), async () => { + browser.tabs.create({ + url: "https://accounts.firefox.com/?service=sync&utm_source=addon&utm_medium=panel&utm_campaign=container-sync", + }); + await Logic.setOnboardingStage(7); + Logic.showPanel(P_CONTAINERS_LIST); + }); + Logic.addEnterHandler(document.querySelector("#no-sign-in"), async () => { + await Logic.setOnboardingStage(7); + Logic.showPanel(P_CONTAINERS_LIST); + }); + }, + + // This method is called when the panel is shown. + prepare() { + return Promise.resolve(null); + }, +}); // P_CONTAINERS_LIST: The list of containers. The main page. // ---------------------------------------------------------------------------- diff --git a/src/popup.html b/src/popup.html index 27607a8..1497212 100644 --- a/src/popup.html +++ b/src/popup.html @@ -68,12 +68,22 @@
- Click below to start syncing + Syncing Containers is now Available!

Syncing Containers is now Available!

Turn on Sync to share container and site assignments with any computer connected to your Firefox Account.

+
+ +
+ Firefox Account is required to sync +

Firefox Account is required to sync.

+

Click Sign In to confirm that your Firefox Account is active.

+
From f56f9b0ea8e670f594926778a3e7599b438f142a Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 10 Feb 2020 16:00:47 -0600 Subject: [PATCH 58/60] fixed tests --- test/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common.js b/test/common.js index b87fe1c..8640afa 100644 --- a/test/common.js +++ b/test/common.js @@ -85,7 +85,7 @@ const initializeWithTab = async (details = { beforeParse(window) { window.browser.storage.local.set({ "browserActionBadgesClicked": [], - "onboarding-stage": 6, + "onboarding-stage": 7, "achievements": [], "syncEnabled": true }); From 8cdfe0191f4176575d2715b2c6714577059f9621 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 10 Feb 2020 16:55:48 -0600 Subject: [PATCH 59/60] fixed url for syn setup --- 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 8c1f4ab..b93981d 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -565,7 +565,7 @@ Logic.registerPanel(P_ONBOARDING_7, { // Let's move to the containers list panel. Logic.addEnterHandler(document.querySelector("#sign-in"), async () => { browser.tabs.create({ - url: "https://accounts.firefox.com/?service=sync&utm_source=addon&utm_medium=panel&utm_campaign=container-sync", + url: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=multi-account-containers&utm_source=addon&utm_medium=panel&utm_campaign=container-sync", }); await Logic.setOnboardingStage(7); Logic.showPanel(P_CONTAINERS_LIST); From 00ace352e8d93101bcfefcf61f393121f47d9016 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Mon, 10 Feb 2020 17:09:20 -0600 Subject: [PATCH 60/60] upped version and added action badge --- package.json | 2 +- src/js/background/badge.js | 2 +- src/manifest.json | 2 +- test/features/sync.test.js | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ea3893a..1258571 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "testpilot-containers", "title": "Multi-Account Containers", "description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", - "version": "6.1.5", + "version": "6.2.0", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/multi-account-containers/issues" diff --git a/src/js/background/badge.js b/src/js/background/badge.js index 7d532ac..7b6ccf3 100644 --- a/src/js/background/badge.js +++ b/src/js/background/badge.js @@ -1,4 +1,4 @@ -const MAJOR_VERSIONS = ["2.3.0", "2.4.0"]; +const MAJOR_VERSIONS = ["2.3.0", "2.4.0", "6.2.0"]; const badge = { async init() { const currentWindow = await browser.windows.getCurrent(); diff --git a/src/manifest.json b/src/manifest.json index cd6d097..5dfc37b 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Firefox Multi-Account Containers", - "version": "6.1.5", + "version": "6.2.0", "incognito": "not_allowed", "description": "Multi-Account Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", "icons": { diff --git a/test/features/sync.test.js b/test/features/sync.test.js index b646c71..1e4070a 100644 --- a/test/features/sync.test.js +++ b/test/features/sync.test.js @@ -285,7 +285,7 @@ const TEST_ASSIGNMENTS = [ ]; const LOCAL_DATA = { - "browserActionBadgesClicked": [ "6.1.1" ], + "browserActionBadgesClicked": [ "6.2.0" ], "containerTabsOpened": 7, "identitiesState@@_firefox-default": { "hiddenTabs": [] }, "onboarding-stage": 5 @@ -407,7 +407,7 @@ const DUPE_TEST_SYNC = { const DUPE_TEST_LOCAL = { "beenSynced": true, "browserActionBadgesClicked": [ - "6.1.1" + "6.2.0" ], "containerTabsOpened": 7, "identitiesState@@_firefox-default": {