tor-browser

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

browser_privacy_status_card.js (14551B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * https://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const FEATURE_PREF = "browser.settings-redesign.enabled";
      7 const CARD_NAME = "security-privacy-card";
      8 const ISSUE_CONTROL_ID = "securityWarningsGroup";
      9 
     10 // Some things are set dangerously in the test environment.
     11 // We can supress these errors!
     12 const RESET_PROBLEMATIC_TEST_DEFAULTS = [
     13  [
     14    "browser.preferences.config_warning.warningAllowFingerprinters.dismissed",
     15    true,
     16  ],
     17  [
     18    "browser.preferences.config_warning.warningThirdPartyCookies.dismissed",
     19    true,
     20  ],
     21  ["browser.preferences.config_warning.warningPasswordManager.dismissed", true],
     22  ["browser.preferences.config_warning.warningPopupBlocker.dismissed", true],
     23  [
     24    "browser.preferences.config_warning.warningExtensionInstall.dismissed",
     25    true,
     26  ],
     27  ["browser.preferences.config_warning.warningSafeBrowsing.dismissed", true],
     28  ["browser.preferences.config_warning.warningDoH.dismissed", true],
     29  ["browser.preferences.config_warning.warningECH.dismissed", true],
     30  ["browser.preferences.config_warning.warningCT.dismissed", true],
     31  ["browser.preferences.config_warning.warningCRLite.dismissed", true],
     32  [
     33    "browser.preferences.config_warning.warningCertificatePinning.dismissed",
     34    true,
     35  ],
     36  ["browser.preferences.config_warning.warningTLSMin.dismissed", true],
     37  ["browser.preferences.config_warning.warningTLSMax.dismissed", true],
     38  [
     39    "browser.preferences.config_warning.warningProxyAutodetection.dismissed",
     40    true,
     41  ],
     42  [
     43    "browser.preferences.config_warning.warningContentResourceURI.dismissed",
     44    true,
     45  ],
     46  ["browser.preferences.config_warning.warningWorkerMIME.dismissed", true],
     47  ["browser.preferences.config_warning.warningTopLevelDataURI.dismissed", true],
     48  [
     49    "browser.preferences.config_warning.warningActiveMixedContent.dismissed",
     50    true,
     51  ],
     52  ["browser.preferences.config_warning.warningInnerHTMLltgt.dismissed", true],
     53  ["browser.preferences.config_warning.warningFileURIOrigin.dismissed", true],
     54  [
     55    "browser.preferences.config_warning.warningPrivelegedConstraint.dismissed",
     56    true,
     57  ],
     58  ["browser.preferences.config_warning.warningProcessSandbox.dismissed", true],
     59 ];
     60 
     61 function getCardAndCheckHeader(document, expectedHeaderL10n) {
     62  let elements = document.getElementsByTagName(CARD_NAME);
     63  Assert.equal(elements.length, 1, "Card present in preferences");
     64  let card = elements[0];
     65  let header = card.shadowRoot.getElementById("heading");
     66  Assert.equal(
     67    header.attributes.getNamedItem("data-l10n-id").value,
     68    expectedHeaderL10n
     69  );
     70  return card;
     71 }
     72 
     73 function assertHappyBullets(card) {
     74  let bullets = card.shadowRoot.querySelectorAll("li");
     75  Assert.equal(bullets.length, 2);
     76  for (const bullet of bullets) {
     77    Assert.equal(
     78      bullet.classList.contains("status-ok"),
     79      true,
     80      "All bullets must be happy!"
     81    );
     82  }
     83 }
     84 
     85 add_task(async function test_section_hidden_when_feature_flag_disabled() {
     86  await SpecialPowers.pushPrefEnv({
     87    set: [[FEATURE_PREF, false]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
     88  });
     89 
     90  await BrowserTestUtils.withNewTab(
     91    { gBrowser, url: "about:preferences#privacy" },
     92    async function (browser) {
     93      let elements = browser.contentDocument.getElementsByTagName(CARD_NAME);
     94      Assert.equal(elements.length, 0, "No card present in preferences");
     95    }
     96  );
     97 
     98  await SpecialPowers.popPrefEnv();
     99 });
    100 
    101 add_task(async function test_section_default_state() {
    102  await SpecialPowers.pushPrefEnv({
    103    set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    104  });
    105 
    106  await BrowserTestUtils.withNewTab(
    107    { gBrowser, url: "about:preferences#privacy" },
    108    async function (browser) {
    109      let card = getCardAndCheckHeader(
    110        browser.contentDocument,
    111        "security-privacy-status-ok-header"
    112      );
    113      assertHappyBullets(card);
    114      let strictLabel = card.shadowRoot.getElementById("strictEnabled");
    115      Assert.equal(strictLabel, null, "Strict mustn't be enabled");
    116    }
    117  );
    118 
    119  await SpecialPowers.popPrefEnv();
    120 });
    121 
    122 add_task(async function test_section_default_state() {
    123  await SpecialPowers.pushPrefEnv({
    124    set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    125  });
    126 
    127  await BrowserTestUtils.withNewTab(
    128    { gBrowser, url: "about:preferences#privacy" },
    129    async function (browser) {
    130      let card = getCardAndCheckHeader(
    131        browser.contentDocument,
    132        "security-privacy-status-ok-header"
    133      );
    134      assertHappyBullets(card);
    135      let strictLabel = card.shadowRoot.getElementById("strictEnabled");
    136      Assert.equal(strictLabel, null, "Strict mustn't be enabled");
    137    }
    138  );
    139 
    140  await SpecialPowers.popPrefEnv();
    141 });
    142 
    143 add_task(async function test_section_strict_indicator() {
    144  await SpecialPowers.pushPrefEnv({
    145    set: [
    146      [FEATURE_PREF, true],
    147      ["browser.contentblocking.category", "strict"],
    148    ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    149  });
    150 
    151  await BrowserTestUtils.withNewTab(
    152    { gBrowser, url: "about:preferences#privacy" },
    153    async function (browser) {
    154      let card = getCardAndCheckHeader(
    155        browser.contentDocument,
    156        "security-privacy-status-ok-header"
    157      );
    158      assertHappyBullets(card);
    159      let strictLabel = card.shadowRoot.getElementById("strictEnabled");
    160      Assert.notEqual(strictLabel, null, "Strict must be indicated");
    161    }
    162  );
    163 
    164  await SpecialPowers.popPrefEnv();
    165 });
    166 
    167 add_task(async function test_issue_present() {
    168  await SpecialPowers.pushPrefEnv({
    169    set: [
    170      [FEATURE_PREF, true],
    171      ["browser.contentblocking.category", "strict"],
    172      ["privacy.ui.status_card.testing.show_issue", true],
    173    ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    174  });
    175 
    176  await BrowserTestUtils.withNewTab(
    177    { gBrowser, url: "about:preferences#privacy" },
    178    async function (browser) {
    179      let card = getCardAndCheckHeader(
    180        browser.contentDocument,
    181        "security-privacy-status-problem-header"
    182      );
    183      let bulletIcons = card.shadowRoot.querySelectorAll("li");
    184      Assert.equal(bulletIcons.length, 2);
    185      let problemsBulletIcon = bulletIcons[0];
    186      Assert.ok(problemsBulletIcon.classList.contains("status-alert"));
    187      Assert.notEqual(
    188        problemsBulletIcon.querySelector("a"),
    189        null,
    190        "Link to issues is present"
    191      );
    192 
    193      // config card
    194      let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID);
    195      Assert.notEqual(configCard, null, "Issue card is present");
    196      let issues = configCard.listItems;
    197      Assert.equal(issues.length, 1, "One issue present");
    198    }
    199  );
    200 
    201  await SpecialPowers.popPrefEnv();
    202 });
    203 
    204 add_task(async function test_issue_fix() {
    205  await SpecialPowers.pushPrefEnv({
    206    set: [
    207      [FEATURE_PREF, true],
    208      ["privacy.ui.status_card.testing.show_issue", true],
    209    ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    210  });
    211  Services.fog.testResetFOG();
    212 
    213  await BrowserTestUtils.withNewTab(
    214    { gBrowser, url: "about:preferences#privacy" },
    215    async function (browser) {
    216      // config card
    217      let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID);
    218      Assert.notEqual(configCard, null, "Issue card is present");
    219      let issues = configCard.listItems;
    220      Assert.equal(issues.length, 1, "One issue present");
    221      let issue = issues[0];
    222      let fixButton = issue.querySelector(
    223        'moz-button[data-l10n-id="issue-card-reset-button"]'
    224      );
    225      let prefChange = TestUtils.waitForPrefChange(
    226        "privacy.ui.status_card.testing.show_issue"
    227      );
    228      fixButton.click();
    229      await prefChange;
    230      await configCard.updateComplete;
    231      let afterIssues = configCard.listItems;
    232      Assert.equal(
    233        afterIssues.length,
    234        0,
    235        "Issues are gone after the pref is fixed"
    236      );
    237      Assert.ok(
    238        !Services.prefs.prefHasUserValue(
    239          "privacy.ui.status_card.testing.show_issue"
    240        ),
    241        "Pref has no user value after clicking the fix button"
    242      );
    243      let events =
    244        Glean.securityPreferencesWarnings.warningFixed.testGetValue();
    245      Assert.equal(events.length, 1, "One telemetry event was recorded");
    246      Assert.equal(
    247        events[0].category,
    248        "security.preferences.warnings",
    249        "Category is correct"
    250      );
    251      Assert.equal(events[0].name, "warning_fixed", "Event name is correct");
    252 
    253      let warningsShownEvents =
    254        Glean.securityPreferencesWarnings.warningsShown.testGetValue();
    255      Assert.equal(
    256        warningsShownEvents.length,
    257        1,
    258        "warningsShown telemetry was recorded exactly once"
    259      );
    260      Assert.equal(
    261        warningsShownEvents[0].extra.count,
    262        "1",
    263        "Count of warnings shown is correct"
    264      );
    265    }
    266  );
    267 
    268  await SpecialPowers.popPrefEnv();
    269 });
    270 
    271 add_task(async function test_issue_dismiss() {
    272  await SpecialPowers.pushPrefEnv({
    273    set: [
    274      [FEATURE_PREF, true],
    275      ["privacy.ui.status_card.testing.show_issue", true],
    276    ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    277  });
    278  Services.fog.testResetFOG();
    279 
    280  await BrowserTestUtils.withNewTab(
    281    { gBrowser, url: "about:preferences#privacy" },
    282    async function (browser) {
    283      // config card
    284      let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID);
    285      Assert.notEqual(configCard, null, "Issue card is present");
    286      let issues = configCard.listItems;
    287      Assert.equal(issues.length, 1, "One issue present");
    288      let issue = issues[0];
    289      let dismissButton = issue.querySelector(
    290        'moz-button[data-l10n-id="issue-card-dismiss-button"]'
    291      );
    292      let prefChange = TestUtils.waitForPrefChange(
    293        "browser.preferences.config_warning.warningTest.dismissed"
    294      );
    295      dismissButton.click();
    296      await prefChange;
    297      await configCard.updateComplete;
    298      let afterIssues = configCard.listItems;
    299      Assert.equal(
    300        afterIssues.length,
    301        0,
    302        "Issues are gone after the setting is dismissed"
    303      );
    304      Assert.ok(
    305        Services.prefs.prefHasUserValue(
    306          "browser.preferences.config_warning.warningTest.dismissed"
    307        ),
    308        "Pref has no user value after clicking the fix button"
    309      );
    310      let events =
    311        Glean.securityPreferencesWarnings.warningDismissed.testGetValue();
    312      Assert.equal(events.length, 1, "One telemetry event was recorded");
    313      Assert.equal(
    314        events[0].category,
    315        "security.preferences.warnings",
    316        "Category is correct"
    317      );
    318      Assert.equal(
    319        events[0].name,
    320        "warning_dismissed",
    321        "Event name is correct"
    322      );
    323      let warningsShownEvents =
    324        Glean.securityPreferencesWarnings.warningsShown.testGetValue();
    325      Assert.equal(
    326        warningsShownEvents.length,
    327        1,
    328        "warningsShown telemetry was recorded exactly once"
    329      );
    330      Assert.equal(
    331        warningsShownEvents[0].extra.count,
    332        "1",
    333        "Count of warnings shown is correct"
    334      );
    335      Services.prefs.clearUserPref(
    336        "browser.preferences.config_warning.warningTest.dismissed"
    337      );
    338    }
    339  );
    340 
    341  await SpecialPowers.popPrefEnv();
    342 });
    343 
    344 add_task(async function test_dismiss_all_hides_issues() {
    345  await SpecialPowers.pushPrefEnv({
    346    set: [
    347      [FEATURE_PREF, true],
    348      ["privacy.ui.status_card.testing.show_issue", true],
    349      ["browser.preferences.config_warning.dismissAll", true],
    350    ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    351  });
    352 
    353  await BrowserTestUtils.withNewTab(
    354    { gBrowser, url: "about:preferences#privacy" },
    355    async function (browser) {
    356      let card = getCardAndCheckHeader(
    357        browser.contentDocument,
    358        "security-privacy-status-ok-header"
    359      );
    360      assertHappyBullets(card);
    361 
    362      let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID);
    363      Assert.ok(
    364        BrowserTestUtils.isHidden(configCard),
    365        "Issue card is not present when dismissAll is true"
    366      );
    367    }
    368  );
    369 
    370  await SpecialPowers.popPrefEnv();
    371 });
    372 
    373 add_task(async function test_update_status_indicator() {
    374  await SpecialPowers.pushPrefEnv({
    375    set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
    376  });
    377 
    378  // Define testers for each UI state.
    379  let absent = card => {
    380    let label = card.shadowRoot.querySelector("li:nth-child(3) p");
    381    Assert.equal(label, null, "No install status label is present");
    382  };
    383  let issue = card => {
    384    let label = card.shadowRoot.querySelector("li:nth-child(3) p");
    385    Assert.equal(
    386      label.attributes.getNamedItem("data-l10n-id").value,
    387      "security-privacy-status-update-error-label",
    388      "Label correctly identifies an issue"
    389    );
    390  };
    391  let needed = card => {
    392    let label = card.shadowRoot.querySelector("li:nth-child(3) p");
    393    Assert.equal(
    394      label.attributes.getNamedItem("data-l10n-id").value,
    395      "security-privacy-status-update-needed-label",
    396      "Label correctly identifies an update is needed"
    397    );
    398  };
    399  let ok = card => {
    400    let label = card.shadowRoot.querySelector("li:nth-child(3) p");
    401    Assert.equal(
    402      label.attributes.getNamedItem("data-l10n-id").value,
    403      "security-privacy-status-up-to-date-label",
    404      "Label correctly identifies software up to date"
    405    );
    406  };
    407  let checking = card => {
    408    let label = card.shadowRoot.querySelector("li:nth-child(3) p");
    409    Assert.equal(
    410      label.attributes.getNamedItem("data-l10n-id").value,
    411      "security-privacy-status-update-checking-label",
    412      "Label correctly identifies software update checking now"
    413    );
    414  };
    415 
    416  // Define the expected result for each different test case.
    417  // The keys are different AppUpdater.STATUS values.
    418  let cases = {};
    419  cases[0] = issue;
    420  cases[1] = absent;
    421  cases[2] = absent;
    422  cases[3] = absent;
    423  cases[4] = issue;
    424  cases[5] = needed;
    425  cases[6] = checking;
    426  cases[7] = ok;
    427  cases[8] = needed;
    428  cases[9] = issue;
    429  cases[10] = needed;
    430  cases[11] = needed;
    431  cases[12] = needed;
    432  cases[13] = issue;
    433  cases[14] = issue;
    434 
    435  await BrowserTestUtils.withNewTab(
    436    { gBrowser, url: "about:preferences#privacy" },
    437    async function (browser) {
    438      let elements = browser.contentDocument.getElementsByTagName(CARD_NAME);
    439      Assert.equal(elements.length, 1, "Card present in preferences");
    440      let card = elements[0];
    441      for (const status in cases) {
    442        info(`testing AppUpdateStatus ${status}`);
    443        card.appUpdateStatus = parseInt(status);
    444        await card.updateComplete;
    445        cases[status](card);
    446      }
    447    }
    448  );
    449 
    450  await SpecialPowers.popPrefEnv();
    451 });