browser_siteData.js (13224B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 function getPersistentStoragePermStatus(origin) { 7 let uri = Services.io.newURI(origin); 8 let principal = Services.scriptSecurityManager.createContentPrincipal( 9 uri, 10 {} 11 ); 12 return Services.perms.testExactPermissionFromPrincipal( 13 principal, 14 "persistent-storage" 15 ); 16 } 17 18 // Test listing site using quota usage or site using appcache 19 // This is currently disabled because of bug 1414751. 20 add_task(async function test_list_sites() { 21 // Open a test site which would save into appcache 22 await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_OFFLINE_URL); 23 BrowserTestUtils.removeTab(gBrowser.selectedTab); 24 25 // Open a test site which would save into quota manager 26 BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL); 27 await BrowserTestUtils.waitForContentEvent( 28 gBrowser.selectedBrowser, 29 "test-indexedDB-done", 30 false, 31 null, 32 true 33 ); 34 BrowserTestUtils.removeTab(gBrowser.selectedTab); 35 36 let updatedPromise = promiseSiteDataManagerSitesUpdated(); 37 await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); 38 await updatedPromise; 39 await openSiteDataSettingsDialog(); 40 let dialog = content.gSubDialog._topDialog; 41 let dialogFrame = dialog._frame; 42 let frameDoc = dialogFrame.contentDocument; 43 44 let siteItems = frameDoc.getElementsByTagName("richlistitem"); 45 is(siteItems.length, 2, "Should list sites using quota usage or appcache"); 46 47 let appcacheSite = frameDoc.querySelector( 48 `richlistitem[host="${TEST_OFFLINE_HOST}"]` 49 ); 50 ok(appcacheSite, "Should list site using appcache"); 51 52 let qoutaUsageSite = frameDoc.querySelector( 53 `richlistitem[host="${TEST_QUOTA_USAGE_HOST}"]` 54 ); 55 ok(qoutaUsageSite, "Should list site using quota usage"); 56 57 // Always remember to clean up 58 await new Promise(resolve => { 59 let principal = 60 Services.scriptSecurityManager.createContentPrincipalFromOrigin( 61 TEST_QUOTA_USAGE_ORIGIN 62 ); 63 let request = Services.qms.clearStoragesForOriginPrefix(principal); 64 request.callback = resolve; 65 }); 66 67 await SiteDataManager.removeAll(); 68 BrowserTestUtils.removeTab(gBrowser.selectedTab); 69 }).skip(); // Bug 1414751 70 71 // Test buttons are disabled and loading message shown while updating sites 72 add_task(async function test_ui_loading_state() { 73 let updatedPromise = promiseSiteDataManagerSitesUpdated(); 74 await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); 75 await updatedPromise; 76 let cacheSize = await SiteDataManager.getCacheSize(); 77 78 let doc = gBrowser.selectedBrowser.contentDocument; 79 let clearBtn = doc.getElementById("clearSiteDataButton"); 80 let settingsButton = doc.getElementById("siteDataSettings"); 81 let totalSiteDataSizeLabel = doc.getElementById("siteDataSize"); 82 is( 83 clearBtn.disabled, 84 false, 85 "Should enable clear button after sites updated" 86 ); 87 is( 88 settingsButton.disabled, 89 false, 90 "Should enable settings button after sites updated" 91 ); 92 await SiteDataManager.getTotalUsage().then(usage => { 93 let [value, unit] = DownloadUtils.convertByteUnits(usage + cacheSize); 94 Assert.deepEqual( 95 doc.l10n.getAttributes(totalSiteDataSizeLabel), 96 { 97 id: "sitedata-total-size2", 98 args: { value, unit }, 99 }, 100 "Should show the right total site data size" 101 ); 102 }); 103 104 Services.obs.notifyObservers(null, "sitedatamanager:updating-sites"); 105 // Wait a tick for the UI to update. 106 await new Promise(resolve => requestAnimationFrame(resolve)); 107 108 is( 109 clearBtn.disabled, 110 true, 111 "Should disable clear button while updating sites" 112 ); 113 is( 114 settingsButton.disabled, 115 true, 116 "Should disable settings button while updating sites" 117 ); 118 Assert.equal( 119 doc.l10n.getAttributes(totalSiteDataSizeLabel).id, 120 "sitedata-total-size-calculating", 121 "Should show the loading message while updating" 122 ); 123 124 Services.obs.notifyObservers(null, "sitedatamanager:sites-updated"); 125 // Wait a tick for the UI to update. 126 await new Promise(resolve => setTimeout(resolve, 0)); 127 128 is( 129 clearBtn.disabled, 130 false, 131 "Should enable clear button after sites updated" 132 ); 133 is( 134 settingsButton.disabled, 135 false, 136 "Should enable settings button after sites updated" 137 ); 138 cacheSize = await SiteDataManager.getCacheSize(); 139 await SiteDataManager.getTotalUsage().then(usage => { 140 let [value, unit] = DownloadUtils.convertByteUnits(usage + cacheSize); 141 Assert.deepEqual( 142 doc.l10n.getAttributes(totalSiteDataSizeLabel), 143 { 144 id: "sitedata-total-size2", 145 args: { value, unit }, 146 }, 147 "Should show the right total site data size" 148 ); 149 }); 150 151 BrowserTestUtils.removeTab(gBrowser.selectedTab); 152 }); 153 154 // Test clearing service worker through the settings panel 155 add_task(async function test_clear_service_worker() { 156 // Register a test service worker 157 await loadServiceWorkerTestPage(TEST_SERVICE_WORKER_URL); 158 await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); 159 // Test the initial states 160 await promiseServiceWorkerRegisteredFor(TEST_SERVICE_WORKER_URL); 161 // Open the Site Data Settings panel and remove the site 162 await openSiteDataSettingsDialog(); 163 let acceptRemovePromise = BrowserTestUtils.promiseAlertDialogOpen("accept"); 164 let updatePromise = promiseSiteDataManagerSitesUpdated(); 165 SpecialPowers.spawn( 166 gBrowser.selectedBrowser, 167 [{ TEST_OFFLINE_HOST }], 168 args => { 169 let host = args.TEST_OFFLINE_HOST; 170 let frameDoc = content.gSubDialog._topDialog._frame.contentDocument; 171 let sitesList = frameDoc.getElementById("sitesList"); 172 let site = sitesList.querySelector(`richlistitem[host="${host}"]`); 173 if (site) { 174 let removeBtn = frameDoc.getElementById("removeSelected"); 175 let saveBtn = frameDoc.querySelector("dialog").getButton("accept"); 176 site.click(); 177 removeBtn.doCommand(); 178 saveBtn.doCommand(); 179 } else { 180 ok(false, `Should have one site of ${host}`); 181 } 182 } 183 ); 184 await acceptRemovePromise; 185 await updatePromise; 186 await promiseServiceWorkersCleared(); 187 await SiteDataManager.removeAll(); 188 BrowserTestUtils.removeTab(gBrowser.selectedTab); 189 }); 190 191 // Test showing and removing sites with cookies. 192 add_task(async function test_manage_sites_with_cookies() { 193 // Add some test cookies. 194 let uri = Services.io.newURI("https://example.com"); 195 let uri2 = Services.io.newURI("https://example.org"); 196 let cv = Services.cookies.add( 197 uri.host, 198 uri.pathQueryRef, 199 "test1", 200 "1", 201 false, 202 false, 203 false, 204 Date.now() + 1000 * 60 * 60, 205 {}, 206 Ci.nsICookie.SAMESITE_UNSET, 207 Ci.nsICookie.SCHEME_HTTPS 208 ); 209 Assert.equal(cv.result, Ci.nsICookieValidation.eOK); 210 211 cv = Services.cookies.add( 212 uri.host, 213 uri.pathQueryRef, 214 "test2", 215 "2", 216 false, 217 false, 218 false, 219 Date.now() + 1000 * 60 * 60, 220 {}, 221 Ci.nsICookie.SAMESITE_UNSET, 222 Ci.nsICookie.SCHEME_HTTPS 223 ); 224 Assert.equal(cv.result, Ci.nsICookieValidation.eOK); 225 226 cv = Services.cookies.add( 227 uri2.host, 228 uri2.pathQueryRef, 229 "test1", 230 "1", 231 false, 232 false, 233 false, 234 Date.now() + 1000 * 60 * 60, 235 {}, 236 Ci.nsICookie.SAMESITE_UNSET, 237 Ci.nsICookie.SCHEME_HTTPS 238 ); 239 Assert.equal(cv.result, Ci.nsICookieValidation.eOK); 240 241 // Ensure that private browsing cookies are ignored. 242 cv = Services.cookies.add( 243 uri.host, 244 uri.pathQueryRef, 245 "test3", 246 "3", 247 false, 248 false, 249 false, 250 Date.now() + 1000 * 60 * 60, 251 { privateBrowsingId: 1 }, 252 Ci.nsICookie.SAMESITE_UNSET, 253 Ci.nsICookie.SCHEME_HTTPS 254 ); 255 Assert.equal(cv.result, Ci.nsICookieValidation.eOK); 256 257 // Get the exact creation date from the cookies (to avoid intermittents 258 // from minimal time differences, since we round up to minutes). 259 let cookies1 = Services.cookies.getCookiesFromHost(uri.host, {}); 260 let cookies2 = Services.cookies.getCookiesFromHost(uri2.host, {}); 261 // We made two valid cookies for example.com. 262 let cookie1 = cookies1[1]; 263 let cookie2 = cookies2[0]; 264 265 let fullFormatter = new Services.intl.DateTimeFormat(undefined, { 266 dateStyle: "short", 267 timeStyle: "short", 268 }); 269 270 await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); 271 272 // Open the site data manager and remove one site. 273 await openSiteDataSettingsDialog(); 274 let creationDate1 = new Date(cookie1.lastAccessed / 1000); 275 let creationDate1Formatted = fullFormatter.format(creationDate1); 276 let creationDate2 = new Date(cookie2.lastAccessed / 1000); 277 let creationDate2Formatted = fullFormatter.format(creationDate2); 278 let removeDialogOpenPromise = BrowserTestUtils.promiseAlertDialogOpen( 279 "accept", 280 REMOVE_DIALOG_URL 281 ); 282 await SpecialPowers.spawn( 283 gBrowser.selectedBrowser, 284 [ 285 { 286 creationDate1Formatted, 287 creationDate2Formatted, 288 }, 289 ], 290 function (args) { 291 let frameDoc = content.gSubDialog._topDialog._frame.contentDocument; 292 293 let siteItems = frameDoc.getElementsByTagName("richlistitem"); 294 is(siteItems.length, 2, "Should list two sites with cookies"); 295 let sitesList = frameDoc.getElementById("sitesList"); 296 let site1 = sitesList.querySelector(`richlistitem[host="example.com"]`); 297 let site2 = sitesList.querySelector(`richlistitem[host="example.org"]`); 298 299 let columns = site1.querySelectorAll(".item-box > label"); 300 let boxes = site1.querySelectorAll(".item-box"); 301 is(columns[0].value, "example.com", "Should show the correct host."); 302 is(columns[1].value, "2", "Should show the correct number of cookies."); 303 is(columns[2].value, "", "Should show no site data."); 304 is( 305 /(now|second)/.test(columns[3].value), 306 true, 307 "Should show the relative date." 308 ); 309 is( 310 boxes[3].getAttribute("tooltiptext"), 311 args.creationDate1Formatted, 312 "Should show the correct date." 313 ); 314 315 columns = site2.querySelectorAll(".item-box > label"); 316 boxes = site2.querySelectorAll(".item-box"); 317 is(columns[0].value, "example.org", "Should show the correct host."); 318 is(columns[1].value, "1", "Should show the correct number of cookies."); 319 is(columns[2].value, "", "Should show no site data."); 320 is( 321 /(now|second)/.test(columns[3].value), 322 true, 323 "Should show the relative date." 324 ); 325 is( 326 boxes[3].getAttribute("tooltiptext"), 327 args.creationDate2Formatted, 328 "Should show the correct date." 329 ); 330 331 let removeBtn = frameDoc.getElementById("removeSelected"); 332 let saveBtn = frameDoc.querySelector("dialog").getButton("accept"); 333 site2.click(); 334 removeBtn.doCommand(); 335 saveBtn.doCommand(); 336 } 337 ); 338 await removeDialogOpenPromise; 339 340 await TestUtils.waitForCondition( 341 () => Services.cookies.countCookiesFromHost(uri2.host) == 0, 342 "Cookies from the first host should be cleared" 343 ); 344 is( 345 Services.cookies.countCookiesFromHost(uri.host), 346 2, 347 "Cookies from the second host should not be cleared" 348 ); 349 350 // Open the site data manager and remove another site. 351 await openSiteDataSettingsDialog(); 352 let acceptRemovePromise = BrowserTestUtils.promiseAlertDialogOpen("accept"); 353 await SpecialPowers.spawn( 354 gBrowser.selectedBrowser, 355 [{ creationDate1Formatted }], 356 function (args) { 357 let frameDoc = content.gSubDialog._topDialog._frame.contentDocument; 358 359 let siteItems = frameDoc.getElementsByTagName("richlistitem"); 360 is(siteItems.length, 1, "Should list one site with cookies"); 361 let sitesList = frameDoc.getElementById("sitesList"); 362 let site1 = sitesList.querySelector(`richlistitem[host="example.com"]`); 363 364 let columns = site1.querySelectorAll(".item-box > label"); 365 let boxes = site1.querySelectorAll(".item-box"); 366 is(columns[0].value, "example.com", "Should show the correct host."); 367 is(columns[1].value, "2", "Should show the correct number of cookies."); 368 is(columns[2].value, "", "Should show no site data."); 369 is( 370 /(now|second)/.test(columns[3].value), 371 true, 372 "Should show the relative date." 373 ); 374 is( 375 boxes[3].getAttribute("tooltiptext"), 376 args.creationDate1Formatted, 377 "Should show the correct date." 378 ); 379 380 let removeBtn = frameDoc.getElementById("removeSelected"); 381 let saveBtn = frameDoc.querySelector("dialog").getButton("accept"); 382 site1.click(); 383 removeBtn.doCommand(); 384 saveBtn.doCommand(); 385 } 386 ); 387 await acceptRemovePromise; 388 389 await TestUtils.waitForCondition( 390 () => Services.cookies.countCookiesFromHost(uri.host) == 0, 391 "Cookies from the second host should be cleared" 392 ); 393 394 await openSiteDataSettingsDialog(); 395 396 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () { 397 let frameDoc = content.gSubDialog._topDialog._frame.contentDocument; 398 399 let siteItems = frameDoc.getElementsByTagName("richlistitem"); 400 is(siteItems.length, 0, "Should list no sites with cookies"); 401 }); 402 403 BrowserTestUtils.removeTab(gBrowser.selectedTab); 404 });