Skip to content

Commit a53eb64

Browse files
authored
Merge pull request #2654 from mozilla/feat-#303
#303: Reset cookies in site manager
2 parents 077c7e0 + c644a60 commit a53eb64

File tree

9 files changed

+205
-12
lines changed

9 files changed

+205
-12
lines changed

src/css/popup.css

+55-9
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ body {
228228

229229
/* Hack for menu icons to use a light color without affecting container icons */
230230
[data-theme="light"] img.delete-assignment,
231+
[data-theme="dark"] img.reset-assignment,
231232
[data-theme="dark"] .trash-button,
232233
[data-theme="dark"] img.menu-icon,
233234
[data-theme="dark"] .menu-icon > img,
@@ -236,6 +237,7 @@ body {
236237
filter: invert(1);
237238
}
238239

240+
[data-theme="dark"] img.clear-storage-icon,
239241
[data-theme="dark"] img.delete-assignment,
240242
[data-theme="dark"] #edit-sites-assigned .menu-icon,
241243
[data-theme="dark"] #container-info-table .menu-icon {
@@ -285,9 +287,33 @@ table {
285287
display: none !important;
286288
}
287289

290+
.popup-notification-card {
291+
opacity: 0;
292+
pointer-events: none;
293+
transition: opacity 2s;
294+
border-radius: 4px;
295+
font-size: 12px;
296+
position: absolute;
297+
inset-block-start: 0;
298+
inset-inline-start: 0;
299+
padding-block: 8px;
300+
padding-inline: 8px;
301+
margin-block: 8px;
302+
margin-inline: 8px;
303+
inline-size: calc(100vw - 25px);
304+
background-color: var(--button-bg-active-color-secondary);
305+
z-index: 3;
306+
}
307+
308+
.is-shown {
309+
pointer-events: auto;
310+
opacity: 1;
311+
transition: opacity 0s;
312+
}
313+
288314
/* effect borrowed from tabs in firefox, ensure that the element flexes to the full width */
289315
.truncate-text {
290-
inline-size: calc(100vw - 80px);
316+
inline-size: calc(100vw - 100px);
291317
overflow: hidden;
292318
position: relative;
293319
white-space: nowrap;
@@ -1505,8 +1531,9 @@ input[type=text] {
15051531
min-block-size: 500px;
15061532
}
15071533

1508-
.delete-container-panel {
1509-
min-block-size: 300px;
1534+
.delete-container-panel,
1535+
.clear-container-storage-panel {
1536+
min-block-size: 500px;
15101537
}
15111538

15121539
.panel.onboarding,
@@ -1794,12 +1821,14 @@ manage things like container crud */
17941821
margin-inline-end: 0;
17951822
}
17961823

1797-
.delete-container-confirm {
1824+
.delete-container-confirm,
1825+
.clear-container-storage-confirm {
17981826
padding-inline-end: 20px;
17991827
padding-inline-start: 20px;
18001828
}
18011829

1802-
.delete-container-confirm-title {
1830+
.delete-container-confirm-title,
1831+
.clear-container-storage-confirm-title {
18031832
color: var(--text-color-primary);
18041833
font-size: var(--font-size-heading);
18051834
}
@@ -2173,6 +2202,11 @@ hr {
21732202
text-align: center;
21742203
}
21752204

2205+
.confirmation-destructive-ok-btn {
2206+
background-color: var(--button-destructive-bg-color);
2207+
color: var(--button-destructive-text-color);
2208+
}
2209+
21762210
.delete-btn {
21772211
background-color: var(--button-destructive-bg-color);
21782212
block-size: 32px;
@@ -2303,7 +2337,8 @@ input {
23032337
font-weight: bolder;
23042338
}
23052339

2306-
.delete-warning {
2340+
.delete-warning,
2341+
.clear-container-storage-warning {
23072342
padding-block-end: 8px;
23082343
padding-block-start: 8px;
23092344
padding-inline-end: 0;
@@ -2314,7 +2349,8 @@ input {
23142349
* rules grouped together at the beginning of the file
23152350
*/
23162351
/* stylelint-disable no-descending-specificity */
2317-
.trash-button {
2352+
.trash-button,
2353+
.reset-button {
23182354
display: inline-block;
23192355
block-size: 20px;
23202356
inline-size: 20px;
@@ -2323,11 +2359,21 @@ input {
23232359
text-align: center;
23242360
}
23252361

2326-
tr > td > .trash-button {
2362+
.reset-button {
2363+
margin-inline-end: 12px;
2364+
}
2365+
2366+
.tooltip-wrapper:hover .site-settings-tooltip {
2367+
display: block;
2368+
}
2369+
2370+
tr > td > .trash-button,
2371+
tr > td > .reset-button {
23272372
display: none;
23282373
}
23292374

2330-
tr:hover > td > .trash-button {
2375+
tr:hover > td > .trash-button,
2376+
tr:hover > td > .reset-button {
23312377
display: block;
23322378
}
23332379

src/js/background/assignManager.js

+10
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,16 @@ window.assignManager = {
577577
return true;
578578
},
579579

580+
async _resetCookiesForSite(hostname, cookieStoreId) {
581+
const hostNameTruncated = hostname.replace(/^www\./, ""); // Remove "www." from the hostname
582+
await browser.browsingData.removeCookies({
583+
cookieStoreId: cookieStoreId,
584+
hostnames: [hostNameTruncated] // This does not remove cookies from associated domains. To remove all cookies, we have a container storage removal option.
585+
});
586+
587+
return true;
588+
},
589+
580590
async _setOrRemoveAssignment(tabId, pageUrl, userContextId, remove) {
581591
let actionName;
582592
// https://github.com/mozilla/testpilot-containers/issues/626

src/js/background/backgroundLogic.js

+13
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@ const backgroundLogic = {
7575
return extensionInfo;
7676
},
7777

78+
// Remove container data (cookies, localStorage and cache)
79+
async deleteContainerDataOnly(userContextId) {
80+
await browser.browsingData.removeCookies({
81+
cookieStoreId: this.cookieStoreId(userContextId)
82+
});
83+
84+
await browser.browsingData.removeLocalStorage({
85+
cookieStoreId: this.cookieStoreId(userContextId)
86+
});
87+
88+
return {done: true, userContextId};
89+
},
90+
7891
getUserContextIdFromCookieStoreId(cookieStoreId) {
7992
if (!cookieStoreId) {
8093
return false;

src/js/background/messageHandler.js

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const messageHandler = {
2323
case "deleteContainer":
2424
response = backgroundLogic.deleteContainer(m.message.userContextId);
2525
break;
26+
case "deleteContainerDataOnly":
27+
response = backgroundLogic.deleteContainerDataOnly(m.message.userContextId);
28+
break;
2629
case "createOrUpdateContainer":
2730
response = backgroundLogic.createOrUpdateContainer(m.message);
2831
break;
@@ -45,6 +48,9 @@ const messageHandler = {
4548
// m.url is the assignment to be removed/added
4649
response = assignManager._setOrRemoveAssignment(m.tabId, m.url, m.userContextId, m.value);
4750
break;
51+
case "resetCookiesForSite":
52+
response = assignManager._resetCookiesForSite(m.pageUrl, m.cookieStoreId);
53+
break;
4854
case "sortTabs":
4955
backgroundLogic.sortTabs();
5056
break;

src/js/popup.js

+81-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const P_CONTAINER_EDIT = "containerEdit";
3232
const P_CONTAINER_DELETE = "containerDelete";
3333
const P_CONTAINERS_ACHIEVEMENT = "containersAchievement";
3434
const P_CONTAINER_ASSIGNMENTS = "containerAssignments";
35+
const P_CLEAR_CONTAINER_STORAGE = "clearContainerStorage";
3536

3637
const P_MOZILLA_VPN_SERVER_LIST = "moz-vpn-server-list";
3738
const P_ADVANCED_PROXY_SETTINGS = "advanced-proxy-settings-panel";
@@ -122,6 +123,19 @@ const Logic = {
122123

123124
},
124125

126+
notify(i18nOpts) {
127+
const notificationCards = document.querySelectorAll(".popup-notification-card");
128+
const text = browser.i18n.getMessage(i18nOpts.messageId, i18nOpts.placeholders);
129+
notificationCards.forEach(notificationCard => {
130+
notificationCard.textContent = text;
131+
notificationCard.classList.add("is-shown");
132+
133+
setTimeout(() => {
134+
notificationCard.classList.remove("is-shown");
135+
}, 2000);
136+
});
137+
},
138+
125139
async showAchievementOrContainersListPanel() {
126140
// Do we need to show an achievement panel?
127141
let showAchievements = false;
@@ -971,6 +985,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
971985
Utils.alwaysOpenInContainer(identity);
972986
window.close();
973987
});
988+
974989
// Show or not the has-tabs section.
975990
for (let trHasTabs of document.getElementsByClassName("container-info-has-tabs")) { // eslint-disable-line prefer-const
976991
trHasTabs.style.display = !identity.hasHiddenTabs && !identity.hasOpenTabs ? "none" : "";
@@ -994,6 +1009,13 @@ Logic.registerPanel(P_CONTAINER_INFO, {
9941009
Utils.addEnterHandler(manageContainer, async () => {
9951010
Logic.showPanel(P_CONTAINER_EDIT, identity);
9961011
});
1012+
const clearContainerStorageButton = document.getElementById("clear-container-storage-info");
1013+
Utils.addEnterHandler(clearContainerStorageButton, async () => {
1014+
const granted = await browser.permissions.request({ permissions: ["browsingData"] });
1015+
if (granted) {
1016+
Logic.showPanel(P_CLEAR_CONTAINER_STORAGE, identity);
1017+
}
1018+
});
9971019
return this.buildOpenTabTable(tabs);
9981020
},
9991021

@@ -1455,11 +1477,14 @@ Logic.registerPanel(P_CONTAINER_ASSIGNMENTS, {
14551477
/* As we don't have the full or correct path the best we can assume is the path is HTTPS and then replace with a broken icon later if it doesn't load.
14561478
This is pending a better solution for favicons from web extensions */
14571479
const assumedUrl = `https://${site.hostname}/favicon.ico`;
1480+
const resetSiteCookiesInfo = browser.i18n.getMessage("clearSiteCookiesTooltipInfo");
1481+
const deleteSiteInfo = browser.i18n.getMessage("deleteSiteTooltipInfo");
14581482
trElement.innerHTML = Utils.escaped`
14591483
<td>
14601484
<div class="favicon"></div>
14611485
<span title="${site.hostname}" class="menu-text truncate-text">${site.hostname}</span>
1462-
<img class="trash-button delete-assignment" src="/img/container-delete.svg" />
1486+
<img title="${resetSiteCookiesInfo}" class="reset-button reset-assignment" src="/img/refresh-16.svg" />
1487+
<img title="${deleteSiteInfo}" class="trash-button delete-assignment" src="/img/container-delete.svg" />
14631488
</td>`;
14641489
trElement.getElementsByClassName("favicon")[0].appendChild(Utils.createFavIconElement(assumedUrl));
14651490
const deleteButton = trElement.querySelector(".trash-button");
@@ -1471,6 +1496,20 @@ Logic.registerPanel(P_CONTAINER_ASSIGNMENTS, {
14711496
delete assignments[siteKey];
14721497
this.showAssignedContainers(assignments);
14731498
});
1499+
const resetButton = trElement.querySelector(".reset-button");
1500+
Utils.addEnterHandler(resetButton, async () => {
1501+
const cookieStoreId = Logic.currentCookieStoreId();
1502+
const granted = await browser.permissions.request({ permissions: ["browsingData"] });
1503+
if (!granted) {
1504+
return;
1505+
}
1506+
const result = await Utils.resetCookiesForSite(site.hostname, cookieStoreId);
1507+
if (result === true) {
1508+
Logic.notify({messageId: "cookiesClearedSuccess", placeholders: [site.hostname]});
1509+
} else {
1510+
Logic.notify({messageId: "cookiesCouldNotBeCleared", placeholders: [site.hostname]});
1511+
}
1512+
});
14741513
trElement.classList.add("menu-item", "hover-highlight", "keyboard-nav");
14751514
tableElement.appendChild(trElement);
14761515
});
@@ -2246,6 +2285,47 @@ Logic.registerPanel(P_MOZILLA_VPN_SERVER_LIST, {
22462285
}
22472286
});
22482287

2288+
// P_CLEAR_CONTAINER_STORAGE: Page for confirming container storage removal.
2289+
// ----------------------------------------------------------------------------
2290+
2291+
Logic.registerPanel(P_CLEAR_CONTAINER_STORAGE, {
2292+
panelSelector: "#clear-container-storage-panel",
2293+
2294+
// This method is called when the object is registered.
2295+
initialize() {
2296+
2297+
Utils.addEnterHandler(document.querySelector("#clear-container-storage-cancel-link"), () => {
2298+
const identity = Logic.currentIdentity();
2299+
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
2300+
});
2301+
Utils.addEnterHandler(document.querySelector("#close-clear-container-storage-panel"), () => {
2302+
const identity = Logic.currentIdentity();
2303+
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
2304+
});
2305+
Utils.addEnterHandler(document.querySelector("#clear-container-storage-ok-link"), async () => {
2306+
const identity = Logic.currentIdentity();
2307+
const userContextId = Utils.userContextId(identity.cookieStoreId);
2308+
const result = await browser.runtime.sendMessage({
2309+
method: "deleteContainerDataOnly",
2310+
message: { userContextId }
2311+
});
2312+
if (result.done === true) {
2313+
Logic.notify({messageId: "storageWasClearedConfirmation", placeholders: [identity.name]});
2314+
}
2315+
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
2316+
});
2317+
},
2318+
2319+
// This method is called when the panel is shown.
2320+
prepare() {
2321+
const identity = Logic.currentIdentity();
2322+
2323+
// Populating the panel: name, icon, and warning message
2324+
document.getElementById("container-clear-storage-title").textContent = identity.name;
2325+
return Promise.resolve(null);
2326+
},
2327+
});
2328+
22492329
// P_CONTAINER_DELETE: Delete a container.
22502330
// ----------------------------------------------------------------------------
22512331

src/js/utils.js

+8
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,14 @@ const Utils = {
138138
});
139139
},
140140

141+
resetCookiesForSite(pageUrl, cookieStoreId) {
142+
return browser.runtime.sendMessage({
143+
method: "resetCookiesForSite",
144+
pageUrl,
145+
cookieStoreId,
146+
});
147+
},
148+
141149
async reloadInContainer(url, currentUserContextId, newUserContextId, tabIndex, active) {
142150
return await browser.runtime.sendMessage({
143151
method: "reloadInContainer",

src/manifest.json

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
],
2727
"optional_permissions": [
2828
"bookmarks",
29+
"browsingData",
2930
"nativeMessaging",
3031
"proxy"
3132
],

0 commit comments

Comments
 (0)