Container locking - restrict container to currently assigned domains
This commit is contained in:
parent
dc9e8f6399
commit
b57a9c1725
9 changed files with 218 additions and 16 deletions
|
@ -925,6 +925,15 @@ span ~ .panel-header-text {
|
||||||
padding-block-end: 6px;
|
padding-block-end: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* https://github.com/mozilla/multi-account-containers/issues/847 */
|
||||||
|
.container-lockorunlock.container-locked * {
|
||||||
|
filter: invert(0.5) sepia(1) saturate(127) hue-rotate(360deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-lockorunlock.container-unlocked * {
|
||||||
|
filter: invert(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
/* Achievement panel elements */
|
/* Achievement panel elements */
|
||||||
.share-ctas {
|
.share-ctas {
|
||||||
padding-block-end: 0.5em;
|
padding-block-end: 0.5em;
|
||||||
|
|
8
src/img/container-lock.svg
Normal file
8
src/img/container-lock.svg
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Adapted from https://www.materialui.co/icon/lock -->
|
||||||
|
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||||
|
<path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 545 B |
8
src/img/container-unlock.svg
Normal file
8
src/img/container-unlock.svg
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Adapted from https://www.materialui.co/icon/lock-open -->
|
||||||
|
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||||
|
<path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 556 B |
|
@ -141,8 +141,21 @@ const assignManager = {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const userContextId = this.getUserContextIdFromCookieStore(tab);
|
const userContextId = this.getUserContextIdFromCookieStore(tab);
|
||||||
if (!siteSettings
|
|
||||||
|| userContextId === siteSettings.userContextId
|
// Determine if "locked out", i.e.:
|
||||||
|
// This request's URL is not associated with any particular contextualIdentity.
|
||||||
|
// But the current tab's contextualIdentity is locked. So must open request in new tab.
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
let isLockedOut;
|
||||||
|
if (!siteSettings && "cookieStoreId" in tab) {
|
||||||
|
const currentContainerState = await identityState.storageArea.get(tab.cookieStoreId);
|
||||||
|
isLockedOut = !!currentContainerState.isLocked;
|
||||||
|
} else {
|
||||||
|
isLockedOut = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!siteSettings && !isLockedOut)
|
||||||
|
|| (siteSettings && userContextId === siteSettings.userContextId)
|
||||||
|| this.storageArea.isExempted(options.url, tab.id)) {
|
|| this.storageArea.isExempted(options.url, tab.id)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -188,6 +201,12 @@ const assignManager = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isLockedOut) {
|
||||||
|
// Open new tab in default context
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
browser.tabs.create({url: options.url});
|
||||||
|
} else {
|
||||||
|
// Open new tab in specific context
|
||||||
this.reloadPageInContainer(
|
this.reloadPageInContainer(
|
||||||
options.url,
|
options.url,
|
||||||
userContextId,
|
userContextId,
|
||||||
|
@ -197,6 +216,7 @@ const assignManager = {
|
||||||
siteSettings.neverAsk,
|
siteSettings.neverAsk,
|
||||||
openTabId
|
openTabId
|
||||||
);
|
);
|
||||||
|
}
|
||||||
this.calculateContextMenu(tab);
|
this.calculateContextMenu(tab);
|
||||||
|
|
||||||
/* Removal of existing tabs:
|
/* Removal of existing tabs:
|
||||||
|
@ -395,7 +415,20 @@ const assignManager = {
|
||||||
neverAsk: false
|
neverAsk: false
|
||||||
}, exemptedTabIds);
|
}, exemptedTabIds);
|
||||||
actionName = "added";
|
actionName = "added";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// Unlock container if no more assignments after this one is removed.
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
const assignments = await this.storageArea.getByContainer(userContextId);
|
||||||
|
const assignmentKeys = Object.keys(assignments);
|
||||||
|
if (!(assignmentKeys.length > 1)) {
|
||||||
|
await backgroundLogic.lockOrUnlockContainer({
|
||||||
|
userContextId: userContextId,
|
||||||
|
isLocked: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove assignment
|
||||||
await this.storageArea.remove(pageUrl);
|
await this.storageArea.remove(pageUrl);
|
||||||
actionName = "removed";
|
actionName = "removed";
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,22 @@ const backgroundLogic = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
async lockOrUnlockContainer(options) {
|
||||||
|
if (!("userContextId" in options)) {
|
||||||
|
return Promise.reject("lockOrUnlockContainer must be called with userContextId argument.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookieStoreId = this.cookieStoreId(options.userContextId);
|
||||||
|
const containerState = await identityState.storageArea.get(cookieStoreId);
|
||||||
|
if (options.isLocked) {
|
||||||
|
containerState.isLocked = "locked";
|
||||||
|
} else {
|
||||||
|
delete containerState.isLocked;
|
||||||
|
}
|
||||||
|
return await identityState.storageArea.set(cookieStoreId, containerState);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
async moveTabsToWindow(options) {
|
async moveTabsToWindow(options) {
|
||||||
const requiredArguments = ["cookieStoreId", "windowId"];
|
const requiredArguments = ["cookieStoreId", "windowId"];
|
||||||
|
@ -229,7 +245,9 @@ const backgroundLogic = {
|
||||||
hasHiddenTabs: !!containerState.hiddenTabs.length,
|
hasHiddenTabs: !!containerState.hiddenTabs.length,
|
||||||
hasOpenTabs: !!openTabs.length,
|
hasOpenTabs: !!openTabs.length,
|
||||||
numberOfHiddenTabs: containerState.hiddenTabs.length,
|
numberOfHiddenTabs: containerState.hiddenTabs.length,
|
||||||
numberOfOpenTabs: openTabs.length
|
numberOfOpenTabs: openTabs.length,
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
isLocked: !!containerState.isLocked
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,6 +19,10 @@ const messageHandler = {
|
||||||
case "createOrUpdateContainer":
|
case "createOrUpdateContainer":
|
||||||
response = backgroundLogic.createOrUpdateContainer(m.message);
|
response = backgroundLogic.createOrUpdateContainer(m.message);
|
||||||
break;
|
break;
|
||||||
|
case "lockOrUnlockContainer":
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
response = backgroundLogic.lockOrUnlockContainer(m.message);
|
||||||
|
break;
|
||||||
case "neverAsk":
|
case "neverAsk":
|
||||||
assignManager._neverAsk(m);
|
assignManager._neverAsk(m);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
const CONTAINER_HIDE_SRC = "/img/container-hide.svg";
|
const CONTAINER_HIDE_SRC = "/img/container-hide.svg";
|
||||||
const CONTAINER_UNHIDE_SRC = "/img/container-unhide.svg";
|
const CONTAINER_UNHIDE_SRC = "/img/container-unhide.svg";
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
const CONTAINER_LOCKED_SRC = "/img/container-lock.svg";
|
||||||
|
const CONTAINER_UNLOCKED_SRC = "/img/container-unlock.svg";
|
||||||
|
|
||||||
const DEFAULT_COLOR = "blue";
|
const DEFAULT_COLOR = "blue";
|
||||||
const DEFAULT_ICON = "circle";
|
const DEFAULT_ICON = "circle";
|
||||||
|
@ -252,6 +255,8 @@ const Logic = {
|
||||||
identity.hasHiddenTabs = stateObject.hasHiddenTabs;
|
identity.hasHiddenTabs = stateObject.hasHiddenTabs;
|
||||||
identity.numberOfHiddenTabs = stateObject.numberOfHiddenTabs;
|
identity.numberOfHiddenTabs = stateObject.numberOfHiddenTabs;
|
||||||
identity.numberOfOpenTabs = stateObject.numberOfOpenTabs;
|
identity.numberOfOpenTabs = stateObject.numberOfOpenTabs;
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
identity.isLocked = stateObject.isLocked;
|
||||||
}
|
}
|
||||||
return identity;
|
return identity;
|
||||||
});
|
});
|
||||||
|
@ -1011,7 +1016,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showAssignedContainers(assignments) {
|
showAssignedContainers(assignments, isLocked) {
|
||||||
const assignmentPanel = document.getElementById("edit-sites-assigned");
|
const assignmentPanel = document.getElementById("edit-sites-assigned");
|
||||||
const assignmentKeys = Object.keys(assignments);
|
const assignmentKeys = Object.keys(assignments);
|
||||||
assignmentPanel.hidden = !(assignmentKeys.length > 0);
|
assignmentPanel.hidden = !(assignmentKeys.length > 0);
|
||||||
|
@ -1022,6 +1027,38 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
while (tableElement.firstChild) {
|
while (tableElement.firstChild) {
|
||||||
tableElement.firstChild.remove();
|
tableElement.firstChild.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Container locking: https://github.com/mozilla/multi-account-containers/issues/847 */
|
||||||
|
const lockOrUnlockIcon = isLocked ? CONTAINER_LOCKED_SRC : CONTAINER_UNLOCKED_SRC;
|
||||||
|
const lockOrUnlockLabel = isLocked ? "Locked" : "Unlocked";
|
||||||
|
const lockOrUnlockClass = isLocked ? "container-locked" : "container-unlocked";
|
||||||
|
const lockElement = document.createElement("div");
|
||||||
|
lockElement.innerHTML = escaped`
|
||||||
|
<img class="icon" src="${lockOrUnlockIcon}">
|
||||||
|
<div title="${lockOrUnlockLabel}">
|
||||||
|
${lockOrUnlockLabel}
|
||||||
|
</div>`;
|
||||||
|
lockElement.classList.add("container-info-tab-row", "clickable", "container-lockorunlock", lockOrUnlockClass);
|
||||||
|
tableElement.appendChild(lockElement);
|
||||||
|
|
||||||
|
const that = this;
|
||||||
|
Logic.addEnterHandler(lockElement, async () => {
|
||||||
|
try {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
method: "lockOrUnlockContainer",
|
||||||
|
message: {
|
||||||
|
userContextId: Logic.currentUserContextId(),
|
||||||
|
isLocked: !isLocked
|
||||||
|
}
|
||||||
|
});
|
||||||
|
that.showAssignedContainers(assignments, !isLocked);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error("Failed to lock/unlock. ", e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/* Container locking: https://github.com/mozilla/multi-account-containers/issues/847 */
|
||||||
|
|
||||||
|
/* Assignment list */
|
||||||
assignmentKeys.forEach((siteKey) => {
|
assignmentKeys.forEach((siteKey) => {
|
||||||
const site = assignments[siteKey];
|
const site = assignments[siteKey];
|
||||||
const trElement = document.createElement("div");
|
const trElement = document.createElement("div");
|
||||||
|
@ -1047,7 +1084,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
const currentTab = await Logic.currentTab();
|
const currentTab = await Logic.currentTab();
|
||||||
Logic.setOrRemoveAssignment(currentTab.id, assumedUrl, userContextId, true);
|
Logic.setOrRemoveAssignment(currentTab.id, assumedUrl, userContextId, true);
|
||||||
delete assignments[siteKey];
|
delete assignments[siteKey];
|
||||||
that.showAssignedContainers(assignments);
|
that.showAssignedContainers(assignments, isLocked);
|
||||||
});
|
});
|
||||||
trElement.classList.add("container-info-tab-row", "clickable");
|
trElement.classList.add("container-info-tab-row", "clickable");
|
||||||
tableElement.appendChild(trElement);
|
tableElement.appendChild(trElement);
|
||||||
|
@ -1091,7 +1128,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
|
|
||||||
const userContextId = Logic.currentUserContextId();
|
const userContextId = Logic.currentUserContextId();
|
||||||
const assignments = await Logic.getAssignmentObjectByContainer(userContextId);
|
const assignments = await Logic.getAssignmentObjectByContainer(userContextId);
|
||||||
this.showAssignedContainers(assignments);
|
this.showAssignedContainers(assignments, identity.isLocked);
|
||||||
document.querySelector("#edit-container-panel .panel-footer").hidden = !!userContextId;
|
document.querySelector("#edit-container-panel .panel-footer").hidden = !!userContextId;
|
||||||
|
|
||||||
document.querySelector("#edit-container-panel-name-input").value = identity.name || "";
|
document.querySelector("#edit-container-panel-name-input").value = identity.name || "";
|
||||||
|
|
54
test/features/lock.test.js
Normal file
54
test/features/lock.test.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
describe("Lock Feature", () => {
|
||||||
|
const activeTab = {
|
||||||
|
id: 1,
|
||||||
|
cookieStoreId: "firefox-container-1",
|
||||||
|
url: "http://example.com",
|
||||||
|
index: 0
|
||||||
|
};
|
||||||
|
beforeEach(async () => {
|
||||||
|
await helper.browser.initializeWithTab(activeTab);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("click the 'Always open in' checkbox in the popup", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
// popup click to set assignment for activeTab.url
|
||||||
|
await helper.popup.clickElementById("container-page-assigned");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("open different URL in same tab", () => {
|
||||||
|
const differentURL = "http://example2.com";
|
||||||
|
beforeEach(async () => {
|
||||||
|
await helper.browser.updateTab(activeTab, {
|
||||||
|
url: differentURL,
|
||||||
|
resetHistory: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not open a new tab", () => {
|
||||||
|
background.browser.tabs.create.should.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("lock the container", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await helper.popup.setContainerIsLocked(activeTab.cookieStoreId, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("open different URL in same tab", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await helper.browser.updateTab(activeTab, {
|
||||||
|
url: differentURL,
|
||||||
|
resetHistory: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should open a new tab in the default container", () => {
|
||||||
|
background.browser.tabs.create.should.have.been.calledWith({
|
||||||
|
url: differentURL
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -29,7 +29,19 @@ module.exports = {
|
||||||
|
|
||||||
async openNewTab(tab, options = {}) {
|
async openNewTab(tab, options = {}) {
|
||||||
return background.browser.tabs._create(tab, options);
|
return background.browser.tabs._create(tab, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
async updateTab(tab, options = {}) {
|
||||||
|
const updatedTab = {};
|
||||||
|
for (const key in tab) {
|
||||||
|
updatedTab[key] = tab[key];
|
||||||
}
|
}
|
||||||
|
for (const key in options) {
|
||||||
|
updatedTab[key] = options[key];
|
||||||
|
}
|
||||||
|
return this.openNewTab(updatedTab);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
popup: {
|
popup: {
|
||||||
|
@ -39,6 +51,25 @@ module.exports = {
|
||||||
|
|
||||||
async clickLastMatchingElementByQuerySelector(querySelector) {
|
async clickLastMatchingElementByQuerySelector(querySelector) {
|
||||||
await popup.helper.clickElementByQuerySelectorAll(querySelector, "last");
|
await popup.helper.clickElementByQuerySelectorAll(querySelector, "last");
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||||
|
async setContainerIsLocked(cookieStoreId, isLocked) {
|
||||||
|
const identityStateKey = this.getIdentityStateContainerStoreKey(cookieStoreId);
|
||||||
|
const identityState = await background.browser.storage.local.get([identityStateKey]) || {};
|
||||||
|
if (isLocked) {
|
||||||
|
identityState.isLocked = "locked";
|
||||||
|
} else {
|
||||||
|
delete identityState.isLocked;
|
||||||
|
}
|
||||||
|
// Must have valid 'hiddenTabs', otherwise backgroundLogic.showTabs() throws error
|
||||||
|
if (!identityState.hiddenTabs) { identityState.hiddenTabs = []; }
|
||||||
|
await background.browser.storage.local.set({[identityStateKey]: identityState});
|
||||||
|
},
|
||||||
|
|
||||||
|
getIdentityStateContainerStoreKey(cookieStoreId) {
|
||||||
|
const storagePrefix = "identitiesState@@_";
|
||||||
|
return `${storagePrefix}${cookieStoreId}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue