918 lines
No EOL
41 KiB
JavaScript
918 lines
No EOL
41 KiB
JavaScript
/* jshint esversion: 8*/
|
|
const assignManager = {
|
|
MENU_ASSIGN_ID: "open-in-this-container",
|
|
MENU_REMOVE_ID: "remove-open-in-this-container",
|
|
MENU_SEPARATOR_ID: "separator",
|
|
MENU_HIDE_ID: "hide-container",
|
|
MENU_MOVE_ID: "move-to-new-window-container",
|
|
OPEN_IN_CONTAINER: "open-bookmark-in-container-tab",
|
|
storageArea: {
|
|
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@@_";
|
|
if (url.port === "80" || url.port === "443") {
|
|
return `${storagePrefix}${url.hostname}`;
|
|
} else {
|
|
return `${storagePrefix}${url.hostname}${url.port}`;
|
|
}
|
|
},
|
|
|
|
setExempted(pageUrl, tabId) {
|
|
const siteStoreKey = this.getSiteStoreKey(pageUrl);
|
|
if (!(siteStoreKey in this.exemptedTabs)) {
|
|
this.exemptedTabs[siteStoreKey] = [];
|
|
}
|
|
this.exemptedTabs[siteStoreKey].push(tabId);
|
|
},
|
|
|
|
removeExempted(pageUrl) {
|
|
const siteStoreKey = this.getSiteStoreKey(pageUrl);
|
|
this.exemptedTabs[siteStoreKey] = [];
|
|
},
|
|
|
|
isExempted(pageUrl, tabId) {
|
|
const siteStoreKey = this.getSiteStoreKey(pageUrl);
|
|
if (!(siteStoreKey in this.exemptedTabs)) {
|
|
return false;
|
|
}
|
|
return this.exemptedTabs[siteStoreKey].includes(tabId);
|
|
},
|
|
|
|
get(pageUrl) {
|
|
const siteStoreKey = this.getSiteStoreKey(pageUrl);
|
|
return new Promise((resolve, reject) => {
|
|
this.area.get([siteStoreKey]).then((storageResponse) => {
|
|
if (storageResponse && siteStoreKey in storageResponse) {
|
|
resolve(storageResponse[siteStoreKey]);
|
|
}
|
|
resolve(null);
|
|
}).catch((e) => {
|
|
reject(e);
|
|
});
|
|
});
|
|
},
|
|
|
|
set(pageUrl, data, exemptedTabIds) {
|
|
const siteStoreKey = this.getSiteStoreKey(pageUrl);
|
|
if (exemptedTabIds) {
|
|
exemptedTabIds.forEach((tabId) => {
|
|
this.setExempted(pageUrl, tabId);
|
|
});
|
|
}
|
|
return this.area.set({
|
|
[siteStoreKey]: data
|
|
});
|
|
},
|
|
|
|
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]);
|
|
},
|
|
|
|
async deleteContainer(userContextId) {
|
|
const sitesByContainer = await this.getAssignedSites(userContextId);
|
|
this.area.remove(Object.keys(sitesByContainer));
|
|
},
|
|
|
|
async getAssignedSites(userContextId = null) {
|
|
const sites = {};
|
|
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)) {
|
|
continue;
|
|
}
|
|
const site = siteConfigs[urlKey];
|
|
// In hindsight we should have stored this
|
|
// TODO file a follow up to clean the storage onLoad
|
|
site.hostname = urlKey.replace(/^siteContainerMap@@_/, "");
|
|
sites[urlKey] = site;
|
|
}
|
|
};
|
|
return sites;
|
|
},
|
|
},
|
|
|
|
_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
|
|
this.storageArea.get(pageUrl).then((siteSettings) => {
|
|
if (siteSettings) {
|
|
siteSettings.neverAsk = true;
|
|
this.storageArea.set(pageUrl, siteSettings);
|
|
}
|
|
}).catch((e) => {
|
|
throw e;
|
|
});
|
|
}
|
|
},
|
|
|
|
// 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);
|
|
return true;
|
|
},
|
|
|
|
// 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 {};
|
|
}
|
|
this.removeContextMenu();
|
|
const [tab, siteSettings] = await Promise.all([
|
|
browser.tabs.get(options.tabId),
|
|
this.storageArea.get(options.url)
|
|
]);
|
|
let container;
|
|
try {
|
|
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
|
|
if (siteSettings && !container) {
|
|
this.deleteContainer(siteSettings.userContextId);
|
|
return {};
|
|
}
|
|
const userContextId = this.getUserContextIdFromCookieStore(tab);
|
|
if (!siteSettings
|
|
|| userContextId === siteSettings.userContextId
|
|
|| this.storageArea.isExempted(options.url, tab.id)) {
|
|
return {};
|
|
}
|
|
const removeTab = backgroundLogic.NEW_TAB_PAGES.has(tab.url)
|
|
|| (messageHandler.lastCreatedTab
|
|
&& messageHandler.lastCreatedTab.id === tab.id);
|
|
const openTabId = removeTab ? tab.openerTabId : tab.id;
|
|
|
|
if (!this.canceledRequests[tab.id]) {
|
|
// we decided to cancel the request at this point, register canceled request
|
|
this.canceledRequests[tab.id] = {
|
|
requestIds: {
|
|
[options.requestId]: true
|
|
},
|
|
urls: {
|
|
[options.url]: true
|
|
}
|
|
};
|
|
|
|
// 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]) {
|
|
delete this.canceledRequests[tab.id];
|
|
}
|
|
}, 2000);
|
|
} else {
|
|
let cancelEarly = false;
|
|
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
|
|
cancelEarly = true;
|
|
}
|
|
// 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) {
|
|
return {
|
|
cancel: true
|
|
};
|
|
}
|
|
}
|
|
|
|
this.reloadPageInContainer(
|
|
options.url,
|
|
userContextId,
|
|
siteSettings.userContextId,
|
|
tab.index + 1,
|
|
tab.active,
|
|
siteSettings.neverAsk,
|
|
openTabId
|
|
);
|
|
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.
|
|
*/
|
|
if (removeTab) {
|
|
browser.tabs.remove(tab.id);
|
|
}
|
|
return {
|
|
cancel: true,
|
|
};
|
|
},
|
|
|
|
init() {
|
|
browser.contextMenus.onClicked.addListener((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
|
|
this.canceledRequests = {};
|
|
browser.webRequest.onBeforeRequest.addListener((options) => {
|
|
return this.onBeforeRequest(options);
|
|
},{urls: ["<all_urls>"], types: ["main_frame"]}, ["blocking"]);
|
|
|
|
// Clean up canceled requests
|
|
browser.webRequest.onCompleted.addListener((options) => {
|
|
if (this.canceledRequests[options.tabId]) {
|
|
delete this.canceledRequests[options.tabId];
|
|
}
|
|
},{urls: ["<all_urls>"], types: ["main_frame"]});
|
|
browser.webRequest.onErrorOccurred.addListener((options) => {
|
|
if (this.canceledRequests[options.tabId]) {
|
|
delete this.canceledRequests[options.tabId];
|
|
}
|
|
},{urls: ["<all_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() {
|
|
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);
|
|
} else {
|
|
this.removeBookmarksMenu();
|
|
browser.contextualIdentities.onCreated.removeListener(this.contextualIdentityCreated);
|
|
browser.contextualIdentities.onUpdated.removeListener(this.contextualIdentityUpdated);
|
|
browser.contextualIdentities.onRemoved.removeListener(this.contextualIdentityRemoved);
|
|
}
|
|
},
|
|
|
|
contextualIdentityCreated(changeInfo) {
|
|
browser.contextMenus.create({
|
|
parentId: assignManager.OPEN_IN_CONTAINER,
|
|
id: changeInfo.contextualIdentity.cookieStoreId,
|
|
title: changeInfo.contextualIdentity.name,
|
|
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}` }
|
|
});
|
|
},
|
|
|
|
contextualIdentityRemoved(changeInfo) {
|
|
browser.contextMenus.remove(changeInfo.contextualIdentity.cookieStoreId);
|
|
},
|
|
|
|
async _onClickedHandler(info, tab) {
|
|
const userContextId = this.getUserContextIdFromCookieStore(tab);
|
|
// Mapping ${URL(info.pageUrl).hostname} to ${userContextId}
|
|
let remove;
|
|
if (userContextId) {
|
|
switch (info.menuItemId) {
|
|
case this.MENU_ASSIGN_ID:
|
|
case this.MENU_REMOVE_ID:
|
|
if (info.menuItemId === this.MENU_ASSIGN_ID) {
|
|
remove = false;
|
|
} else {
|
|
remove = true;
|
|
}
|
|
await this._setOrRemoveAssignment(tab.id, info.pageUrl, userContextId, remove);
|
|
break;
|
|
case this.MENU_MOVE_ID:
|
|
backgroundLogic.moveTabsToWindow({
|
|
cookieStoreId: tab.cookieStoreId,
|
|
windowId: tab.windowId,
|
|
});
|
|
break;
|
|
case this.MENU_HIDE_ID:
|
|
backgroundLogic.hideTabs({
|
|
cookieStoreId: tab.cookieStoreId,
|
|
windowId: tab.windowId,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
async _onClickedBookmark(info) {
|
|
|
|
async function _getBookmarksFromInfo(info) {
|
|
const [bookmarkTreeNode] = await browser.bookmarks.get(info.bookmarkId);
|
|
if (bookmarkTreeNode.type === "folder") {
|
|
return await browser.bookmarks.getChildren(bookmarkTreeNode.id);
|
|
}
|
|
return [bookmarkTreeNode];
|
|
}
|
|
|
|
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") {
|
|
const openInReaderMode = bookmark.url.startsWith("about:reader");
|
|
if(openInReaderMode) {
|
|
try {
|
|
const parsed = new URL(bookmark.url);
|
|
bookmark.url = parsed.searchParams.get("url") + parsed.hash;
|
|
} catch (err) {
|
|
return err.message;
|
|
}
|
|
}
|
|
browser.tabs.create({
|
|
cookieStoreId: info.menuItemId,
|
|
url: bookmark.url,
|
|
openInReaderMode: openInReaderMode
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
deleteContainer(userContextId) {
|
|
this.storageArea.deleteContainer(userContextId);
|
|
},
|
|
|
|
getUserContextIdFromCookieStore(tab) {
|
|
if (!("cookieStoreId" in tab)) {
|
|
return false;
|
|
}
|
|
return backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId);
|
|
},
|
|
|
|
isTabPermittedAssign(tab) {
|
|
// Ensure we are not an important about url
|
|
const url = new URL(tab.url);
|
|
if (url.protocol === "about:"
|
|
|| url.protocol === "moz-extension:") {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
async _setOrRemoveAssignment(tabId, pageUrl, userContextId, remove) {
|
|
let actionName;
|
|
|
|
// https://github.com/mozilla/testpilot-containers/issues/626
|
|
// Context menu has stored context IDs as strings, so we need to coerce
|
|
// the value to a string for accurate checking
|
|
userContextId = String(userContextId);
|
|
|
|
if (!remove) {
|
|
const tabs = await browser.tabs.query({});
|
|
const assignmentStoreKey = this.storageArea.getSiteStoreKey(pageUrl);
|
|
const exemptedTabIds = tabs.filter((tab) => {
|
|
const tabStoreKey = this.storageArea.getSiteStoreKey(tab.url);
|
|
/* Auto exempt all tabs that exist for this hostname that are not in the same container */
|
|
if (tabStoreKey === assignmentStoreKey &&
|
|
this.getUserContextIdFromCookieStore(tab) !== userContextId) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}).map((tab) => {
|
|
return tab.id;
|
|
});
|
|
|
|
await this.storageArea.set(pageUrl, {
|
|
userContextId,
|
|
neverAsk: false
|
|
}, exemptedTabIds);
|
|
actionName = "added";
|
|
} else {
|
|
await this.storageArea.remove(pageUrl);
|
|
actionName = "removed";
|
|
}
|
|
browser.tabs.sendMessage(tabId, {
|
|
text: `Successfully ${actionName} site to always open in this container`
|
|
});
|
|
const tab = await browser.tabs.get(tabId);
|
|
this.calculateContextMenu(tab);
|
|
},
|
|
|
|
async _getAssignment(tab) {
|
|
const cookieStore = this.getUserContextIdFromCookieStore(tab);
|
|
// Ensure we have a cookieStore to assign to
|
|
if (cookieStore
|
|
&& this.isTabPermittedAssign(tab)) {
|
|
return await this.storageArea.get(tab.url);
|
|
}
|
|
return false;
|
|
},
|
|
|
|
_getByContainer(userContextId) {
|
|
return this.storageArea.getAssignedSites(userContextId);
|
|
},
|
|
|
|
removeContextMenu() {
|
|
// There is a focus issue in this menu where if you change window with a context menu click
|
|
// you get the wrong menu display because of async
|
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1215376#c16
|
|
// We also can't change for always private mode
|
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1352102
|
|
browser.contextMenus.remove(this.MENU_ASSIGN_ID);
|
|
browser.contextMenus.remove(this.MENU_REMOVE_ID);
|
|
browser.contextMenus.remove(this.MENU_SEPARATOR_ID);
|
|
browser.contextMenus.remove(this.MENU_HIDE_ID);
|
|
browser.contextMenus.remove(this.MENU_MOVE_ID);
|
|
},
|
|
|
|
async calculateContextMenu(tab) {
|
|
this.removeContextMenu();
|
|
const siteSettings = await this._getAssignment(tab);
|
|
// Return early and not add an item if we have false
|
|
// False represents assignment is not permitted
|
|
if (siteSettings === false) {
|
|
return false;
|
|
}
|
|
let checked = false;
|
|
let menuId = this.MENU_ASSIGN_ID;
|
|
const tabUserContextId = this.getUserContextIdFromCookieStore(tab);
|
|
if (siteSettings &&
|
|
Number(siteSettings.userContextId) === Number(tabUserContextId)) {
|
|
checked = true;
|
|
menuId = this.MENU_REMOVE_ID;
|
|
}
|
|
browser.contextMenus.create({
|
|
id: menuId,
|
|
title: "Always Open in This Container",
|
|
checked,
|
|
type: "checkbox",
|
|
contexts: ["all"],
|
|
});
|
|
|
|
browser.contextMenus.create({
|
|
id: this.MENU_SEPARATOR_ID,
|
|
type: "separator",
|
|
contexts: ["all"],
|
|
});
|
|
|
|
browser.contextMenus.create({
|
|
id: this.MENU_HIDE_ID,
|
|
title: "Hide This Container",
|
|
contexts: ["all"],
|
|
});
|
|
|
|
browser.contextMenus.create({
|
|
id: this.MENU_MOVE_ID,
|
|
title: "Move Tabs to a New Window",
|
|
contexts: ["all"],
|
|
});
|
|
},
|
|
|
|
encodeURLProperty(url) {
|
|
return encodeURIComponent(url).replace(/[!'()*]/g, (c) => {
|
|
const charCode = c.charCodeAt(0).toString(16);
|
|
return `%${charCode}`;
|
|
});
|
|
},
|
|
|
|
reloadPageInContainer(url, currentUserContextId, userContextId, index, active, neverAsk = false, openerTabId = null) {
|
|
const cookieStoreId = backgroundLogic.cookieStoreId(userContextId);
|
|
const loadPage = browser.extension.getURL("confirm-page.html");
|
|
// False represents assignment is not permitted
|
|
// If the user has explicitly checked "Never Ask Again" on the warning page we will send them straight there
|
|
if (neverAsk) {
|
|
browser.tabs.create({url, cookieStoreId, index, active, openerTabId});
|
|
} else {
|
|
let confirmUrl = `${loadPage}?url=${this.encodeURLProperty(url)}&cookieStoreId=${cookieStoreId}`;
|
|
let currentCookieStoreId;
|
|
if (currentUserContextId) {
|
|
currentCookieStoreId = backgroundLogic.cookieStoreId(currentUserContextId);
|
|
confirmUrl += `¤tCookieStoreId=${currentCookieStoreId}`;
|
|
}
|
|
browser.tabs.create({
|
|
url: confirmUrl,
|
|
cookieStoreId: currentCookieStoreId,
|
|
openerTabId,
|
|
index,
|
|
active
|
|
}).then(() => {
|
|
// We don't want to sync this URL ever nor clutter the users history
|
|
browser.history.deleteUrl({url: confirmUrl});
|
|
}).catch((e) => {
|
|
throw e;
|
|
});
|
|
}
|
|
},
|
|
|
|
async initBookmarksMenu() {
|
|
browser.contextMenus.create({
|
|
id: this.OPEN_IN_CONTAINER,
|
|
title: "Open Bookmark in Container Tab",
|
|
contexts: ["bookmark"],
|
|
});
|
|
|
|
const identities = await browser.contextualIdentities.query({});
|
|
for (const identity of identities) {
|
|
browser.contextMenus.create({
|
|
parentId: this.OPEN_IN_CONTAINER,
|
|
id: identity.cookieStoreId,
|
|
title: identity.name,
|
|
icons: { "16": `img/usercontext.svg#${identity.icon}` }
|
|
});
|
|
}
|
|
},
|
|
|
|
async removeBookmarksMenu() {
|
|
browser.contextMenus.remove(this.OPEN_IN_CONTAINER);
|
|
const identities = await browser.contextualIdentities.query({});
|
|
for (const identity of identities) {
|
|
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){
|
|
await runSync();
|
|
return;
|
|
}
|
|
await 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) {
|
|
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(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 () {
|
|
// 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;
|
|
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;
|
|
}
|
|
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.
|
|
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);
|
|
assignedSite.userContextId = cookieStoreId.replace(/^firefox-container-/, "");
|
|
await assignManager.storageArea.set(
|
|
urlKey.replace(/^siteContainerMap@@_/, "https://"),
|
|
assignedSite
|
|
);
|
|
}
|
|
|
|
async function runSync() {
|
|
browser.storage.onChanged.removeListener(syncOnChangedListener);
|
|
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();
|
|
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");
|
|
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 {
|
|
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) {
|
|
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");
|
|
}
|
|
}
|
|
} |