added UUIDs of containers to site assignments

This commit is contained in:
Kendall Werts 2020-01-13 17:27:29 -06:00
parent 18d6324c5a
commit 76e884aee2
5 changed files with 168 additions and 147 deletions

View file

@ -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
);
}
}
}

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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"
}
},

View file

@ -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;
});
});