Skip to content

Commit

Permalink
Reopen already open facebook tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
stoically authored and Perflyst committed May 1, 2018
1 parent c847e26 commit b5ed2e8
Showing 1 changed file with 160 additions and 57 deletions.
217 changes: 160 additions & 57 deletions background.js
Expand Up @@ -12,9 +12,9 @@ const MAC_ADDON_ID = "@testpilot-containers";

let macAddonEnabled = false;
let googleCookieStoreId = null;
let googleCookiesCleared = false;

const canceledRequests = {};
const tabsWaitingToLoad = {};
const googleHostREs = [];

async function isMACAddonEnabled () {
Expand All @@ -39,20 +39,24 @@ async function setupMACAddonManagementListeners () {
if (info.id === MAC_ADDON_ID) {
macAddonEnabled = false;
}
})
});
browser.management.onEnabled.addListener(info => {
if (info.id === MAC_ADDON_ID) {
macAddonEnabled = true;
}
})
});
browser.management.onDisabled.addListener(info => {
if (info.id === MAC_ADDON_ID) {
macAddonEnabled = false;
}
})
});
}

async function getMACAssignment (url) {
if (!macAddonEnabled) {
return false;
}

try {
const assignment = await browser.runtime.sendMessage(MAC_ADDON_ID, {
method: "getAssignment",
Expand Down Expand Up @@ -117,7 +121,7 @@ async function clearGoogleCookies () {
// Clear all google cookies
const containers = await browser.contextualIdentities.query({});
containers.push({
cookieStoreId: 'firefox-default'
cookieStoreId: "firefox-default"
});
containers.map(container => {
const storeId = container.cookieStoreId;
Expand Down Expand Up @@ -147,7 +151,7 @@ async function clearGoogleCookies () {

async function setupContainer () {
// Use existing Google container, or create one
const contexts = await browser.contextualIdentities.query({name: GOOGLE_CONTAINER_NAME})
const contexts = await browser.contextualIdentities.query({name: GOOGLE_CONTAINER_NAME});
if (contexts.length > 0) {
googleCookieStoreId = contexts[0].cookieStoreId;
} else {
Expand All @@ -160,87 +164,186 @@ async function setupContainer () {
}
}

async function containGoogle (options) {
// Listen to requests and open Google into its Container,
// open other sites into the default tab context
const requestUrl = new URL(options.url);
function reopenTab ({url, tab, cookieStoreId}) {
browser.tabs.create({
url,
cookieStoreId,
active: tab.active,
index: tab.index,
windowId: tab.windowId
});
browser.tabs.remove(tab.id);
}

let isGoogle = false;
function isGoogleURL (url) {
const parsedUrl = new URL(url);
for (let googleHostRE of googleHostREs) {
if (googleHostRE.test(requestUrl.host)) {
isGoogle = true;
break;
if (googleHostRE.test(parsedUrl.host)) {
return true;
}
}
return false;
}

// We have to check with every request if the requested URL is assigned with MAC
// because the user can assign URLs at any given time (needs MAC Events)
if (macAddonEnabled) {
const macAssigned = await getMACAssignment(options.url);
function shouldContainInto (url, tab) {
if (!url.startsWith("http")) {
// we only handle URLs starting with http(s)
return false;
}

if (isGoogleURL(url)) {
if (tab.cookieStoreId !== googleCookieStoreId) {
// Google-URL outside of Google Container Tab
// Should contain into Google Container
return googleCookieStoreId;
}
} else if (tab.cookieStoreId === googleCookieStoreId) {
// Non-Google-URL inside Google Container Tab
// Should contain into Default Container
return "firefox-default";
}

return false;
}

async function maybeReopenAlreadyOpenTabs () {
const maybeReopenTab = async tab => {
const macAssigned = await getMACAssignment(tab.url);
if (macAssigned) {
// This URL is assigned with MAC, so we don't handle this request
// We don't reopen MAC assigned urls
return;
}
}
const cookieStoreId = shouldContainInto(tab.url, tab);
if (!cookieStoreId) {
// Tab doesn't need to be contained
return;
}
reopenTab({
url: tab.url,
tab,
cookieStoreId
});
};

const tab = await browser.tabs.get(options.tabId);
const tabCookieStoreId = tab.cookieStoreId;
if (isGoogle) {
if (tabCookieStoreId !== googleCookieStoreId && !tab.incognito) {
// See https://github.com/mozilla/contain-google/issues/23
// Sometimes this add-on is installed but doesn't get a googleCookieStoreId ?
if (googleCookieStoreId) {
if (shouldCancelEarly(tab, options)) {
return {cancel: true};
}
browser.tabs.create({
url: requestUrl.toString(),
cookieStoreId: googleCookieStoreId,
active: tab.active,
index: tab.index,
windowId: tab.windowId
});
browser.tabs.remove(options.tabId);
return {cancel: true};
}
const tabsOnUpdated = (tabId, changeInfo, tab) => {
if (changeInfo.url && tabsWaitingToLoad[tabId]) {
// Tab we're waiting for switched it's url, maybe we reopen
delete tabsWaitingToLoad[tabId];
maybeReopenTab(tab);
}
} else {
if (tabCookieStoreId === googleCookieStoreId) {
if (shouldCancelEarly(tab, options)) {
return {cancel: true};
if (tab.status === "complete" && tabsWaitingToLoad[tabId]) {
// Tab we're waiting for completed loading
delete tabsWaitingToLoad[tabId];
}
if (!Object.keys(tabsWaitingToLoad).length) {
// We're done waiting for tabs to load, remove event listener
browser.tabs.onUpdated.removeListener(tabsOnUpdated);
}
};

// Query for already open Tabs
const tabs = await browser.tabs.query({});
tabs.map(async tab => {
if (tab.incognito) {
return;
}
if (tab.url === "about:blank") {
if (tab.status !== "loading") {
return;
}
browser.tabs.create({
url: requestUrl.toString(),
active: tab.active,
index: tab.index,
windowId: tab.windowId
});
browser.tabs.remove(options.tabId);
return {cancel: true};
// about:blank Tab is still loading, so we indicate that we wait for it to load
// and register the event listener if we haven't yet.
//
// This is a workaround until platform support is implemented:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1447551
// https://github.com/mozilla/multi-account-containers/issues/474
tabsWaitingToLoad[tab.id] = true;
if (!browser.tabs.onUpdated.hasListener(tabsOnUpdated)) {
browser.tabs.onUpdated.addListener(tabsOnUpdated);
}
} else {
// Tab already has an url, maybe we reopen
maybeReopenTab(tab);
}
});
}

async function containGoogle (options) {
// Listen to requests and open Google into its Container,
// open other sites into the default tab context
if (options.tabId === -1) {
// Request doesn't belong to a tab
return;
}
if (tabsWaitingToLoad[options.tabId]) {
// Cleanup just to make sure we don't get a race-condition with startup reopening
delete tabsWaitingToLoad[options.tabId];
}

// We have to check with every request if the requested URL is assigned with MAC
// because the user can assign URLs at any given time (needs MAC Events)
const macAssigned = await getMACAssignment(options.url);
if (macAssigned) {
// This URL is assigned with MAC, so we don't handle this request
return;
}

const tab = await browser.tabs.get(options.tabId);
if (tab.incognito) {
// We don't handle incognito tabs
return;
}

// Check whether we should contain this request into another container
const cookieStoreId = shouldContainInto(options.url, tab);
if (!cookieStoreId) {
// Request doesn't need to be contained
return;
}
if (shouldCancelEarly(tab, options)) {
// We need to cancel early to prevent multiple reopenings
return {cancel: true};
}
// Decided to contain
reopenTab({
url: options.url,
tab,
cookieStoreId
});
return {cancel: true};
}

(async function init() {
await setupMACAddonManagementListeners();
macAddonEnabled = await isMACAddonEnabled();

await setupContainer();
try {
await setupContainer();
} catch (error) {
// TODO: Needs backup strategy
// See https://github.com/mozilla/contain-facebook/issues/23
// Sometimes this add-on is installed but doesn't get a googleCookieStoreId ?
// eslint-disable-next-line no-console
console.log(error);
return;
}
clearGoogleCookies();
generateGoogleHostREs();

// Add the request listener
browser.webRequest.onBeforeRequest.addListener(containGoogle, {urls: ["<all_urls>"], types: ["main_frame"]}, ["blocking"]);

// Clean up canceled requests
browser.webRequest.onCompleted.addListener((options) => {
if (canceledRequests[options.tabId]) {
delete canceledRequests[options.tabId];
delete canceledRequests[options.tabId];
}
},{urls: ["<all_urls>"], types: ["main_frame"]});
browser.webRequest.onErrorOccurred.addListener((options) => {
if (canceledRequests[options.tabId]) {
delete canceledRequests[options.tabId];
}
},{urls: ["<all_urls>"], types: ["main_frame"]});

// Add the request listener
browser.webRequest.onBeforeRequest.addListener(containGoogle, {urls: ["<all_urls>"], types: ["main_frame"]}, ["blocking"]);

maybeReopenAlreadyOpenTabs();
})();

0 comments on commit b5ed2e8

Please sign in to comment.