tor-browser

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

browser_aboutNetError.js (10398B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const SSL3_PAGE = "https://ssl3.example.com/";
      7 const TLS10_PAGE = "https://tls1.example.com/";
      8 const TLS12_PAGE = "https://tls12.example.com/";
      9 const TRIPLEDES_PAGE = "https://3des.example.com/";
     10 
     11 const lazy = {};
     12 
     13 XPCOMUtils.defineLazyServiceGetter(
     14  lazy,
     15  "gDNSOverride",
     16  "@mozilla.org/network/native-dns-override;1",
     17  Ci.nsINativeDNSResolverOverride
     18 );
     19 
     20 // This includes all the cipher suite prefs we have.
     21 function resetPrefs() {
     22  Services.prefs.clearUserPref("security.tls.version.min");
     23  Services.prefs.clearUserPref("security.tls.version.max");
     24  Services.prefs.clearUserPref("security.tls.version.enable-deprecated");
     25  Services.prefs.clearUserPref("browser.fixup.alternate.enabled");
     26 }
     27 
     28 const SSL_ERROR_BASE = -0x3000;
     29 const SSL_ERROR_NO_CYPHER_OVERLAP = SSL_ERROR_BASE + 2;
     30 const SSL_ERROR_PROTOCOL_VERSION_ALERT = SSL_ERROR_BASE + 98;
     31 
     32 function nssErrorToNSErrorAsString(nssError) {
     33  let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"].getService(
     34    Ci.nsINSSErrorsService
     35  );
     36  return nssErrorsService.getXPCOMFromNSSError(nssError).toString();
     37 }
     38 
     39 async function resetTelemetry() {
     40  Services.telemetry.clearEvents();
     41  await TestUtils.waitForCondition(() => {
     42    let events = Services.telemetry.snapshotEvents(
     43      Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
     44      true
     45    ).content;
     46    return !events || !events.length;
     47  });
     48 }
     49 
     50 async function checkTelemetry(errorString, nssError) {
     51  let loadEvent = await TestUtils.waitForCondition(() => {
     52    let events = Services.telemetry.snapshotEvents(
     53      Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
     54      true
     55    ).content;
     56    return events?.find(e => e[1] == "security.ui.tlserror" && e[2] == "load");
     57  }, "recorded telemetry for the load");
     58  loadEvent.shift();
     59  Assert.deepEqual(loadEvent, [
     60    "security.ui.tlserror",
     61    "load",
     62    "abouttlserror",
     63    errorString,
     64    {
     65      is_frame: "false",
     66      channel_status: nssErrorToNSErrorAsString(nssError),
     67    },
     68  ]);
     69 }
     70 
     71 add_task(async function resetToDefaultConfig() {
     72  info(
     73    "Change TLS config to cause page load to fail, check that reset button is shown and that it works"
     74  );
     75 
     76  // Set ourselves up for a TLS error.
     77  Services.prefs.setIntPref("security.tls.version.min", 1); // TLS 1.0
     78  Services.prefs.setIntPref("security.tls.version.max", 1);
     79 
     80  await resetTelemetry();
     81 
     82  let browser;
     83  let pageLoaded;
     84  await BrowserTestUtils.openNewForegroundTab(
     85    gBrowser,
     86    () => {
     87      gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TLS12_PAGE);
     88      browser = gBrowser.selectedBrowser;
     89      pageLoaded = BrowserTestUtils.waitForErrorPage(browser);
     90    },
     91    false
     92  );
     93 
     94  info("Loading and waiting for the net error");
     95  await pageLoaded;
     96 
     97  await checkTelemetry(
     98    "SSL_ERROR_PROTOCOL_VERSION_ALERT",
     99    SSL_ERROR_PROTOCOL_VERSION_ALERT
    100  );
    101 
    102  // Setup an observer for the target page.
    103  const finalLoadComplete = BrowserTestUtils.browserLoaded(
    104    browser,
    105    false,
    106    TLS12_PAGE
    107  );
    108 
    109  await SpecialPowers.spawn(browser, [], async function () {
    110    const doc = content.document;
    111    ok(
    112      doc.documentURI.startsWith("about:neterror"),
    113      "Should be showing error page"
    114    );
    115 
    116    const prefResetButton = doc.getElementById("prefResetButton");
    117    await ContentTaskUtils.waitForCondition(
    118      () => ContentTaskUtils.isVisible(prefResetButton),
    119      "prefResetButton is visible"
    120    );
    121 
    122    if (!Services.focus.focusedElement == prefResetButton) {
    123      await ContentTaskUtils.waitForEvent(prefResetButton, "focus");
    124    }
    125 
    126    Assert.ok(true, "prefResetButton has focus");
    127 
    128    prefResetButton.click();
    129  });
    130 
    131  info("Waiting for the page to load after the click");
    132  await finalLoadComplete;
    133 
    134  resetPrefs();
    135  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    136 });
    137 
    138 add_task(async function checkLearnMoreLink() {
    139  info("Load an unsupported TLS page and check for a learn more link");
    140 
    141  // Set ourselves up for TLS error
    142  Services.prefs.setIntPref("security.tls.version.min", 3);
    143  Services.prefs.setIntPref("security.tls.version.max", 4);
    144 
    145  await resetTelemetry();
    146 
    147  let browser;
    148  let pageLoaded;
    149  await BrowserTestUtils.openNewForegroundTab(
    150    gBrowser,
    151    () => {
    152      gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TLS10_PAGE);
    153      browser = gBrowser.selectedBrowser;
    154      pageLoaded = BrowserTestUtils.waitForErrorPage(browser);
    155    },
    156    false
    157  );
    158 
    159  info("Loading and waiting for the net error");
    160  await pageLoaded;
    161 
    162  await checkTelemetry(
    163    "SSL_ERROR_PROTOCOL_VERSION_ALERT",
    164    SSL_ERROR_PROTOCOL_VERSION_ALERT
    165  );
    166 
    167  const baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
    168 
    169  await SpecialPowers.spawn(browser, [baseURL], function (_baseURL) {
    170    const doc = content.document;
    171    ok(
    172      doc.documentURI.startsWith("about:neterror"),
    173      "Should be showing error page"
    174    );
    175 
    176    const tlsVersionNotice = doc.getElementById("tlsVersionNotice");
    177    ok(
    178      ContentTaskUtils.isVisible(tlsVersionNotice),
    179      "TLS version notice is visible"
    180    );
    181 
    182    const learnMoreLink = doc.getElementById("learnMoreLink");
    183    ok(ContentTaskUtils.isVisible(learnMoreLink), "Learn More link is visible");
    184    is(learnMoreLink.getAttribute("href"), _baseURL + "connection-not-secure");
    185 
    186    const titleEl = doc.querySelector(".title-text");
    187    const actualDataL10nID = titleEl.getAttribute("data-l10n-id");
    188    is(
    189      actualDataL10nID,
    190      "nssFailure2-title",
    191      "Correct error page title is set"
    192    );
    193 
    194    const errorCodeEl = doc.querySelector("#errorShortDesc2");
    195    const actualDataL10Args = errorCodeEl.getAttribute("data-l10n-args");
    196    ok(
    197      actualDataL10Args.includes("SSL_ERROR_PROTOCOL_VERSION_ALERT"),
    198      "Correct error code is set"
    199    );
    200  });
    201 
    202  resetPrefs();
    203  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    204 });
    205 
    206 // When a user tries going to a host without a suffix
    207 // and the term doesn't match a host and we are able to suggest a
    208 // valid correction, the page should show the correction.
    209 // e.g. http://example/example2 -> https://www.example.com/example2
    210 add_task(async function checkDomainCorrection() {
    211  await SpecialPowers.pushPrefEnv({
    212    set: [["browser.fixup.alternate.enabled", false]],
    213  });
    214  lazy.gDNSOverride.addIPOverride("www.example.com", "::1");
    215 
    216  info("Try loading a URI that should result in an error page");
    217  BrowserTestUtils.openNewForegroundTab(
    218    gBrowser,
    219    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    220    "http://example/example2/",
    221    false
    222  );
    223 
    224  info("Loading and waiting for the net error");
    225  let browser = gBrowser.selectedBrowser;
    226  let pageLoaded = BrowserTestUtils.waitForErrorPage(browser);
    227  await pageLoaded;
    228 
    229  const baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
    230 
    231  await SpecialPowers.spawn(browser, [baseURL], async function (_baseURL) {
    232    const doc = content.document;
    233    ok(
    234      doc.documentURI.startsWith("about:neterror"),
    235      "Should be showing error page"
    236    );
    237 
    238    const errorNotice = doc.getElementById("errorShortDesc");
    239    ok(ContentTaskUtils.isVisible(errorNotice), "Error text is visible");
    240 
    241    // Wait for the domain suggestion to be resolved and for the text to update
    242    let link;
    243    await ContentTaskUtils.waitForCondition(() => {
    244      link = errorNotice.querySelector("a");
    245      return link && link.textContent != "";
    246    }, "Helper link has been set");
    247 
    248    is(
    249      link.getAttribute("href"),
    250      "https://www.example.com/example2/",
    251      "Link was corrected"
    252    );
    253 
    254    const actualDataL10nID = link.getAttribute("data-l10n-name");
    255    is(actualDataL10nID, "website", "Correct name is set");
    256  });
    257 
    258  lazy.gDNSOverride.clearHostOverride("www.example.com");
    259  resetPrefs();
    260  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    261 });
    262 
    263 // Test that ciphersuites that use 3DES (namely, TLS_RSA_WITH_3DES_EDE_CBC_SHA)
    264 // can only be enabled when deprecated TLS is enabled.
    265 add_task(async function onlyAllow3DESWithDeprecatedTLS() {
    266  await resetTelemetry();
    267 
    268  // By default, connecting to a server that only uses 3DES should fail.
    269  await BrowserTestUtils.withNewTab(
    270    { gBrowser, url: "about:blank" },
    271    async browser => {
    272      BrowserTestUtils.startLoadingURIString(browser, TRIPLEDES_PAGE);
    273      await BrowserTestUtils.waitForErrorPage(browser);
    274    }
    275  );
    276 
    277  await checkTelemetry(
    278    "SSL_ERROR_NO_CYPHER_OVERLAP",
    279    SSL_ERROR_NO_CYPHER_OVERLAP
    280  );
    281 
    282  // Enabling deprecated TLS should also enable 3DES.
    283  Services.prefs.setBoolPref("security.tls.version.enable-deprecated", true);
    284  await BrowserTestUtils.withNewTab(
    285    { gBrowser, url: "about:blank" },
    286    async browser => {
    287      BrowserTestUtils.startLoadingURIString(browser, TRIPLEDES_PAGE);
    288      await BrowserTestUtils.browserLoaded(browser, false, TRIPLEDES_PAGE);
    289    }
    290  );
    291 
    292  // 3DES can be disabled separately.
    293  Services.prefs.setBoolPref(
    294    "security.ssl3.deprecated.rsa_des_ede3_sha",
    295    false
    296  );
    297  await BrowserTestUtils.withNewTab(
    298    { gBrowser, url: "about:blank" },
    299    async browser => {
    300      BrowserTestUtils.startLoadingURIString(browser, TRIPLEDES_PAGE);
    301      await BrowserTestUtils.waitForErrorPage(browser);
    302      await SpecialPowers.spawn(browser, [], async function () {
    303        const doc = content.document;
    304        const netErrorCard =
    305          doc.querySelector("net-error-card")?.wrappedJSObject;
    306        Assert.ok(netErrorCard, "netErrorCard is rendered.");
    307 
    308        netErrorCard.advancedButton.scrollIntoView();
    309        EventUtils.synthesizeMouseAtCenter(
    310          netErrorCard.advancedButton,
    311          {},
    312          content
    313        );
    314        await ContentTaskUtils.waitForCondition(
    315          () => ContentTaskUtils.isVisible(netErrorCard.advancedContainer),
    316          "Advanced container is visible"
    317        );
    318 
    319        const prefResetButton = netErrorCard.prefResetButton;
    320        Assert.ok(prefResetButton, "prefResetButton exists in the DOM.");
    321        netErrorCard.prefResetButton.scrollIntoView();
    322        await ContentTaskUtils.waitForCondition(
    323          () => ContentTaskUtils.isVisible(netErrorCard.prefResetButton),
    324          "Pref reset button is visible"
    325        );
    326        ok(
    327          ContentTaskUtils.isVisible(prefResetButton),
    328          "prefResetButton is visible"
    329        );
    330      });
    331    }
    332  );
    333 
    334  resetPrefs();
    335 });