tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 });