From f33b3b39c0217e36a7b0eddf440e434db461827f Mon Sep 17 00:00:00 2001 From: Jo IE Date: Mon, 7 Oct 2019 18:02:40 +0100 Subject: [PATCH 001/146] remove HTML entities from tooltip --- src/js/popup.js | 70 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/js/popup.js b/src/js/popup.js index 80986a2..e5b4dbf 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -12,15 +12,15 @@ const NEW_CONTAINER_ID = "new"; const ONBOARDING_STORAGE_KEY = "onboarding-stage"; // List of panels -const P_ONBOARDING_1 = "onboarding1"; -const P_ONBOARDING_2 = "onboarding2"; -const P_ONBOARDING_3 = "onboarding3"; -const P_ONBOARDING_4 = "onboarding4"; -const P_ONBOARDING_5 = "onboarding5"; -const P_CONTAINERS_LIST = "containersList"; -const P_CONTAINERS_EDIT = "containersEdit"; -const P_CONTAINER_INFO = "containerInfo"; -const P_CONTAINER_EDIT = "containerEdit"; +const P_ONBOARDING_1 = "onboarding1"; +const P_ONBOARDING_2 = "onboarding2"; +const P_ONBOARDING_3 = "onboarding3"; +const P_ONBOARDING_4 = "onboarding4"; +const P_ONBOARDING_5 = "onboarding5"; +const P_CONTAINERS_LIST = "containersList"; +const P_CONTAINERS_EDIT = "containersEdit"; +const P_CONTAINER_INFO = "containerInfo"; +const P_CONTAINER_EDIT = "containerEdit"; const P_CONTAINER_DELETE = "containerDelete"; const P_CONTAINERS_ACHIEVEMENT = "containersAchievement"; @@ -32,7 +32,7 @@ const P_CONTAINERS_ACHIEVEMENT = "containersAchievement"; * @return {string} The escaped string. */ function escapeXML(str) { - const replacements = {"&": "&", "\"": """, "'": "'", "<": "<", ">": ">", "/": "/"}; + const replacements = { "&": "&", "\"": """, "'": "'", "<": "<", ">": ">", "/": "/" }; return String(str).replace(/[&"'<>/]/g, m => replacements[m]); } @@ -85,7 +85,7 @@ const Logic = { try { await identitiesPromise; - } catch(e) { + } catch (e) { throw new Error("Failed to retrieve the identities or variation. We cannot continue. ", e.message); } @@ -125,7 +125,7 @@ const Logic = { async showAchievementOrContainersListPanel() { // Do we need to show an achievement panel? let showAchievements = false; - const achievementsStorage = await browser.storage.local.get({achievements: []}); + const achievementsStorage = await browser.storage.local.get({ achievements: [] }); for (const achievement of achievementsStorage.achievements) { if (!achievement.done) { showAchievements = true; @@ -142,7 +142,7 @@ const Logic = { // they have to click the "Done" button to stop the panel // from showing async setAchievementDone(achievementName) { - const achievementsStorage = await browser.storage.local.get({achievements: []}); + const achievementsStorage = await browser.storage.local.get({ achievements: [] }); const achievements = achievementsStorage.achievements; achievements.forEach((achievement, index, achievementsArray) => { if (achievement.name === achievementName) { @@ -150,7 +150,7 @@ const Logic = { achievementsArray[index] = achievement; } }); - browser.storage.local.set({achievements}); + browser.storage.local.set({ achievements }); }, setOnboardingStage(stage) { @@ -161,9 +161,9 @@ const Logic = { async clearBrowserActionBadge() { const extensionInfo = await getExtensionInfo(); - const storage = await browser.storage.local.get({browserActionBadgesClicked: []}); - browser.browserAction.setBadgeBackgroundColor({color: null}); - browser.browserAction.setBadgeText({text: ""}); + const storage = await browser.storage.local.get({ browserActionBadgesClicked: [] }); + browser.browserAction.setBadgeBackgroundColor({ color: null }); + browser.browserAction.setBadgeText({ text: "" }); storage.browserActionBadgesClicked.push(extensionInfo.version); // use set and spread to create a unique array const browserActionBadgesClicked = [...new Set(storage.browserActionBadgesClicked)]; @@ -184,7 +184,7 @@ const Logic = { // Handle old style rejection with null and also Promise.reject new style try { return await browser.contextualIdentities.get(cookieStoreId) || defaultContainer; - } catch(e) { + } catch (e) { return defaultContainer; } }, @@ -207,7 +207,7 @@ const Logic = { }, async currentTab() { - const activeTabs = await browser.tabs.query({active: true, windowId: browser.windows.WINDOW_ID_CURRENT}); + const activeTabs = await browser.tabs.query({ active: true, windowId: browser.windows.WINDOW_ID_CURRENT }); if (activeTabs.length > 0) { return activeTabs[0]; } @@ -215,7 +215,7 @@ const Logic = { }, async numTabs() { - const activeTabs = await browser.tabs.query({windowId: browser.windows.WINDOW_ID_CURRENT}); + const activeTabs = await browser.tabs.query({ windowId: browser.windows.WINDOW_ID_CURRENT }); return activeTabs.length; }, @@ -259,7 +259,7 @@ const Logic = { getPanelSelector(panel) { if (this._onboardingVariation === "securityOnboarding" && - panel.hasOwnProperty("securityPanelSelector")) { + panel.hasOwnProperty("securityPanelSelector")) { return panel.securityPanelSelector; } else { return panel.panelSelector; @@ -333,7 +333,7 @@ const Logic = { return browser.runtime.sendMessage({ method: "deleteContainer", - message: {userContextId} + message: { userContextId } }); }, @@ -347,7 +347,7 @@ const Logic = { getAssignmentObjectByContainer(userContextId) { return browser.runtime.sendMessage({ method: "getAssignmentObjectByContainer", - message: {userContextId} + message: { userContextId } }); }, @@ -376,7 +376,7 @@ const Logic = { }); // Here we find the first valid id. - for (let id = 1;; ++id) { + for (let id = 1; ; ++id) { if (ids.indexOf(id) === -1) { return defaultName + (id < 10 ? "0" : "") + id; } @@ -511,7 +511,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, { }); Logic.addEnterHandler(document.querySelector("#edit-containers-link"), (e) => { - if (!e.target.classList.contains("disable-edit-containers")){ + if (!e.target.classList.contains("disable-edit-containers")) { Logic.showPanel(P_CONTAINERS_EDIT); } }); @@ -637,9 +637,9 @@ Logic.registerPanel(P_CONTAINERS_LIST, { context.classList.add("userContext-wrapper", "open-newtab", "clickable"); manage.classList.add("show-tabs", "pop-button"); - manage.title = escaped`View ${identity.name} container`; + manage.setAttribute("title", `View ${identity.name} container`); context.setAttribute("tabindex", "0"); - context.title = escaped`Create ${identity.name} tab`; + context.setAttribute("title", `Create ${identity.name} tab`); context.innerHTML = escaped`
{ if (e.target.matches(".open-newtab") - || e.target.parentNode.matches(".open-newtab") - || e.type === "keydown") { + || e.target.parentNode.matches(".open-newtab") + || e.type === "keydown") { try { browser.tabs.create({ cookieStoreId: identity.cookieStoreId @@ -747,7 +747,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { return; } else if (numTabs === 1) { Logic._disableMoveTabs("Cannot move a tab from a single-tab window."); - return; + return; } Logic.addEnterHandler(moveTabsEl, async () => { await browser.runtime.sendMessage({ @@ -808,7 +808,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
${tab.title}
`; tr.querySelector("td").appendChild(Utils.createFavIconElement(tab.favIconUrl)); document.getElementById("container-info-table").appendChild(fragment); - + // On click, we activate this tab. But only if this tab is active. if (!tab.hiddenState) { const closeImage = document.createElement("img"); @@ -830,7 +830,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { tr.classList.add("clickable"); Logic.addEnterHandler(tr, async () => { - await browser.tabs.update(tab.id, {active: true}); + await browser.tabs.update(tab.id, { active: true }); window.close(); }); @@ -842,7 +842,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { }); } } - } + } }, }); @@ -1018,7 +1018,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { return escaped`
From 426e81b88ba62e77488944529309299a789c3a06 Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 18 Dec 2019 09:02:02 +0100 Subject: [PATCH 026/146] Fix eslint errors after bump to 6.6.0 (#1595) * Bump eslint from 3.19.0 to 6.6.0 Bumps [eslint](https://github.com/eslint/eslint) from 3.19.0 to 6.6.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v3.19.0...v6.6.0) Signed-off-by: dependabot[bot] * Fix (and suppress) eslint errors --- package.json | 2 +- src/js/background/messageHandler.js | 1 + src/js/popup.js | 25 +++++++++++++------------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index b72d3d5..eb31d53 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "addons-linter": "^1.3.2", "ajv": "^6.6.2", "chai": "^4.1.2", - "eslint": "^3.17.1", + "eslint": "^6.6.0", "eslint-plugin-no-unsanitized": "^2.0.0", "eslint-plugin-promise": "^3.4.0", "htmllint-cli": "0.0.7", diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index fa95181..9578e6e 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -82,6 +82,7 @@ const messageHandler = { if (!extensionInfo.permissions.includes("contextualIdentities")) { throw new Error("Missing contextualIdentities permission"); } + // eslint-disable-next-line require-atomic-updates externalExtensionAllowed[sender.id] = true; } let response; diff --git a/src/js/popup.js b/src/js/popup.js index 433db3c..64dca45 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -259,6 +259,7 @@ const Logic = { getPanelSelector(panel) { if (this._onboardingVariation === "securityOnboarding" && + // eslint-disable-next-line no-prototype-builtins panel.hasOwnProperty("securityPanelSelector")) { return panel.securityPanelSelector; } else { @@ -570,21 +571,21 @@ Logic.registerPanel(P_CONTAINERS_LIST, { break; } case 39: - { - const showTabs = element.parentNode.querySelector(".show-tabs"); - if(showTabs) { - showTabs.click(); - } - break; + { + const showTabs = element.parentNode.querySelector(".show-tabs"); + if(showTabs) { + showTabs.click(); } + break; + } case 37: - { - const hideTabs = document.querySelector(".panel-back-arrow"); - if(hideTabs) { - hideTabs.click(); - } - break; + { + const hideTabs = document.querySelector(".panel-back-arrow"); + if(hideTabs) { + hideTabs.click(); } + break; + } default: if ((e.keyCode >= 49 && e.keyCode <= 57) && Logic._currentPanel === "containersList") { From 96ab4685e922e5120aac5245a5ae77bd94952aa0 Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 18 Dec 2019 09:13:41 +0100 Subject: [PATCH 027/146] Bump test dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index eb31d53..3bfcfba 100644 --- a/package.json +++ b/package.json @@ -11,17 +11,17 @@ "devDependencies": { "addons-linter": "^1.3.2", "ajv": "^6.6.2", - "chai": "^4.1.2", + "chai": "^4.2.0", "eslint": "^6.6.0", "eslint-plugin-no-unsanitized": "^2.0.0", "eslint-plugin-promise": "^3.4.0", "htmllint-cli": "0.0.7", "jsdom": "^11.6.2", "json": "^9.0.6", - "mocha": "^5.0.0", + "mocha": "^6.2.2", "npm-run-all": "^4.0.0", - "sinon": "^4.4.0", - "sinon-chai": "^2.14.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", From 77fd843b3de62903f56ffd72ce92421610bebfab Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 18 Dec 2019 09:18:10 +0100 Subject: [PATCH 028/146] Replace manual mock/jsdom with webextensions-jsdom --- package.json | 4 +- test/.eslintrc.js | 4 ++ test/browser.mock.js | 149 ------------------------------------------- test/helper.js | 63 +++++++++--------- test/setup.js | 110 +++++++++++++------------------- 5 files changed, 81 insertions(+), 249 deletions(-) delete mode 100644 test/browser.mock.js diff --git a/package.json b/package.json index 3bfcfba..bf05207 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "eslint-plugin-no-unsanitized": "^2.0.0", "eslint-plugin-promise": "^3.4.0", "htmllint-cli": "0.0.7", - "jsdom": "^11.6.2", "json": "^9.0.6", "mocha": "^6.2.2", "npm-run-all": "^4.0.0", @@ -25,7 +24,8 @@ "stylelint": "^7.9.0", "stylelint-config-standard": "^16.0.0", "stylelint-order": "^0.3.0", - "web-ext": "^2.9.3" + "web-ext": "^2.9.3", + "webextensions-jsdom": "^1.1.0" }, "homepage": "https://github.com/mozilla/multi-account-containers#readme", "license": "MPL-2.0", diff --git a/test/.eslintrc.js b/test/.eslintrc.js index 0b29fac..d32e265 100644 --- a/test/.eslintrc.js +++ b/test/.eslintrc.js @@ -3,10 +3,14 @@ module.exports = { "node": true, "mocha": true }, + "parserOptions": { + "ecmaVersion": 2018 + }, globals: { "sinon": false, "expect": false, "nextTick": false, + "buildDom": false, "buildBackgroundDom": false, "background": false, "buildPopupDom": false, diff --git a/test/browser.mock.js b/test/browser.mock.js deleted file mode 100644 index ad52c3d..0000000 --- a/test/browser.mock.js +++ /dev/null @@ -1,149 +0,0 @@ -module.exports = () => { - const _storage = {}; - - // could maybe be replaced by https://github.com/acvetkov/sinon-chrome - const browserMock = { - _storage, - runtime: { - onMessage: { - addListener: sinon.stub(), - }, - onMessageExternal: { - addListener: sinon.stub(), - }, - sendMessage: sinon.stub().resolves(), - }, - webRequest: { - onBeforeRequest: { - addListener: sinon.stub() - }, - onCompleted: { - addListener: sinon.stub() - }, - onErrorOccurred: { - addListener: sinon.stub() - } - }, - windows: { - getCurrent: sinon.stub().resolves({}), - onFocusChanged: { - addListener: sinon.stub(), - } - }, - tabs: { - onActivated: { - addListener: sinon.stub() - }, - onCreated: { - addListener: sinon.stub() - }, - onUpdated: { - addListener: sinon.stub() - }, - sendMessage: sinon.stub(), - query: sinon.stub().resolves([{}]), - get: sinon.stub(), - create: sinon.stub().resolves({}), - remove: sinon.stub().resolves() - }, - history: { - deleteUrl: sinon.stub() - }, - storage: { - local: { - get: sinon.stub(), - set: sinon.stub() - } - }, - contextualIdentities: { - create: sinon.stub(), - get: sinon.stub(), - query: sinon.stub().resolves([]), - onCreated: { - addListener: sinon.stub() - }, - onUpdated: { - addListener: sinon.stub() - }, - onRemoved: { - addListener: sinon.stub() - } - }, - contextMenus: { - create: sinon.stub(), - remove: sinon.stub(), - onClicked: { - addListener: sinon.stub() - } - }, - browserAction: { - setBadgeBackgroundColor: sinon.stub(), - setBadgeText: sinon.stub() - }, - management: { - get: sinon.stub(), - onInstalled: { - addListener: sinon.stub() - }, - onUninstalled: { - addListener: sinon.stub() - } - }, - extension: { - getURL: sinon.stub().returns("moz-extension://multi-account-containers/confirm-page.html") - }, - permissions: { - contains: sinon.stub().returns(true) - } - }; - - // inmemory local storage - browserMock.storage.local = { - get: sinon.spy(async key => { - if (!key) { - return _storage; - } - let result = {}; - if (Array.isArray(key)) { - key.map(akey => { - if (typeof _storage[akey] !== "undefined") { - result[akey] = _storage[akey]; - } - }); - } else if (typeof key === "object") { - // TODO support nested objects - Object.keys(key).map(oKey => { - if (typeof _storage[oKey] !== "undefined") { - result[oKey] = _storage[oKey]; - } else { - result[oKey] = key[oKey]; - } - }); - } else { - result = _storage[key]; - } - return result; - }), - set: sinon.spy(async (key, value) => { - if (typeof key === "object") { - // TODO support nested objects - Object.keys(key).map(oKey => { - _storage[oKey] = key[oKey]; - }); - } else { - _storage[key] = value; - } - }), - remove: sinon.spy(async (key) => { - if (Array.isArray(key)) { - key.map(aKey => { - delete _storage[aKey]; - }); - } else { - delete _storage[key]; - } - }), - }; - - return browserMock; -}; diff --git a/test/helper.js b/test/helper.js index 555ee7a..2704bac 100644 --- a/test/helper.js +++ b/test/helper.js @@ -1,47 +1,44 @@ module.exports = { browser: { - async initializeWithTab(tab) { - await buildBackgroundDom({ - beforeParse(window) { - window.browser.tabs.get.resolves(tab); - window.browser.tabs.query.resolves([tab]); - window.browser.contextualIdentities.get.resolves({ - cookieStoreId: tab.cookieStoreId - }); - } - }); - await buildPopupDom({ - beforeParse(window) { - window.browser.tabs.get.resolves(tab); - window.browser.tabs.query.resolves([tab]); + 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": 5, + "achievements": [] + }); + window.browser.storage.local.set.resetHistory(); + } + } } }); + + return tab; }, async openNewTab(tab, options = {}) { - if (options.resetHistory) { - background.browser.tabs.create.resetHistory(); - background.browser.tabs.remove.resetHistory(); - } - background.browser.tabs.get.resolves(tab); - background.browser.tabs.onCreated.addListener.yield(tab); - const [promise] = background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: tab.id, - url: tab.url, - requestId: options.requestId - }); - - return promise; + return background.browser.tabs._create(tab, options); } }, popup: { async clickElementById(id) { - const clickEvent = popup.document.createEvent("HTMLEvents"); - clickEvent.initEvent("click"); - popup.document.getElementById(id).dispatchEvent(clickEvent); - await nextTick(); + await popup.helper.clickElementById(id); + }, + + async clickLastMatchingElementByQuerySelector(querySelector) { + await popup.helper.clickElementByQuerySelectorAll(querySelector, "last"); } - }, + } }; diff --git a/test/setup.js b/test/setup.js index b6d563d..0cc45ee 100644 --- a/test/setup.js +++ b/test/setup.js @@ -2,7 +2,6 @@ if (!process.listenerCount("unhandledRejection")) { // eslint-disable-next-line no-console process.on("unhandledRejection", r => console.log(r)); } -const jsdom = require("jsdom"); const path = require("path"); const chai = require("chai"); const sinonChai = require("sinon-chai"); @@ -19,83 +18,64 @@ global.nextTick = () => { }; global.helper = require("./helper"); -const browserMock = require("./browser.mock"); -const srcBasePath = path.resolve(path.join(__dirname, "..", "src")); -const srcJsBackgroundPath = path.join(srcBasePath, "js", "background"); -global.buildBackgroundDom = async (options = {}) => { - const dom = await jsdom.JSDOM.fromFile(path.join(srcJsBackgroundPath, "index.html"), { - runScripts: "dangerously", - resources: "usable", - virtualConsole: (new jsdom.VirtualConsole).sendTo(console), - beforeParse(window) { - window.browser = browserMock(); - window.fetch = sinon.stub().resolves({ - json: sinon.stub().resolves({}) - }); - if (options.beforeParse) { - options.beforeParse(window); +const webExtensionsJSDOM = require("webextensions-jsdom"); +const manifestPath = path.resolve(path.join(__dirname, "../src/manifest.json")); + +global.buildDom = async ({background = {}, popup = {}}) => { + background = { + ...background, + jsdom: { + ...background.jsom, + beforeParse(window) { + window.browser.permissions.getAll.resolves({permissions: ["bookmarks"]}); } } - }); - await new Promise(resolve => { - dom.window.document.addEventListener("DOMContentLoaded", resolve); - }); - await nextTick(); - - global.background = { - dom, - browser: dom.window.browser }; -}; -global.buildPopupDom = async (options = {}) => { - const dom = await jsdom.JSDOM.fromFile(path.join(srcBasePath, "popup.html"), { - runScripts: "dangerously", - resources: "usable", - virtualConsole: (new jsdom.VirtualConsole).sendTo(console), - beforeParse(window) { - window.browser = browserMock(); - window.browser.storage.local.set("browserActionBadgesClicked", []); - window.browser.storage.local.set("onboarding-stage", 5); - window.browser.storage.local.set("achievements", []); - window.browser.storage.local.set.resetHistory(); - window.fetch = sinon.stub().resolves({ - json: sinon.stub().resolves({}) - }); - - if (options.beforeParse) { - options.beforeParse(window); - } + popup = { + ...popup, + jsdom: { + ...popup.jsdom, + pretendToBeVisual: true } - }); - await new Promise(resolve => { - dom.window.document.addEventListener("DOMContentLoaded", resolve); - }); - await nextTick(); - dom.window.browser.runtime.sendMessage.resetHistory(); - - if (global.background) { - dom.window.browser.runtime.sendMessage = sinon.spy(function() { - global.background.browser.runtime.onMessage.addListener.yield(...arguments); - }); - } - - global.popup = { - dom, - document: dom.window.document, - browser: dom.window.browser }; + + const webExtension = await webExtensionsJSDOM.fromManifest(manifestPath, { + apiFake: true, + wiring: true, + sinon: global.sinon, + background, + popup + }); + + // eslint-disable-next-line require-atomic-updates + global.background = webExtension.background; + // eslint-disable-next-line require-atomic-updates + global.popup = webExtension.popup; }; +global.buildBackgroundDom = async background => { + await global.buildDom({ + background, + popup: false + }); +}; + +global.buildPopupDom = async popup => { + await global.buildDom({ + popup, + background: false + }); +}; + + global.afterEach(() => { if (global.background) { - global.background.dom.window.close(); - delete global.background; + global.background.destroy(); } if (global.popup) { - global.popup.dom.window.close(); - delete global.popup; + global.popup.destroy(); } }); From 5eb79949e9876a45aba96b8103ed43ec0c996371 Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 18 Dec 2019 09:19:01 +0100 Subject: [PATCH 029/146] Adapt existing tests to use webextensions-jsdom --- test/features/assignment.test.js | 49 ++-- test/features/external-webextensions.test.js | 48 ++-- test/issues/940.test.js | 236 +++++++++---------- 3 files changed, 153 insertions(+), 180 deletions(-) diff --git a/test/features/assignment.test.js b/test/features/assignment.test.js index 632c60b..43bb981 100644 --- a/test/features/assignment.test.js +++ b/test/features/assignment.test.js @@ -1,12 +1,12 @@ describe("Assignment Feature", () => { - const activeTab = { - id: 1, - cookieStoreId: "firefox-container-1", - url: "http://example.com", - index: 0 - }; + const url = "http://example.com"; + + let activeTab; beforeEach(async () => { - await helper.browser.initializeWithTab(activeTab); + activeTab = await helper.browser.initializeWithTab({ + cookieStoreId: "firefox-container-1", + url + }); }); describe("click the 'Always open in' checkbox in the popup", () => { @@ -16,23 +16,24 @@ describe("Assignment Feature", () => { }); describe("open new Tab with the assigned URL in the default container", () => { - const newTab = { - id: 2, - cookieStoreId: "firefox-default", - url: activeTab.url, - index: 1, - active: true - }; + let newTab; beforeEach(async () => { // new Tab opening activeTab.url in default container - await helper.browser.openNewTab(newTab); + newTab = await helper.browser.openNewTab({ + cookieStoreId: "firefox-default", + url + }, { + options: { + webRequestError: true // because request is canceled due to reopening + } + }); }); it("should open the confirm page", async () => { // should have created a new tab with the confirm page - background.browser.tabs.create.should.have.been.calledWith({ - url: "moz-extension://multi-account-containers/confirm-page.html?" + - `url=${encodeURIComponent(activeTab.url)}` + + background.browser.tabs.create.should.have.been.calledWithMatch({ + url: "moz-extension://fake/confirm-page.html?" + + `url=${encodeURIComponent(url)}` + `&cookieStoreId=${activeTab.cookieStoreId}`, cookieStoreId: undefined, openerTabId: null, @@ -53,16 +54,12 @@ describe("Assignment Feature", () => { }); describe("open new Tab with the no longer assigned URL in the default container", () => { - const newTab = { - id: 3, - cookieStoreId: "firefox-default", - url: activeTab.url, - index: 3, - active: true - }; beforeEach(async () => { // new Tab opening activeTab.url in default container - await helper.browser.openNewTab(newTab); + await helper.browser.openNewTab({ + cookieStoreId: "firefox-default", + url + }); }); it("should not open the confirm page", async () => { diff --git a/test/features/external-webextensions.test.js b/test/features/external-webextensions.test.js index fe32e4d..30e6b49 100644 --- a/test/features/external-webextensions.test.js +++ b/test/features/external-webextensions.test.js @@ -1,12 +1,11 @@ describe("External Webextensions", () => { - const activeTab = { - id: 1, - cookieStoreId: "firefox-container-1", - url: "http://example.com", - index: 0 - }; + const url = "http://example.com"; + beforeEach(async () => { - await helper.browser.initializeWithTab(activeTab); + await helper.browser.initializeWithTab({ + cookieStoreId: "firefox-container-1", + url + }); await helper.popup.clickElementById("container-page-assigned"); }); @@ -18,25 +17,18 @@ describe("External Webextensions", () => { const message = { method: "getAssignment", - url: "http://example.com" + url }; const sender = { id: "external-webextension" }; - // currently not possible to get the return value of yielding with sinon - // so we expect that if no error is thrown and the storage was called, everything is ok - // maybe i get around to provide a PR https://github.com/sinonjs/sinon/issues/903 - // - // the alternative would be to expose the actual messageHandler and call it directly - // but personally i think that goes against the black-box-ish nature of these feature tests - const rejectionStub = sinon.stub(); - process.on("unhandledRejection", rejectionStub); - background.browser.runtime.onMessageExternal.addListener.yield(message, sender); - await nextTick(); - process.removeListener("unhandledRejection", rejectionStub); - rejectionStub.should.not.have.been.called; - background.browser.storage.local.get.should.have.been.called; + const [promise] = background.browser.runtime.onMessageExternal.addListener.yield(message, sender); + const answer = await promise; + expect(answer).to.deep.equal({ + userContextId: "1", + neverAsk: false + }); }); }); @@ -48,20 +40,16 @@ describe("External Webextensions", () => { const message = { method: "getAssignment", - url: "http://example.com" + url }; const sender = { id: "external-webextension" }; - const rejectionStub = sinon.spy(); - process.on("unhandledRejection", rejectionStub); - background.browser.runtime.onMessageExternal.addListener.yield(message, sender); - await nextTick(); - process.removeListener("unhandledRejection", rejectionStub); - rejectionStub.should.have.been.calledWith(sinon.match({ - message: "Missing contextualIdentities permission" - })); + const [promise] = background.browser.runtime.onMessageExternal.addListener.yield(message, sender); + return promise.catch(error => { + expect(error.message).to.equal("Missing contextualIdentities permission"); + }); }); }); }); diff --git a/test/issues/940.test.js b/test/issues/940.test.js index b889035..4a7eb0e 100644 --- a/test/issues/940.test.js +++ b/test/issues/940.test.js @@ -1,112 +1,82 @@ describe("#940", () => { describe("when other onBeforeRequestHandlers are faster and redirect with the same requestId", () => { it("should not open two confirm pages", async () => { - // init - const activeTab = { - id: 1, + await helper.browser.initializeWithTab({ cookieStoreId: "firefox-container-1", - url: "http://example.com", - index: 0 - }; - await helper.browser.initializeWithTab(activeTab); - // assign the activeTab.url + url: "http://example.com" + }); await helper.popup.clickElementById("container-page-assigned"); - // start request and don't await the requests at all - // so the second request below is actually comparable to an actual redirect that also fires immediately - const newTab = { - id: 2, - cookieStoreId: "firefox-default", - url: activeTab.url, - index: 1, - active: true - }; - helper.browser.openNewTab(newTab, { - requestId: 1 + const responses = {}; + await helper.browser.openNewTab({ + url: "http://example.com" + }, { + options: { + webRequestRedirects: ["https://example.com"], + webRequestError: true, + instantRedirects: true + }, + responses }); - // other addon sees the same request - // and redirects to the https version of activeTab.url - // since it's a redirect the request has the same requestId - background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: newTab.id, - url: "https://example.com", - requestId: 1 + const result = await responses.webRequest.onBeforeRequest[1]; + expect(result).to.deep.equal({ + cancel: true }); - await nextTick(); - background.browser.tabs.create.should.have.been.calledOnce; }); }); describe("when redirects change requestId midflight", () => { - let promiseResults; + 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 () => { - // init - const activeTab = { - id: 1, + await helper.browser.initializeWithTab({ cookieStoreId: "firefox-container-1", - url: "https://www.youtube.com", - index: 0 - }; - await helper.browser.initializeWithTab(activeTab); - // assign the activeTab.url + url: "https://www.youtube.com" + }); await helper.popup.clickElementById("container-page-assigned"); - - // http://youtube.com - const newTab = { - id: 2, - cookieStoreId: "firefox-default", - url: "http://youtube.com", - index: 1, - active: true - }; - const promise1 = helper.browser.openNewTab(newTab, { - requestId: 1 - }); - - // https://youtube.com - const [promise2] = background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: newTab.id, - url: "https://youtube.com", - requestId: 1 - }); - - // https://www.youtube.com - const [promise3] = background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: newTab.id, - url: "https://www.youtube.com", - requestId: 1 - }); - - // https://www.youtube.com - const [promise4] = background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: newTab.id, - url: "https://www.youtube.com", - requestId: 2 - }); - - promiseResults = await Promise.all([promise1, promise2, promise3, promise4]); }); it("should not open two confirm pages", async () => { + await redirectedRequest(); + // http://youtube.com is not assigned, no cancel, no reopening - expect(promiseResults[0]).to.deep.equal({}); + expect(await newTabResponses.webRequest.onBeforeRequest[0]).to.deep.equal({}); // https://youtube.com is not assigned, no cancel, no reopening - expect(promiseResults[1]).to.deep.equal({}); + expect(await newTabResponses.webRequest.onBeforeRequest[1]).to.deep.equal({}); // https://www.youtube.com is assigned, this triggers reopening, cancel - expect(promiseResults[2]).to.deep.equal({ + expect(await newTabResponses.webRequest.onBeforeRequest[2]).to.deep.equal({ cancel: true }); // https://www.youtube.com is assigned, this was a redirect, cancel early, no reopening - expect(promiseResults[3]).to.deep.equal({ + expect(await newTabResponses.webRequest.onBeforeRequest[3]).to.deep.equal({ cancel: true }); @@ -114,67 +84,85 @@ describe("#940", () => { }); it("should uncancel after webRequest.onCompleted", async () => { - const [promise1] = background.browser.webRequest.onCompleted.addListener.yield({ - tabId: 2 + await 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(); + // we create a tab with the same id and use the same request id to see if uncanceled + await helper.browser.openNewTab({ + id: newTab.id, + url: "https://www.youtube.com" + }, { + options: { + webRequest: { + requestId: newTabResponses.webRequest.request.requestId + } + } }); - await promise1; - const [promise2] = background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: 2, - url: "https://www.youtube.com", - requestId: 123 - }); - await promise2; - - background.browser.tabs.create.should.have.been.calledTwice; + background.browser.tabs.create.should.have.been.calledOnce; }); it("should uncancel after webRequest.onErrorOccurred", async () => { - const [promise1] = background.browser.webRequest.onErrorOccurred.addListener.yield({ - tabId: 2 + await redirectedRequest(); + 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({ + id: newTab.id, + url: "https://www.youtube.com" + }, { + options: { + webRequest: { + requestId: newTabResponses.webRequest.request.requestId + }, + webRequestError: true + } }); - await promise1; - // request to assigned url in same tab - const [promise2] = background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: 2, - url: "https://www.youtube.com", - requestId: 123 - }); - await promise2; - - background.browser.tabs.create.should.have.been.calledTwice; + background.browser.tabs.create.should.have.been.calledOnce; }); it("should uncancel after 2 seconds", async () => { - await new Promise(resolve => setTimeout(resolve, 2000)); - // request to assigned url in same tab - const [promise2] = background.browser.webRequest.onBeforeRequest.addListener.yield({ - frameId: 0, - tabId: 2, - url: "https://www.youtube.com", - requestId: 123 + await redirectedRequest({ + webRequestDontYield: ["onCompleted", "onErrorOccurred"] }); - await promise2; + global.clock.tick(2000); - background.browser.tabs.create.should.have.been.calledTwice; - }).timeout(2002); + 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({ + id: newTab.id, + url: "https://www.youtube.com" + }, { + options: { + webRequest: { + requestId: newTabResponses.webRequest.request.requestId + }, + webRequestError: true + } + }); + + background.browser.tabs.create.should.have.been.calledOnce; + }); it("should not influence the canceled url in other tabs", async () => { - const newTab = { - id: 123, + await redirectedRequest(); + background.browser.tabs.create.resetHistory(); + await helper.browser.openNewTab({ cookieStoreId: "firefox-default", - url: "https://www.youtube.com", - index: 10, - active: true - }; - await helper.browser.openNewTab(newTab, { - requestId: 321 + url: "https://www.youtube.com" + }, { + options: { + webRequestError: true + } }); - background.browser.tabs.create.should.have.been.calledTwice; + background.browser.tabs.create.should.have.been.calledOnce; + }); + + afterEach(() => { + global.clock.restore(); }); }); }); From 703a7cd3c20c2c8be4ef744471a1a3eef8fa2d6b Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 18 Dec 2019 09:24:05 +0100 Subject: [PATCH 030/146] Add test coverage with nyc --- .eslintignore | 1 + .gitignore | 4 ++++ package.json | 6 ++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.eslintignore b/.eslintignore index 9f1953c..3a5b5a0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ lib/testpilot/*.js +coverage \ No newline at end of file diff --git a/.gitignore b/.gitignore index c745683..ff6bfab 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ src/web-ext-artifacts/* # JetBrains IDE files .idea + +# IstanbulJS +.nyc_output +coverage \ No newline at end of file diff --git a/package.json b/package.json index bf05207..753f292 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "json": "^9.0.6", "mocha": "^6.2.2", "npm-run-all": "^4.0.0", + "nyc": "^14.1.1", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", "stylelint": "^7.9.0", @@ -42,7 +43,8 @@ "lint:html": "htmllint *.html", "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 && mocha ./test/setup.js test/**/*.test.js", - "test-watch": "mocha ./test/setup.js test/**/*.test.js --watch" + "test": "npm run lint && npm run coverage", + "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 e37440720f91eec22f099e2c9f8e95ed6ea5046d Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 18 Dec 2019 09:24:17 +0100 Subject: [PATCH 031/146] Add container feature test --- test/features/containers.test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/features/containers.test.js diff --git a/test/features/containers.test.js b/test/features/containers.test.js new file mode 100644 index 0000000..ac5bccd --- /dev/null +++ b/test/features/containers.test.js @@ -0,0 +1,28 @@ +describe("Containers Management", () => { + beforeEach(async () => { + await helper.browser.initializeWithTab(); + }); + + describe("creating a new container", () => { + beforeEach(async () => { + await helper.popup.clickElementById("container-add-link"); + await helper.popup.clickElementById("edit-container-ok-link"); + }); + + it("should create it in the browser as well", () => { + 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"); + }); + + it("should remove it in the browser as well", () => { + background.browser.contextualIdentities.remove.should.have.been.calledOnce; + }); + }); + }); +}); \ No newline at end of file From dc9e8f6399ffc1d434254a56ab64cb20a77e6cd4 Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 18 Dec 2019 09:24:52 +0100 Subject: [PATCH 032/146] Add test for unresolved issue See: https://github.com/mozilla/multi-account-containers/issues/1168#issuecomment-378394091 --- test/issues/1168.test.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/issues/1168.test.js diff --git a/test/issues/1168.test.js b/test/issues/1168.test.js new file mode 100644 index 0000000..50f463a --- /dev/null +++ b/test/issues/1168.test.js @@ -0,0 +1,34 @@ +describe("#1168", () => { + describe("when navigation happens too slow after opening new tab to a page which then redirects", () => { + let clock, tab; + + beforeEach(async () => { + await helper.browser.initializeWithTab({ + cookieStoreId: "firefox-container-1", + url: "https://bugzilla.mozilla.org" + }); + await helper.popup.clickElementById("container-page-assigned"); + + clock = sinon.useFakeTimers(); + tab = await helper.browser.openNewTab({}); + + clock.tick(2000); + + await background.browser.tabs._navigate(tab.id, "https://duckduckgo.com/?q=%21bugzilla+thing&t=ffab"); + await background.browser.tabs._redirect(tab.id, [ + "https://bugzilla.mozilla.org" + ]); + }); + + // Not solved yet + // See: https://github.com/mozilla/multi-account-containers/issues/1168#issuecomment-378394091 + it.skip("should remove the old tab", async () => { + 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 From 24c960bed0058a6c57025d8bcf562cf2bebc1f2b Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 11 Dec 2019 18:49:55 -0600 Subject: [PATCH 033/146] 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 034/146] 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 035/146] 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 036/146] 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 037/146] 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 038/146] 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 039/146] 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 040/146] 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 041/146] 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 042/146] 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 043/146] 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 044/146] 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 045/146] 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 046/146] 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 047/146] 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 048/146] 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 049/146] 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 050/146] 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 051/146] 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 052/146] 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 053/146] 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 054/146] 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 055/146] 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 056/146] 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 057/146] 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 058/146] 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 059/146] 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 060/146] 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 061/146] 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 062/146] 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 063/146] 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 064/146] 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 065/146] 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 066/146] 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 067/146] 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 068/146] 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 069/146] 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 070/146] 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 071/146] 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 072/146] 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 073/146] 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 074/146] 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 +
No Thanks
From 85c403bef5c8853a786ff6df443564b219547013 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 23 Jan 2020 10:08:12 -0600 Subject: [PATCH 075/146] 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 076/146] 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 077/146] 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 078/146] 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 079/146] 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 080/146] 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 081/146] 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 082/146] 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 083/146] 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 084/146] 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 085/146] 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 086/146] 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 087/146] 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 088/146] 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 089/146] 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 090/146] 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 091/146] 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 092/146] 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": { From 9e12014c076e8a0ec53c7fb5cfc6ad4f684ce7b4 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 13 Feb 2020 16:54:18 -0600 Subject: [PATCH 093/146] Fix for #1632: Pinned tabs cannot be loaded as 'discarded' --- src/js/background/backgroundLogic.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/background/backgroundLogic.js b/src/js/background/backgroundLogic.js index 96e7939..d68e51e 100644 --- a/src/js/background/backgroundLogic.js +++ b/src/js/background/backgroundLogic.js @@ -310,12 +310,13 @@ const backgroundLogic = { for (let object of containerState.hiddenTabs) { // eslint-disable-line prefer-const // do not show already opened url + const noload = !object.pinned; if (object.url !== options.alreadyShowingUrl) { promises.push(this.openNewTab({ userContextId: userContextId, url: object.url, nofocus: options.nofocus || false, - noload: true, + noload: noload, pinned: object.pinned, })); } From 8172f291dd596336aee8c82c603245b2bcf11866 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 13 Feb 2020 17:26:31 -0600 Subject: [PATCH 094/146] bumped version --- package.json | 2 +- src/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1258571..ded707c 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.2.0", + "version": "6.2.1", "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 5dfc37b..e88af90 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Firefox Multi-Account Containers", - "version": "6.2.0", + "version": "6.2.1", "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 5bbf902b4762adefc77a51811b9d8ab19051fadf Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 26 Feb 2020 17:02:01 -0600 Subject: [PATCH 095/146] fix for #1656, #1643, and #1637 removes enter key listener in favor of focus highlighting to notify user that there is keyboard navigation available for the onboarding panels. (enter key listener was added as keyboard navication for onboarding panels). bumped version --- package.json | 3 ++- src/css/popup.css | 5 +++++ src/js/popup.js | 8 -------- src/manifest.json | 2 +- src/popup.html | 24 ++++++++++++------------ 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index ded707c..1bf6531 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.2.1", + "version": "6.2.2", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/multi-account-containers/issues" @@ -37,6 +37,7 @@ }, "scripts": { "build": "npm test && cd src && web-ext build --overwrite-dest", + "webext": "web-ext run -s src/", "lint": "npm-run-all lint:*", "lint:addon": "addons-linter src --self-hosted", "lint:css": "stylelint src/css/*.css", diff --git a/src/css/popup.css b/src/css/popup.css index 2ffbce5..3ce65aa 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -390,6 +390,11 @@ table { background-color: #0675d3; } +.onboarding-button:focus, +.half-onboarding-button:focus { + box-shadow: 0 0 0 1px #0a84ff inset, 0 0 0 1px #0a84ff, 0 0 0 4px rgba(10, 132, 255, 0.3); +} + /* Pop buttons are the square shaped buttons used to manage things like container crud */ .pop-button { diff --git a/src/js/popup.js b/src/js/popup.js index b93981d..92f54b4 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -633,14 +633,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, { case 38: previous(); break; - case 13: { - const panel = Logic.getCurrentPanelElement(); - const button = panel.getElementsByTagName("A")[0]; - if(button) { - button.click(); - } - break; - } case 39: { const showTabs = element.parentNode.querySelector(".show-tabs"); diff --git a/src/manifest.json b/src/manifest.json index e88af90..4c1480f 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Firefox Multi-Account Containers", - "version": "6.2.1", + "version": "6.2.2", "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/src/popup.html b/src/popup.html index 1497212..813a02d 100644 --- a/src/popup.html +++ b/src/popup.html @@ -13,7 +13,7 @@

Use containers to organize tasks, manage accounts, and keep your focus where you want it.

- Get Started + Get Started
@@ -22,49 +22,49 @@

Use containers to organize tasks, manage accounts, and store sensitive data.

- Get Started + Get Started
How Containers Work

Put containers to work for you.

Features like color-coding and separate container tabs help you find things easily, focus your attention, and minimize distractions.

- Next + Next
How Containers Work

Put containers to work for you.

Color-coding helps you categorize your online life, find things easily, and minimize distractions.

- Next + Next
How Containers Work

A place for everything, and everything in its place.

Start with the containers we've created, or create your own.

- Next + Next
How Containers Work

Set boundaries for your browsing.

Cookies are stored within a container, so you can segment sensitive data and browsing history to stay organized and to limit the impact of online trackers.

- Next + Next
How to assign sites to containers

Always open sites in the containers you want.

Right-click inside a container tab to assign the site to always open in the container.

- Next + Next
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.

- Next + Next
@@ -72,8 +72,8 @@

Syncing Containers is now Available!

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

@@ -82,8 +82,8 @@

Firefox Account is required to sync.

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

- Not Now - Sign In + Not Now + Sign In
From 358551feda5f8f0d22e31f775fdcfc65fe2ff8af Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 28 Feb 2020 09:23:14 -0600 Subject: [PATCH 096/146] Made selector for keyboard shortcuts more specific to fix #1666 Bumped version for release --- package.json | 2 +- src/js/popup.js | 4 ++-- src/manifest.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 1bf6531..f226f31 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.2.2", + "version": "6.2.3", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/multi-account-containers/issues" diff --git a/src/js/popup.js b/src/js/popup.js index 92f54b4..1349ffa 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -611,7 +611,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, { }); document.addEventListener("keydown", (e) => { - const selectables = [...document.querySelectorAll("[tabindex='0'], [tabindex='-1']")]; + const selectables = [...document.querySelectorAll(".open-newtab[tabindex='0']")]; const element = document.activeElement; const index = selectables.indexOf(element) || 0; function next() { @@ -652,7 +652,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, { default: if ((e.keyCode >= 49 && e.keyCode <= 57) && Logic._currentPanel === "containersList") { - const element = selectables[e.keyCode - 48]; + const element = selectables[e.keyCode - 49]; if (element) { element.click(); } diff --git a/src/manifest.json b/src/manifest.json index 4c1480f..a18a44c 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Firefox Multi-Account Containers", - "version": "6.2.2", + "version": "6.2.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": { From 0cbc9879bb7f345bbba0378ad2c22a36fb2d1570 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Wed, 12 Feb 2020 12:24:35 -0600 Subject: [PATCH 097/146] Implemented UI/UX for container list Panel (first panel). --- src/css/popup.css | 140 ++++++++++++++++--- src/img/arrow-icon-left.svg | 1 + src/img/arrow-icon-right.svg | 21 +++ src/img/movetowindow-16.svg | 7 + src/img/open-in-new-16.svg | 7 + src/img/open-in-stop-16.svg | 7 + src/img/password-hide.svg | 9 ++ src/img/refresh-16.svg | 6 + src/img/sort-16_1.svg | 6 + src/img/tab-new-16.svg | 6 + src/js/popup.js | 253 +++++++++++++++-------------------- src/popup.html | 124 ++++++++++++----- 12 files changed, 383 insertions(+), 204 deletions(-) create mode 100644 src/img/arrow-icon-left.svg create mode 100644 src/img/arrow-icon-right.svg create mode 100644 src/img/movetowindow-16.svg create mode 100644 src/img/open-in-new-16.svg create mode 100644 src/img/open-in-stop-16.svg create mode 100644 src/img/password-hide.svg create mode 100644 src/img/refresh-16.svg create mode 100644 src/img/sort-16_1.svg create mode 100644 src/img/tab-new-16.svg diff --git a/src/css/popup.css b/src/css/popup.css index 3ce65aa..2dc9bc9 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -91,7 +91,7 @@ table { } .scrollable { - border-block-start: 1px solid #f1f1f1; +/* border-block-start: 1px solid #f1f1f1;*/ inline-size: 100%; max-block-size: 400px; overflow: auto; @@ -493,24 +493,6 @@ manage things like container crud */ margin-inline-start: var(--inline-item-space-size); } -#container-panel #sort-containers-link { - align-items: center; - block-size: var(--block-url-label-size); - border: 1px solid #d8d8d8; - border-radius: var(--small-radius); - color: var(--title-text-color); - display: flex; - font-size: var(--small-text-size); - inline-size: var(--inline-button-size); - justify-content: center; - text-decoration: none; -} - -#container-panel #sort-containers-link:hover, -#container-panel #sort-containers-link:focus { - background: #f2f2f2; -} - span ~ .panel-header-text { padding-block-end: 0; padding-block-start: 0; @@ -649,7 +631,7 @@ span ~ .panel-header-text { background-image: var(--identity-icon); background-position: center center; background-repeat: no-repeat; - background-size: 20px 20px; + background-size: 16px 16px; block-size: 100%; fill: var(--identity-icon-color); filter: url('/img/filters.svg#fill'); @@ -1008,3 +990,121 @@ span ~ .panel-header-text { .amo-rate-cta { background: #0f1126; } + +body { + font-family: 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + color: #000000; + font-size: 13px; + letter-spacing: -0.1px; + width: 320px; + /* remove in prodcution*/ +} + +h3.title { + width: 100%; + color: #000000; + font-size: 13px; + letter-spacing: -0.1px; + font-weight: bold; + line-height: 40px; + text-align: center; + height: 40px; +} + +.menu { + width: 100%; + border-style: none; +} + +.menu-item { + height: 24px; + line-height: 24px; + width: 100%; + cursor: pointer; +} + +.menu-item:hover { + background: #1296F8; + color: #FFFFFF; +} + +.hover-highlight { + +} + +.menu-text { + line-height: 24px; +} + +.menu-icon { + float: left; + text-align: center; + width: 40px; + display: block; + height: 24px; + padding: 0 8px 0 16px; +} + +.menu-right-float { + float: right; + text-align: right; + width: 60px; + display: inline-block; + height: 24px; +} + +.container-count { + opacity: 0.6; + padding: 0 6px 0 0; + text-align: right; +} + +.menu-arrow { + float: right; + text-align: center; + width: 18px; + display: inline-block; + height: 24px; + padding: 6px 12px 6px 0; +} + +.menu-arrow img { + padding: 2 2 2 2; + height: 12px; + width: 12px; +} + +hr { + display: block; + border: 0; + border-top: 1px solid #e3e3e3; + padding: 0 0 6px 0; + margin: 6px 0 0 0; +} + +.sub-header { + height: 24px; + color: #737373; + line-height: 24px; + padding: 0 16px 0 16px; +} + +.identities-list { + margin: 0 0 41px 0; +} + +.bottom-btn { + height: 41px; + line-height: 41px; + background-color: #e3e3e3; + padding: 0 16px 0 16px; + border: solid 1px #d9d9d9; + cursor: pointer; + position: fixed; + bottom: 0px; + width: 100%; +} + +.menu-panel { + justify-content: flex-start; +} \ No newline at end of file diff --git a/src/img/arrow-icon-left.svg b/src/img/arrow-icon-left.svg new file mode 100644 index 0000000..ab0a30f --- /dev/null +++ b/src/img/arrow-icon-left.svg @@ -0,0 +1 @@ + diff --git a/src/img/arrow-icon-right.svg b/src/img/arrow-icon-right.svg new file mode 100644 index 0000000..f740140 --- /dev/null +++ b/src/img/arrow-icon-right.svg @@ -0,0 +1,21 @@ + + + + Arrow + Created with Sketch. + + + + + + + + + + + + + + + + diff --git a/src/img/movetowindow-16.svg b/src/img/movetowindow-16.svg new file mode 100644 index 0000000..80181a3 --- /dev/null +++ b/src/img/movetowindow-16.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/src/img/open-in-new-16.svg b/src/img/open-in-new-16.svg new file mode 100644 index 0000000..c6685c4 --- /dev/null +++ b/src/img/open-in-new-16.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/src/img/open-in-stop-16.svg b/src/img/open-in-stop-16.svg new file mode 100644 index 0000000..8ba3d97 --- /dev/null +++ b/src/img/open-in-stop-16.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/src/img/password-hide.svg b/src/img/password-hide.svg new file mode 100644 index 0000000..af7818d --- /dev/null +++ b/src/img/password-hide.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/img/refresh-16.svg b/src/img/refresh-16.svg new file mode 100644 index 0000000..2e40ef6 --- /dev/null +++ b/src/img/refresh-16.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/img/sort-16_1.svg b/src/img/sort-16_1.svg new file mode 100644 index 0000000..83ae0ee --- /dev/null +++ b/src/img/sort-16_1.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/img/tab-new-16.svg b/src/img/tab-new-16.svg new file mode 100644 index 0000000..d8c7ba6 --- /dev/null +++ b/src/img/tab-new-16.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/js/popup.js b/src/js/popup.js index 1349ffa..1d4fce6 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -20,7 +20,11 @@ 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_PICKER = "containerPicker"; +const OPEN_NEW_CONTAINER_PICKER = "new-tab"; +const MANAGE_CONTAINERS_PICKER = "manage"; +const REOPEN_IN_CONTAINER = "reopen-in"; +const ALWAYS_OPEN_IN_PICKER = "always-open-in"; const P_CONTAINER_INFO = "containerInfo"; const P_CONTAINER_EDIT = "containerEdit"; const P_CONTAINER_DELETE = "containerDelete"; @@ -275,7 +279,7 @@ const Logic = { } }, - async showPanel(panel, currentIdentity = null) { + async showPanel(panel, currentIdentity = null, pickerType = null) { // Invalid panel... ?!? if (!(panel in this._panels)) { throw new Error("Something really bad happened. Unknown panel: " + panel); @@ -283,6 +287,7 @@ const Logic = { this._previousPanel = this._currentPanel; this._currentPanel = panel; + this.pickerType = pickerType; this._currentIdentity = currentIdentity; @@ -589,16 +594,20 @@ Logic.registerPanel(P_CONTAINERS_LIST, { // This method is called when the object is registered. async initialize() { - Logic.addEnterHandler(document.querySelector("#container-add-link"), () => { - Logic.showPanel(P_CONTAINER_EDIT, { name: Logic.generateIdentityName() }); - }); - - Logic.addEnterHandler(document.querySelector("#edit-containers-link"), (e) => { + Logic.addEnterHandler(document.querySelector("#manage-containers-link"), (e) => { if (!e.target.classList.contains("disable-edit-containers")) { - Logic.showPanel(P_CONTAINERS_EDIT); + Logic.showPanel(P_CONTAINER_PICKER, null, MANAGE_CONTAINERS_PICKER); } }); - + Logic.addEnterHandler(document.querySelector("#open-new-tab-in"), () => { + Logic.showPanel(P_CONTAINER_PICKER, null, OPEN_NEW_CONTAINER_PICKER); + }); + Logic.addEnterHandler(document.querySelector("#reopen-site-in"), () => { + Logic.showPanel(P_CONTAINER_PICKER, null, REOPEN_IN_CONTAINER); + }); + Logic.addEnterHandler(document.querySelector("#always-open-in"), () => { + Logic.showPanel(P_CONTAINER_PICKER, null, ALWAYS_OPEN_IN_PICKER); + }); Logic.addEnterHandler(document.querySelector("#sort-containers-link"), async () => { try { await browser.runtime.sendMessage({ @@ -660,123 +669,47 @@ Logic.registerPanel(P_CONTAINERS_LIST, { break; } }); - - // When the popup is open sometimes the tab will still be updating it's state - this.tabUpdateHandler = (tabId, changeInfo) => { - const propertiesToUpdate = ["title", "favIconUrl"]; - const hasChanged = Object.keys(changeInfo).find((changeInfoKey) => { - if (propertiesToUpdate.includes(changeInfoKey)) { - return true; - } - }); - if (hasChanged) { - this.prepareCurrentTabHeader(); - } - }; - browser.tabs.onUpdated.addListener(this.tabUpdateHandler); }, unregister() { - browser.tabs.onUpdated.removeListener(this.tabUpdateHandler); - }, - setupAssignmentCheckbox(siteSettings, currentUserContextId) { - const assignmentCheckboxElement = document.getElementById("container-page-assigned"); - let checked = false; - if (siteSettings && Number(siteSettings.userContextId) === currentUserContextId) { - checked = true; - } - assignmentCheckboxElement.checked = checked; - let disabled = false; - if (siteSettings === false) { - disabled = true; - } - assignmentCheckboxElement.disabled = disabled; - }, - - async prepareCurrentTabHeader() { - const currentTab = await Logic.currentTab(); - const currentTabElement = document.getElementById("current-tab"); - const assignmentCheckboxElement = document.getElementById("container-page-assigned"); - const currentTabUserContextId = Logic.userContextId(currentTab.cookieStoreId); - assignmentCheckboxElement.addEventListener("change", () => { - Logic.setOrRemoveAssignment(currentTab.id, currentTab.url, currentTabUserContextId, !assignmentCheckboxElement.checked); - }); - currentTabElement.hidden = !currentTab; - this.setupAssignmentCheckbox(false, currentTabUserContextId); - if (currentTab) { - const identity = await Logic.identity(currentTab.cookieStoreId); - const siteSettings = await Logic.getAssignment(currentTab); - this.setupAssignmentCheckbox(siteSettings, currentTabUserContextId); - const currentPage = document.getElementById("current-page"); - currentPage.innerHTML = escaped`${currentTab.title}`; - const favIconElement = Utils.createFavIconElement(currentTab.favIconUrl || ""); - currentPage.prepend(favIconElement); - - const currentContainer = document.getElementById("current-container"); - currentContainer.innerText = identity.name; - - currentContainer.setAttribute("data-identity-color", identity.color); - } }, // This method is called when the panel is shown. async prepare() { const fragment = document.createDocumentFragment(); - this.prepareCurrentTabHeader(); - Logic.identities().forEach(identity => { - const hasTabs = (identity.hasHiddenTabs || identity.hasOpenTabs); const tr = document.createElement("tr"); - const context = document.createElement("td"); - const manage = document.createElement("td"); + tr.classList.add("menu-item"); + const td = document.createElement("td"); + const openTabs = identity.numberOfOpenTabs || "" ; - tr.classList.add("container-panel-row"); - - context.classList.add("userContext-wrapper", "open-newtab", "clickable", "firstTabindex"); - manage.classList.add("show-tabs", "pop-button"); - manage.setAttribute("title", `View ${identity.name} container`); - context.setAttribute("tabindex", "0"); - context.setAttribute("title", `Create ${identity.name} tab`); - context.innerHTML = escaped` -
+ td.innerHTML = escaped` + -
`; - context.querySelector(".container-name").textContent = identity.name; - manage.innerHTML = ""; + ${identity.name} + + ${openTabs} + + Container Info + + `; fragment.appendChild(tr); - tr.appendChild(context); + tr.appendChild(td); - if (hasTabs) { - tr.appendChild(manage); - } - - Logic.addEnterHandler(tr, async (e) => { - if (e.target.matches(".open-newtab") - || e.target.parentNode.matches(".open-newtab") - || e.type === "keydown") { - try { - browser.tabs.create({ - cookieStoreId: identity.cookieStoreId - }); - window.close(); - } catch (e) { - window.close(); - } - } else if (hasTabs) { - Logic.showPanel(P_CONTAINER_INFO, identity); - } + Logic.addEnterHandler(tr, () => { + Logic.showPanel(P_CONTAINER_INFO, identity); }); }); - const list = document.querySelector(".identities-list tbody"); + const list = document.querySelector("#identities-list"); list.innerHTML = ""; list.appendChild(fragment); @@ -796,14 +729,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, { document.addEventListener("mousedown", () => { document.removeEventListener("focus", focusHandler); }); - /* If no container is present disable the Edit Containers button */ - const editContainer = document.querySelector("#edit-containers-link"); - if (Logic.identities().length === 0) { - editContainer.classList.add("disable-edit-containers"); - } else { - editContainer.classList.remove("disable-edit-containers"); - } - return Promise.resolve(); }, }); @@ -955,68 +880,100 @@ Logic.registerPanel(P_CONTAINER_INFO, { }, }); -// P_CONTAINERS_EDIT: Makes the list editable. +// P_CONTAINER_PICKER: Makes the list editable. // ---------------------------------------------------------------------------- -Logic.registerPanel(P_CONTAINERS_EDIT, { - panelSelector: "#edit-containers-panel", +Logic.registerPanel(P_CONTAINER_PICKER, { + panelSelector: "#container-picker-panel", // This method is called when the object is registered. initialize() { - Logic.addEnterHandler(document.querySelector("#exit-edit-mode-link"), () => { - Logic.showPanel(P_CONTAINERS_LIST); - }); + // Logic.addEnterHandler(document.querySelector("#exit-edit-mode-link"), () => { + // Logic.showPanel(P_CONTAINERS_LIST); + // }); }, // This method is called when the panel is shown. prepare() { const fragment = document.createDocumentFragment(); + let pickedFunction; + switch (Logic.pickerType) { + case OPEN_NEW_CONTAINER_PICKER: + pickedFunction = function (identity) { + try { + browser.tabs.create({ + cookieStoreId: identity.cookieStoreId + }); + window.close(); + } catch (e) { + window.close(); + } + }; + break; + case MANAGE_CONTAINERS_PICKER: + pickedFunction = function (identity) { + Logic.showPanel(P_CONTAINER_EDIT, identity); + }; + break; + case REOPEN_IN_CONTAINER: + pickedFunction = function (identity) { + try { + browser.tabs.create({ + cookieStoreId: identity.cookieStoreId + }); + window.close(); + } catch (e) { + window.close(); + } + }; + break; + case ALWAYS_OPEN_IN_PICKER: + default: + pickedFunction = async function (identity) { + const currentTab = await Logic.currentTab(); + console.log(identity.cookieStoreId) + console.log(identity) + Logic.setOrRemoveAssignment( + currentTab.id, + currentTab.url, + identity.cookieStoreId, + false + ); + window.close(); + }; + break; + } + Logic.identities().forEach(identity => { const tr = document.createElement("tr"); - fragment.appendChild(tr); - tr.classList.add("container-panel-row"); - tr.innerHTML = escaped` - -
-
-
+ tr.classList.add("menu-item"); + const td = document.createElement("td"); + + td.innerHTML = escaped` + + ${identity.name}`; + fragment.appendChild(tr); - Logic.addEnterHandler(tr, e => { - if (e.target.matches(".edit-container-icon") || e.target.parentNode.matches(".edit-container-icon")) { - Logic.showPanel(P_CONTAINER_EDIT, identity); - } else if (e.target.matches(".delete-container-icon") || e.target.parentNode.matches(".delete-container-icon")) { - Logic.showPanel(P_CONTAINER_DELETE, identity); - } + tr.appendChild(td); + + Logic.addEnterHandler(tr, () => { + pickedFunction(identity); }); }); - const list = document.querySelector("#edit-identities-list"); + const list = document.querySelector("#picker-identities-list"); list.innerHTML = ""; list.appendChild(fragment); return Promise.resolve(null); - }, + } }); // P_CONTAINER_EDIT: Editor for a container. diff --git a/src/popup.html b/src/popup.html index 813a02d..dca1948 100644 --- a/src/popup.html +++ b/src/popup.html @@ -115,34 +115,79 @@ Done
-
-
-

Current Tab

-
- + @@ -170,19 +215,26 @@
-
-
-

Edit Containers

-
-
- - +
+

+ Multi-Account Containers +

+
+
+
+ + +
-
From 97d4c46a4e1c6f5ce36667fd6dfc61b580511542 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 13 Feb 2020 16:21:29 -0600 Subject: [PATCH 098/146] Added Facebook Container Fence icon. Fixes #1425 --- src/css/popup.css | 4 ++++ src/img/usercontext.svg | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/src/css/popup.css b/src/css/popup.css index 2dc9bc9..36f9a52 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -206,6 +206,10 @@ table { --identity-icon: url("/img/usercontext.svg#chill"); } +[data-identity-icon="fence"] { + --identity-icon: url("/img/usercontext.svg#fence"); +} + #current-tab [data-identity-icon="default-tab"] { background: center center no-repeat url("/img/blank-tab.svg"); fill: currentColor; diff --git a/src/img/usercontext.svg b/src/img/usercontext.svg index f58067a..fb48e4a 100644 --- a/src/img/usercontext.svg +++ b/src/img/usercontext.svg @@ -13,6 +13,7 @@ display: none; } + + + + + + + + + From fbba6beee29e52b8296b0ace9af83b1cf2e8ae23 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Thu, 13 Feb 2020 23:56:28 -0600 Subject: [PATCH 099/146] testing keyboard shortcuts --- src/js/background/backgroundLogic.js | 12 +++++++++++- src/manifest.json | 12 ++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/js/background/backgroundLogic.js b/src/js/background/backgroundLogic.js index d68e51e..7aba5f6 100644 --- a/src/js/background/backgroundLogic.js +++ b/src/js/background/backgroundLogic.js @@ -331,4 +331,14 @@ const backgroundLogic = { cookieStoreId(userContextId) { return `firefox-container-${userContextId}`; } -}; \ No newline at end of file +}; + +browser.commands.onCommand.addListener(function (command) { + if (command === "open_container_2") { + browser.tabs.create({cookieStoreId: "firefox-container-2"}); + } + if (command === "open_container_1") { + console.log("Toggling the feature!"); + browser.tabs.create({cookieStoreId: "firefox-container-1"}); + } +}); \ No newline at end of file diff --git a/src/manifest.json b/src/manifest.json index a18a44c..57402c5 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -39,6 +39,18 @@ "mac": "MacCtrl+Period" }, "description": "Open containers panel" + }, + "open_container_1": { + "suggested_key": { + "default": "Ctrl+Shift+1" + }, + "description": "Container Shortcut 1" + }, + "open_container_2": { + "suggested_key": { + "default": "Ctrl+Shift+2" + }, + "description": "Container Shortcut 2" } }, "browser_action": { From 1870ce08bc91173c37cb0dbdc54ca70774cf9594 Mon Sep 17 00:00:00 2001 From: Kendall Werts Date: Fri, 14 Feb 2020 00:08:37 -0600 Subject: [PATCH 100/146] Page action assigns site to a container and simultaneously reopens site in container. --- .eslintrc.js | 2 +- src/js/.eslintrc.js | 3 +- src/js/background/assignManager.js | 1 + src/js/background/messageHandler.js | 10 ++ src/js/pageAction.js | 51 +++++++++ src/js/popup.js | 157 ++++++++-------------------- src/js/utils.js | 86 ++++++++++++++- src/manifest.json | 8 ++ src/pageActionPopup.html | 34 ++++++ 9 files changed, 235 insertions(+), 117 deletions(-) create mode 100644 src/js/pageAction.js create mode 100644 src/pageActionPopup.html diff --git a/.eslintrc.js b/.eslintrc.js index 1b0e906..f52aeb7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -46,7 +46,7 @@ module.exports = { "error", { "escape": { - "taggedTemplates": ["escaped"] + "taggedTemplates": ["escaped", "Utils.escaped"] } } ], diff --git a/src/js/.eslintrc.js b/src/js/.eslintrc.js index 11cd71a..4941e75 100644 --- a/src/js/.eslintrc.js +++ b/src/js/.eslintrc.js @@ -8,6 +8,7 @@ module.exports = { "backgroundLogic": true, "identityState": true, "messageHandler": true, - "sync": true + "sync": true, + "Utils": true } }; diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 9dd6e88..861b928 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -474,6 +474,7 @@ window.assignManager = { }, async _setOrRemoveAssignment(tabId, pageUrl, userContextId, remove) { + console.log(userContextId) let actionName; // https://github.com/mozilla/testpilot-containers/issues/626 diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index f4236f1..3e93802 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -73,6 +73,16 @@ const messageHandler = { case "exemptContainerAssignment": response = assignManager._exemptTab(m); break; + case "reloadInContainer": + response = assignManager.reloadPageInContainer( + m.url, + m.currentUserContextId, + m.newUserContextId, + m.tabIndex, + m.active, + true + ); + break; } return response; }); diff --git a/src/js/pageAction.js b/src/js/pageAction.js new file mode 100644 index 0000000..9242f24 --- /dev/null +++ b/src/js/pageAction.js @@ -0,0 +1,51 @@ +async function init() { + const fragment = document.createDocumentFragment(); + + const identities = await browser.contextualIdentities.query({}); + + identities.forEach(identity => { + const tr = document.createElement("tr"); + tr.classList.add("menu-item"); + const td = document.createElement("td"); + + td.innerHTML = Utils.escaped` + + ${identity.name}`; + + fragment.appendChild(tr); + + tr.appendChild(td); + + Utils.addEnterHandler(tr, async () => { + const currentTab = await Utils.currentTab(); + const assignedUserContextId = Utils.userContextId(identity.cookieStoreId); + Utils.setOrRemoveAssignment( + currentTab.id, + currentTab.url, + assignedUserContextId, + false + ); + console.log(currentTab); + Utils.reloadInContainer( + currentTab.url, + false, + assignedUserContextId, + currentTab.index + 1, + currentTab.active + ); + window.close(); + }); + }); + + const list = document.querySelector("#picker-identities-list"); + + list.innerHTML = ""; + list.appendChild(fragment); +} + +init(); diff --git a/src/js/popup.js b/src/js/popup.js index 1d4fce6..e6f22e8 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -30,41 +30,6 @@ const P_CONTAINER_EDIT = "containerEdit"; const P_CONTAINER_DELETE = "containerDelete"; const P_CONTAINERS_ACHIEVEMENT = "containersAchievement"; -/** - * Escapes any occurances of &, ", <, > or / with XML entities. - * - * @param {string} str - * The string to escape. - * @return {string} The escaped string. - */ -function escapeXML(str) { - const replacements = { "&": "&", "\"": """, "'": "'", "<": "<", ">": ">", "/": "/" }; - return String(str).replace(/[&"'<>/]/g, m => replacements[m]); -} - -/** - * A tagged template function which escapes any XML metacharacters in - * interpolated values. - * - * @param {Array} strings - * An array of literal strings extracted from the templates. - * @param {Array} values - * An array of interpolated values extracted from the template. - * @returns {string} - * The result of the escaped values interpolated with the literal - * strings. - */ -function escaped(strings, ...values) { - const result = []; - - for (const [i, string] of strings.entries()) { - result.push(string); - if (i < values.length) - result.push(escapeXML(values[i])); - } - - return result.join(""); -} async function getExtensionInfo() { const manifestPath = browser.extension.getURL("manifest.json"); @@ -201,31 +166,6 @@ const Logic = { } }, - addEnterHandler(element, handler) { - element.addEventListener("click", (e) => { - handler(e); - }); - element.addEventListener("keydown", (e) => { - if (e.keyCode === 13) { - e.preventDefault(); - handler(e); - } - }); - }, - - userContextId(cookieStoreId = "") { - const userContextId = cookieStoreId.replace("firefox-container-", ""); - return (userContextId !== cookieStoreId) ? Number(userContextId) : false; - }, - - async currentTab() { - const activeTabs = await browser.tabs.query({ active: true, windowId: browser.windows.WINDOW_ID_CURRENT }); - if (activeTabs.length > 0) { - return activeTabs[0]; - } - return false; - }, - async numTabs() { const activeTabs = await browser.tabs.query({ windowId: browser.windows.WINDOW_ID_CURRENT }); return activeTabs.length; @@ -338,7 +278,7 @@ const Logic = { currentUserContextId() { const identity = Logic.currentIdentity(); - return Logic.userContextId(identity.cookieStoreId); + return Utils.userContextId(identity.cookieStoreId); }, currentCookieStoreId() { @@ -374,16 +314,6 @@ const Logic = { }); }, - setOrRemoveAssignment(tabId, url, userContextId, value) { - return browser.runtime.sendMessage({ - method: "setOrRemoveAssignment", - tabId, - url, - userContextId, - value - }); - }, - generateIdentityName() { const defaultName = "Container #"; const ids = []; @@ -423,7 +353,7 @@ Logic.registerPanel(P_ONBOARDING_1, { initialize() { // Let's move to the next panel. [...document.querySelectorAll(".onboarding-start-button")].forEach(startElement => { - Logic.addEnterHandler(startElement, async () => { + Utils.addEnterHandler(startElement, async () => { await Logic.setOnboardingStage(1); Logic.showPanel(P_ONBOARDING_2); }); @@ -447,7 +377,7 @@ Logic.registerPanel(P_ONBOARDING_2, { initialize() { // Let's move to the containers list panel. [...document.querySelectorAll(".onboarding-next-button")].forEach(nextElement => { - Logic.addEnterHandler(nextElement, async () => { + Utils.addEnterHandler(nextElement, async () => { await Logic.setOnboardingStage(2); Logic.showPanel(P_ONBOARDING_3); }); @@ -471,7 +401,7 @@ Logic.registerPanel(P_ONBOARDING_3, { initialize() { // Let's move to the containers list panel. [...document.querySelectorAll(".onboarding-almost-done-button")].forEach(almostElement => { - Logic.addEnterHandler(almostElement, async () => { + Utils.addEnterHandler(almostElement, async () => { await Logic.setOnboardingStage(3); Logic.showPanel(P_ONBOARDING_4); }); @@ -493,7 +423,7 @@ Logic.registerPanel(P_ONBOARDING_4, { // This method is called when the object is registered. initialize() { // Let's move to the containers list panel. - Logic.addEnterHandler(document.querySelector("#onboarding-done-button"), async () => { + Utils.addEnterHandler(document.querySelector("#onboarding-done-button"), async () => { await Logic.setOnboardingStage(4); Logic.showPanel(P_ONBOARDING_5); }); @@ -514,7 +444,7 @@ Logic.registerPanel(P_ONBOARDING_5, { // This method is called when the object is registered. initialize() { // Let's move to the containers list panel. - Logic.addEnterHandler(document.querySelector("#onboarding-longpress-button"), async () => { + Utils.addEnterHandler(document.querySelector("#onboarding-longpress-button"), async () => { await Logic.setOnboardingStage(5); Logic.showPanel(P_ONBOARDING_6); }); @@ -535,7 +465,7 @@ Logic.registerPanel(P_ONBOARDING_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 () => { + Utils.addEnterHandler(document.querySelector("#start-sync-button"), async () => { await Logic.setOnboardingStage(6); await browser.storage.local.set({syncEnabled: true}); await browser.runtime.sendMessage({ @@ -543,7 +473,7 @@ Logic.registerPanel(P_ONBOARDING_6, { }); Logic.showPanel(P_ONBOARDING_7); }); - Logic.addEnterHandler(document.querySelector("#no-sync"), async () => { + Utils.addEnterHandler(document.querySelector("#no-sync"), async () => { await Logic.setOnboardingStage(7); await browser.storage.local.set({syncEnabled: false}); await browser.runtime.sendMessage({ @@ -568,14 +498,14 @@ Logic.registerPanel(P_ONBOARDING_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 () => { + Utils.addEnterHandler(document.querySelector("#sign-in"), async () => { browser.tabs.create({ 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); }); - Logic.addEnterHandler(document.querySelector("#no-sign-in"), async () => { + Utils.addEnterHandler(document.querySelector("#no-sign-in"), async () => { await Logic.setOnboardingStage(7); Logic.showPanel(P_CONTAINERS_LIST); }); @@ -594,21 +524,21 @@ Logic.registerPanel(P_CONTAINERS_LIST, { // This method is called when the object is registered. async initialize() { - Logic.addEnterHandler(document.querySelector("#manage-containers-link"), (e) => { + Utils.addEnterHandler(document.querySelector("#manage-containers-link"), (e) => { if (!e.target.classList.contains("disable-edit-containers")) { Logic.showPanel(P_CONTAINER_PICKER, null, MANAGE_CONTAINERS_PICKER); } }); - Logic.addEnterHandler(document.querySelector("#open-new-tab-in"), () => { + Utils.addEnterHandler(document.querySelector("#open-new-tab-in"), () => { Logic.showPanel(P_CONTAINER_PICKER, null, OPEN_NEW_CONTAINER_PICKER); }); - Logic.addEnterHandler(document.querySelector("#reopen-site-in"), () => { + Utils.addEnterHandler(document.querySelector("#reopen-site-in"), () => { Logic.showPanel(P_CONTAINER_PICKER, null, REOPEN_IN_CONTAINER); }); - Logic.addEnterHandler(document.querySelector("#always-open-in"), () => { + Utils.addEnterHandler(document.querySelector("#always-open-in"), () => { Logic.showPanel(P_CONTAINER_PICKER, null, ALWAYS_OPEN_IN_PICKER); }); - Logic.addEnterHandler(document.querySelector("#sort-containers-link"), async () => { + Utils.addEnterHandler(document.querySelector("#sort-containers-link"), async () => { try { await browser.runtime.sendMessage({ method: "sortTabs" @@ -685,7 +615,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, { const td = document.createElement("td"); const openTabs = identity.numberOfOpenTabs || "" ; - td.innerHTML = escaped` + td.innerHTML = Utils.escaped`