tor-browser

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

browser_privacy_ipprotection.js (11897B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * https://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // This file tests the Privacy pane's Firefox VPN UI.
      5 
      6 "use strict";
      7 
      8 const FEATURE_PREF = "browser.ipProtection.enabled";
      9 const SITE_EXCEPTIONS_FEATURE_PREF =
     10  "browser.ipProtection.features.siteExceptions";
     11 const AUTOSTART_FEATURE_ENABLED_PREF =
     12  "browser.ipProtection.features.autoStart";
     13 const AUTOSTART_PREF = "browser.ipProtection.autoStartEnabled";
     14 const AUTOSTART_PRIVATE_PREF = "browser.ipProtection.autoStartPrivateEnabled";
     15 const ONBOARDING_MESSAGE_MASK_PREF =
     16  "browser.ipProtection.onboardingMessageMask";
     17 
     18 const SECTION_ID = "dataIPProtectionGroup";
     19 
     20 async function setupVpnPrefs({
     21  feature = false,
     22  siteExceptions = false,
     23  autostartFeatureEnabled = false,
     24  autostart = false,
     25  autostartprivate = false,
     26 }) {
     27  return SpecialPowers.pushPrefEnv({
     28    set: [
     29      [FEATURE_PREF, feature],
     30      [SITE_EXCEPTIONS_FEATURE_PREF, siteExceptions],
     31      [AUTOSTART_FEATURE_ENABLED_PREF, autostartFeatureEnabled],
     32      [AUTOSTART_PREF, autostart],
     33      [AUTOSTART_PRIVATE_PREF, autostartprivate],
     34    ],
     35  });
     36 }
     37 
     38 function testSettingsGroupVisible(browser, sectionId) {
     39  let section = browser.contentDocument.getElementById(sectionId);
     40  let settingGroup = section.querySelector(
     41    `setting-group[groupid="ipprotection"]`
     42  );
     43  is_element_visible(section, "#dataIPProtectionGroup is shown");
     44  is_element_visible(settingGroup, "ipprotection setting group is shown");
     45 
     46  return settingGroup;
     47 }
     48 
     49 // Test the section is hidden on page load if the feature pref is disabled.
     50 add_task(
     51  async function test_section_removed_when_set_to_ineligible_experiment_pref() {
     52    await setupVpnPrefs({ feature: false });
     53 
     54    await BrowserTestUtils.withNewTab(
     55      { gBrowser, url: "about:preferences#privacy" },
     56      async function (browser) {
     57        let section = browser.contentDocument.getElementById(SECTION_ID);
     58        is_element_hidden(section, "#dataIPProtectionGroup is hidden");
     59      }
     60    );
     61 
     62    await SpecialPowers.popPrefEnv();
     63  }
     64 );
     65 
     66 // Test the section is shown on page load if the feature pref is enabled
     67 add_task(
     68  async function test_section_shown_when_set_to_eligible_experiment_pref() {
     69    await setupVpnPrefs({ feature: true });
     70 
     71    await BrowserTestUtils.withNewTab(
     72      { gBrowser, url: "about:preferences#privacy" },
     73      async function (browser) {
     74        testSettingsGroupVisible(browser, SECTION_ID);
     75      }
     76    );
     77  }
     78 );
     79 
     80 // Test the site exceptions controls load correctly.
     81 add_task(async function test_exceptions_settings() {
     82  await setupVpnPrefs({ feature: true, siteExceptions: true });
     83 
     84  await BrowserTestUtils.withNewTab(
     85    { gBrowser, url: "about:preferences#privacy" },
     86    async function (browser) {
     87      let settingGroup = testSettingsGroupVisible(browser, SECTION_ID);
     88      let siteExceptionsGroup = settingGroup?.querySelector(
     89        "#ipProtectionExceptions"
     90      );
     91      is_element_visible(siteExceptionsGroup, "Site exceptions group is shown");
     92 
     93      let exceptionAllListButton = siteExceptionsGroup?.querySelector(
     94        "#ipProtectionExceptionAllListButton"
     95      );
     96      is_element_visible(
     97        exceptionAllListButton,
     98        "Button for list of exclusions is shown"
     99      );
    100    }
    101  );
    102 });
    103 
    104 // Test that we show the "Add" button in the site exceptions permission dialog
    105 // and correctly add site exclusions.
    106 add_task(async function test_exclusions_add_button() {
    107  const PERM_NAME = "ipp-vpn";
    108  await setupVpnPrefs({ feature: "beta", siteExceptions: true });
    109 
    110  await BrowserTestUtils.withNewTab(
    111    { gBrowser, url: "about:preferences#privacy" },
    112    async function (browser) {
    113      let settingGroup = testSettingsGroupVisible(browser, SECTION_ID);
    114      let siteExceptionsGroup = settingGroup?.querySelector(
    115        "#ipProtectionExceptions"
    116      );
    117      let exceptionAllListButton = siteExceptionsGroup?.querySelector(
    118        "#ipProtectionExceptionAllListButton"
    119      );
    120      is_element_visible(
    121        exceptionAllListButton,
    122        "Button for list of exclusions is shown"
    123      );
    124 
    125      // Clear ipp-vpn to start with 0 exclusions
    126      Services.perms.removeByType(PERM_NAME);
    127 
    128      // Let's load the dialog
    129      let promiseSubDialogLoaded = promiseLoadSubDialog(
    130        "chrome://browser/content/preferences/dialogs/permissions.xhtml"
    131      );
    132 
    133      exceptionAllListButton.click();
    134 
    135      const win = await promiseSubDialogLoaded;
    136 
    137      let addButton = win.document.getElementById("btnAdd");
    138      Assert.ok(addButton, "Add button exists");
    139      Assert.ok(BrowserTestUtils.isVisible(addButton), "Add button is visible");
    140      Assert.ok(addButton.disabled, "Add button is disabled");
    141 
    142      // Now let's click the Add button to add a new exclusion
    143      let permissionsBox = win.document.getElementById("permissionsBox");
    144      let siteListUpdatedPromise = BrowserTestUtils.waitForMutationCondition(
    145        permissionsBox,
    146        { subtree: true, childList: true },
    147        () => {
    148          return permissionsBox.children.length;
    149        }
    150      );
    151 
    152      // Set up a mock url input value
    153      let urlField = win.document.getElementById("url");
    154      Assert.ok(urlField, "Dialog url field exists");
    155      const site1 = "https://example.com";
    156      urlField.focus();
    157 
    158      EventUtils.sendString(site1, win);
    159      Assert.ok(!addButton.disabled, "Add button is enabled");
    160 
    161      addButton.click();
    162 
    163      await siteListUpdatedPromise;
    164 
    165      permissionsBox = win.document.getElementById("permissionsBox");
    166      Assert.equal(
    167        permissionsBox.children.length,
    168        1,
    169        "Should have 1 site listed as an exclusion"
    170      );
    171 
    172      let shownSite1 = permissionsBox.children[0];
    173      Assert.equal(
    174        shownSite1.getAttribute("origin"),
    175        site1,
    176        "Should match inputted site in the list of sites"
    177      );
    178 
    179      // Apply the changes
    180      let saveButton = win.document.querySelector("dialog").getButton("accept");
    181      Assert.ok(saveButton, "Save button is shown");
    182 
    183      saveButton.click();
    184 
    185      let exclusions = Services.perms.getAllByTypes([PERM_NAME]);
    186      Assert.equal(
    187        exclusions.length,
    188        1,
    189        "Should have 1 exclusion after pressing the Add button"
    190      );
    191      Assert.equal(
    192        exclusions[0]?.principal.siteOrigin,
    193        site1,
    194        "Should match the inputted site"
    195      );
    196 
    197      // Clean up
    198      Services.perms.removeByType(PERM_NAME);
    199      Services.prefs.clearUserPref(ONBOARDING_MESSAGE_MASK_PREF);
    200    }
    201  );
    202 });
    203 
    204 // Test that we show the correct number of site exclusions
    205 add_task(async function test_exclusions_count() {
    206  const PERM_NAME = "ipp-vpn";
    207  await setupVpnPrefs({ feature: "beta", siteExceptions: true });
    208 
    209  await BrowserTestUtils.withNewTab(
    210    { gBrowser, url: "about:preferences#privacy" },
    211    async function (browser) {
    212      let section = browser.contentDocument.getElementById(SECTION_ID);
    213      let settingGroup = section.querySelector(
    214        `setting-group[groupid="ipprotection"]`
    215      );
    216      is_element_visible(section, "#dataIPProtectionGroup is shown");
    217      is_element_visible(settingGroup, "ipprotection setting group is shown");
    218 
    219      let siteExceptionsGroup = settingGroup?.querySelector(
    220        "#ipProtectionExceptions"
    221      );
    222      is_element_visible(siteExceptionsGroup, "Site exceptions group is shown");
    223 
    224      let exceptionAllListButton = siteExceptionsGroup?.querySelector(
    225        "#ipProtectionExceptionAllListButton"
    226      );
    227      is_element_visible(
    228        exceptionAllListButton,
    229        "Button for list of exclusions is shown"
    230      );
    231 
    232      let sitesCountUpdatedPromise = BrowserTestUtils.waitForMutationCondition(
    233        exceptionAllListButton,
    234        { attributes: true, attributeFilter: ["data-l10n-args"] },
    235        () => {
    236          let args = exceptionAllListButton.getAttribute("data-l10n-args");
    237          return args && JSON.parse(args)?.count === 0;
    238        }
    239      );
    240 
    241      // Clear ipp-vpn to start with 0 exclusions
    242      Services.perms.removeByType(PERM_NAME);
    243 
    244      await sitesCountUpdatedPromise;
    245 
    246      Assert.ok(true, "Should show 0 exclusions initially");
    247 
    248      // Now test with 1 exclusion
    249      sitesCountUpdatedPromise = BrowserTestUtils.waitForMutationCondition(
    250        exceptionAllListButton,
    251        { attributes: true, attributeFilter: ["data-l10n-args"] },
    252        () => {
    253          let args = exceptionAllListButton.getAttribute("data-l10n-args");
    254          return args && JSON.parse(args)?.count === 1;
    255        }
    256      );
    257      let site1 = "https://example.com";
    258      let principal1 =
    259        Services.scriptSecurityManager.createContentPrincipalFromOrigin(site1);
    260      Services.perms.addFromPrincipal(
    261        principal1,
    262        PERM_NAME,
    263        Services.perms.DENY_ACTION
    264      );
    265 
    266      await sitesCountUpdatedPromise;
    267 
    268      Assert.ok(true, "Should show 1 exclusion after adding the first site");
    269 
    270      // Now test with 2 exclusions
    271      sitesCountUpdatedPromise = BrowserTestUtils.waitForMutationCondition(
    272        exceptionAllListButton,
    273        { attributes: true, attributeFilter: ["data-l10n-args"] },
    274        () => {
    275          let args = exceptionAllListButton.getAttribute("data-l10n-args");
    276          return args && JSON.parse(args)?.count === 2;
    277        }
    278      );
    279      let site2 = "https://example.org";
    280      let principal2 =
    281        Services.scriptSecurityManager.createContentPrincipalFromOrigin(site2);
    282      Services.perms.addFromPrincipal(
    283        principal2,
    284        PERM_NAME,
    285        Services.perms.DENY_ACTION
    286      );
    287 
    288      await sitesCountUpdatedPromise;
    289 
    290      Assert.ok(true, "Should show 2 exclusions after adding the second site");
    291 
    292      // Clean up
    293      Services.perms.removeByType(PERM_NAME);
    294      Services.prefs.clearUserPref(ONBOARDING_MESSAGE_MASK_PREF);
    295    }
    296  );
    297 });
    298 
    299 // Test that autostart checkboxes exist and map to the correct preferences
    300 add_task(async function test_autostart_checkboxes() {
    301  await setupVpnPrefs({
    302    feature: true,
    303    autostartFeatureEnabled: true,
    304    autostart: true,
    305    autostartprivate: true,
    306  });
    307 
    308  await BrowserTestUtils.withNewTab(
    309    { gBrowser, url: "about:preferences#privacy" },
    310    async function (browser) {
    311      let settingGroup = testSettingsGroupVisible(browser, SECTION_ID);
    312      let autoStartSettings = settingGroup?.querySelector(
    313        "#ipProtectionAutoStart"
    314      );
    315      is_element_visible(
    316        autoStartSettings,
    317        "autoStart settings group is shown"
    318      );
    319 
    320      let autoStartCheckbox = autoStartSettings?.querySelector(
    321        "#ipProtectionAutoStartCheckbox"
    322      );
    323      let autoStartPrivateCheckbox = autoStartSettings?.querySelector(
    324        "#ipProtectionAutoStartPrivateCheckbox"
    325      );
    326 
    327      Assert.ok(
    328        autoStartCheckbox.checked,
    329        "Autostart checkbox should be checked"
    330      );
    331      Assert.ok(
    332        autoStartPrivateCheckbox.checked,
    333        "Autostart in private browsing checkbox should be checked"
    334      );
    335    }
    336  );
    337 });
    338 
    339 // Test that additional links exist
    340 add_task(async function test_additional_links() {
    341  await setupVpnPrefs({
    342    feature: true,
    343  });
    344 
    345  await BrowserTestUtils.withNewTab(
    346    { gBrowser, url: "about:preferences#privacy" },
    347    async function (browser) {
    348      let settingGroup = testSettingsGroupVisible(browser, SECTION_ID);
    349      let additionalLinks = settingGroup?.querySelector(
    350        "#ipProtectionAdditionalLinks"
    351      );
    352      is_element_visible(additionalLinks, "Additional links section is shown");
    353 
    354      let ipProtectionSupportLink = additionalLinks?.querySelector(
    355        "#ipProtectionSupportLink"
    356      );
    357      let ipProtectionUpgradeLink = additionalLinks?.querySelector(
    358        "#ipProtectionUpgradeLink"
    359      );
    360      is_element_visible(ipProtectionSupportLink, "Support link is shown");
    361      is_element_visible(ipProtectionUpgradeLink, "Upgrade link is shown");
    362    }
    363  );
    364 });