tor-browser

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

browser_https_telemetry.js (15773B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // We explicitly need HTTP URLs in this test
      7 /* eslint-disable @microsoft/sdl/no-insecure-url */
      8 
      9 requestLongerTimeout(3);
     10 
     11 ChromeUtils.defineLazyGetter(this, "UrlbarTestUtils", () => {
     12  const { UrlbarTestUtils: module } = ChromeUtils.importESModule(
     13    "resource://testing-common/UrlbarTestUtils.sys.mjs"
     14  );
     15  module.init(this);
     16  return module;
     17 });
     18 
     19 const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace(
     20  "chrome://mochitests/content",
     21  "http://example.com"
     22 );
     23 const TEST_PATH_HTTPS = getRootDirectory(gTestPath).replace(
     24  "chrome://mochitests/content",
     25  "https://example.com"
     26 );
     27 const TEST_PATH_SCHEMELESS = getRootDirectory(gTestPath).replace(
     28  "chrome://mochitests/content",
     29  "example.com"
     30 );
     31 
     32 const HSTS_SITE = TEST_PATH_HTTPS + "file_https_telemetry_hsts.sjs";
     33 
     34 const NO_HTTPS_SUPPORT_SITE = TEST_PATH_HTTP + "file_no_https_support.sjs";
     35 const NO_HTTPS_SUPPORT_SITE_SCHEMELESS =
     36  TEST_PATH_SCHEMELESS + "file_no_https_support.sjs";
     37 
     38 async function setPrefsAndResetFog(
     39  aHTTPSOnlyPref,
     40  aHTTPSFirstPref,
     41  aSchemeLessPref
     42 ) {
     43  Services.fog.testResetFOG();
     44 
     45  await SpecialPowers.pushPrefEnv({
     46    set: [
     47      ["dom.security.https_only_mode", aHTTPSOnlyPref],
     48      ["dom.security.https_first", aHTTPSFirstPref],
     49      ["dom.security.https_first_schemeless", aSchemeLessPref],
     50    ],
     51  });
     52 }
     53 
     54 function verifyGleanValues(aDescription, aExpected) {
     55  info(aDescription);
     56 
     57  let notInitialized = aExpected.notInitialized || null;
     58  let noUpgrade = aExpected.noUpgrade || null;
     59  let alreadyHTTPS = aExpected.alreadyHTTPS || null;
     60  let hsts = aExpected.hsts || null;
     61  let httpsOnlyUpgrade = aExpected.httpsOnlyUpgrade || null;
     62  let httpsOnlyUpgradeDowngrade = aExpected.httpsOnlyUpgradeDowngrade || null;
     63  let httpsFirstUpgrade = aExpected.httpsFirstUpgrade || null;
     64  let httpsFirstUpgradeDowngrade = aExpected.httpsFirstUpgradeDowngrade || null;
     65  let httpsFirstSchemelessUpgrade =
     66    aExpected.httpsFirstSchemelessUpgrade || null;
     67  let httpsFirstSchemelessUpgradeDowngrade =
     68    aExpected.httpsFirstSchemelessUpgradeDowngrade || null;
     69  let cspUpgradeInsecureRequests = aExpected.cspUpgradeInsecureRequests || null;
     70  let httpsRR = aExpected.httpsRR || null;
     71  let webExtensionUpgrade = aExpected.webExtensionUpgrade || null;
     72  let upgradeException = aExpected.upgradeException || null;
     73 
     74  let glean = Glean.networking.httpToHttpsUpgradeReason;
     75  is(
     76    glean.not_initialized.testGetValue(),
     77    notInitialized,
     78    "verify not_initialized"
     79  );
     80  is(glean.no_upgrade.testGetValue(), noUpgrade, "verify no_upgrade");
     81  is(glean.already_https.testGetValue(), alreadyHTTPS, "verify already_https");
     82  is(glean.hsts.testGetValue(), hsts, "verify hsts");
     83  is(
     84    glean.https_only_upgrade.testGetValue(),
     85    httpsOnlyUpgrade,
     86    "verify https_only_upgrade"
     87  );
     88  is(
     89    glean.https_only_upgrade_downgrade.testGetValue(),
     90    httpsOnlyUpgradeDowngrade,
     91    "verify https_only_upgrade_downgrade"
     92  );
     93  is(
     94    glean.https_first_upgrade.testGetValue(),
     95    httpsFirstUpgrade,
     96    "verify https_first_upgrade"
     97  );
     98  is(
     99    glean.https_first_upgrade_downgrade.testGetValue(),
    100    httpsFirstUpgradeDowngrade,
    101    "verify https_first_upgrade_downgrade"
    102  );
    103  is(
    104    glean.https_first_schemeless_upgrade.testGetValue(),
    105    httpsFirstSchemelessUpgrade,
    106    "verify https_first_schemeless_upgrade"
    107  );
    108  is(
    109    glean.https_first_schemeless_upgrade_downgrade.testGetValue(),
    110    httpsFirstSchemelessUpgradeDowngrade,
    111    "verify https_first_schemeless_upgrade_downgrade"
    112  );
    113  is(
    114    glean.csp_uir.testGetValue(),
    115    cspUpgradeInsecureRequests,
    116    "verify csp_uir"
    117  );
    118  is(glean.https_rr.testGetValue(), httpsRR, "verify https_rr");
    119  is(
    120    glean.web_extension_upgrade.testGetValue(),
    121    webExtensionUpgrade,
    122    "verify web_extension_upgrade"
    123  );
    124  is(
    125    glean.upgrade_exception.testGetValue(),
    126    upgradeException,
    127    "verify upgrade_exception"
    128  );
    129 }
    130 
    131 async function runUpgradeTest(aURI, aDesc, aAssertURLStartsWith) {
    132  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    133    const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
    134    BrowserTestUtils.startLoadingURIString(browser, aURI);
    135    await loaded;
    136 
    137    await SpecialPowers.spawn(
    138      browser,
    139      [aDesc, aAssertURLStartsWith],
    140      async function (aDesc, aAssertURLStartsWith) {
    141        ok(
    142          content.document.location.href.startsWith(aAssertURLStartsWith),
    143          aDesc
    144        );
    145      }
    146    );
    147    await SpecialPowers.removePermission("https-only-load-insecure", aURI);
    148  });
    149 }
    150 
    151 async function runSchemelessTest(aURI, aDesc, aAssertURLStartsWith) {
    152  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    153    const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
    154    await UrlbarTestUtils.promiseAutocompleteResultPopup({
    155      window,
    156      value: aURI,
    157    });
    158    EventUtils.synthesizeKey("KEY_Enter", { ctrlKey: true });
    159    await loaded;
    160    await SpecialPowers.spawn(
    161      browser,
    162      [aDesc, aAssertURLStartsWith],
    163      async function (aDesc, aAssertURLStartsWith) {
    164        ok(
    165          content.document.location.href.startsWith(aAssertURLStartsWith),
    166          aDesc
    167        );
    168      }
    169    );
    170    // we can't pass a schemeless uri to removePermission
    171    let uri = "https://" + aURI;
    172    await SpecialPowers.removePermission("https-only-load-insecure", uri);
    173  });
    174 }
    175 
    176 add_task(async function () {
    177  info("(0) exempt loopback addresses");
    178 
    179  await setPrefsAndResetFog(
    180    false /* aHTTPSOnlyPref */,
    181    false /* aHTTPSFirstPref */,
    182    false /* aSchemeLessPref */
    183  );
    184 
    185  // the request to localhost will actually fail in our test infra,
    186  // though the telemetry would be recorded.
    187  await runUpgradeTest(
    188    "https://localhost",
    189    "(0) exempt loopback addresses",
    190    "https://"
    191  );
    192  verifyGleanValues("(0) exempt loopback addresses", {});
    193 });
    194 
    195 add_task(async function () {
    196  info("(1) no upgrade test");
    197 
    198  await setPrefsAndResetFog(
    199    false /* aHTTPSOnlyPref */,
    200    false /* aHTTPSFirstPref */,
    201    false /* aSchemeLessPref */
    202  );
    203 
    204  await runUpgradeTest(
    205    "http://example.com?test1",
    206    "(1) no upgrade test",
    207    "http://"
    208  );
    209  verifyGleanValues("(1) no upgrade test", { noUpgrade: 1 });
    210 });
    211 
    212 add_task(async function () {
    213  info("(2) already https test");
    214 
    215  await setPrefsAndResetFog(
    216    false /* aHTTPSOnlyPref */,
    217    false /* aHTTPSFirstPref */,
    218    false /* aSchemeLessPref */
    219  );
    220 
    221  await runUpgradeTest(
    222    "https://example.com?test2",
    223    "(2) already https test",
    224    "https://"
    225  );
    226 
    227  verifyGleanValues("(2) already https test", { alreadyHTTPS: 1 });
    228 });
    229 
    230 add_task(async function () {
    231  info("(2b) already https test all prefs true");
    232 
    233  await setPrefsAndResetFog(
    234    true /* aHTTPSOnlyPref */,
    235    true /* aHTTPSFirstPref */,
    236    true /* aSchemeLessPref */
    237  );
    238 
    239  await runUpgradeTest(
    240    "https://example.com?test2b",
    241    "(2b) already https test all prefs true",
    242    "https://"
    243  );
    244 
    245  verifyGleanValues("(2b) already https test all prefs true", {
    246    alreadyHTTPS: 1,
    247  });
    248 });
    249 
    250 add_task(async function () {
    251  info("(3) hsts");
    252 
    253  await setPrefsAndResetFog(
    254    false /* aHTTPSOnlyPref */,
    255    false /* aHTTPSFirstPref */,
    256    false /* aSchemeLessPref */
    257  );
    258 
    259  // we need to setup hsts first
    260  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    261    const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
    262    BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE);
    263    await loaded;
    264  });
    265 
    266  // now we reset glean again
    267  Services.fog.testResetFOG();
    268 
    269  await runUpgradeTest("http://example.com?test3", "(3) hsts", "https://");
    270 
    271  verifyGleanValues("(3) hsts", { hsts: 1 });
    272 
    273  // finally we need to reset hsts
    274  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    275    const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
    276    BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE + "?reset");
    277    await loaded;
    278  });
    279 
    280  info("(3b) hsts with all prefs true");
    281 
    282  await setPrefsAndResetFog(
    283    true /* aHTTPSOnlyPref */,
    284    true /* aHTTPSFirstPref */,
    285    true /* aSchemeLessPref */
    286  );
    287 
    288  // we need to setup hsts first
    289  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    290    const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
    291    BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE);
    292    await loaded;
    293  });
    294 
    295  // now we reset glean again
    296  Services.fog.testResetFOG();
    297 
    298  await runUpgradeTest(
    299    "http://example.com?test3b",
    300    "(3b) hsts with all prefs true",
    301    "https://"
    302  );
    303 
    304  verifyGleanValues("(3b) hsts with all prefs true", { hsts: 1 });
    305 
    306  // finally we need to reset the hsts host
    307  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    308    const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
    309    BrowserTestUtils.startLoadingURIString(browser, HSTS_SITE + "?reset");
    310    await loaded;
    311  });
    312 });
    313 
    314 add_task(async function () {
    315  info("(4) https-only upgrade");
    316 
    317  await setPrefsAndResetFog(
    318    true /* aHTTPSOnlyPref */,
    319    false /* aHTTPSFirstPref */,
    320    false /* aSchemeLessPref */
    321  );
    322 
    323  await runUpgradeTest(
    324    "http://example.com?test4",
    325    "(4) https-only upgrade",
    326    "https://"
    327  );
    328 
    329  verifyGleanValues("(4) https-only upgrade", { httpsOnlyUpgrade: 1 });
    330 
    331  info("(4b) https-only upgrade downgrade");
    332 
    333  await setPrefsAndResetFog(
    334    true /* aHTTPSOnlyPref */,
    335    false /* aHTTPSFirstPref */,
    336    false /* aSchemeLessPref */
    337  );
    338 
    339  // We specifically want a insecure url here that will fail to upgrade
    340  let uri = "http://untrusted.example.com:80";
    341  let desc = "(4b) https-only upgrade downgrade";
    342  let assertErrorPageStartsWith = "https://";
    343  let assertDowngradedURLStartsWith = "http://";
    344 
    345  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    346    const loaded = BrowserTestUtils.waitForErrorPage(browser);
    347    BrowserTestUtils.startLoadingURIString(browser, uri);
    348    await loaded;
    349 
    350    await SpecialPowers.spawn(
    351      browser,
    352      [desc, assertErrorPageStartsWith],
    353      async function (desc, assertErrorPageStartsWith) {
    354        ok(
    355          content.document.location.href.startsWith(assertErrorPageStartsWith),
    356          desc
    357        );
    358      }
    359    );
    360 
    361    const downGradeLoaded = BrowserTestUtils.browserLoaded(
    362      browser,
    363      false,
    364      null,
    365      true
    366    );
    367 
    368    // click the 'continue to insecure page' button
    369    await SpecialPowers.spawn(browser, [], async function () {
    370      let openInsecureButton = content.document.getElementById("openInsecure");
    371      Assert.notEqual(
    372        openInsecureButton,
    373        null,
    374        "openInsecureButton should exist."
    375      );
    376      info("Waiting for openInsecureButton to be enabled.");
    377      function callback() {
    378        if (!openInsecureButton.classList.contains("disabled")) {
    379          observer.disconnect();
    380          content.requestAnimationFrame(() => {
    381            content.requestAnimationFrame(() => {
    382              openInsecureButton.click();
    383            });
    384          });
    385        }
    386      }
    387      const observer = new content.MutationObserver(callback);
    388      observer.observe(openInsecureButton, { attributeFilter: ["class"] });
    389      callback();
    390    });
    391 
    392    await downGradeLoaded;
    393 
    394    await SpecialPowers.spawn(
    395      browser,
    396      [desc, assertDowngradedURLStartsWith],
    397      async function (desc, assertDowngradedURLStartsWith) {
    398        ok(
    399          content.document.location.href.startsWith(
    400            assertDowngradedURLStartsWith
    401          ),
    402          desc
    403        );
    404      }
    405    );
    406    await SpecialPowers.removePermission("https-only-load-insecure", uri);
    407  });
    408 
    409  verifyGleanValues("(4b) https-only upgrade downgrade", {
    410    httpsOnlyUpgrade: 1,
    411    httpsOnlyUpgradeDowngrade: 1,
    412  });
    413 });
    414 
    415 add_task(async function () {
    416  info("(5) https-first upgrade");
    417 
    418  await setPrefsAndResetFog(
    419    false /* aHTTPSOnlyPref */,
    420    true /* aHTTPSFirstPref */,
    421    false /* aSchemeLessPref */
    422  );
    423 
    424  await runUpgradeTest(
    425    "http://example.com?test5",
    426    "(5) https-first upgrade",
    427    "https://"
    428  );
    429 
    430  verifyGleanValues("(5) https-first upgrade", { httpsFirstUpgrade: 1 });
    431 
    432  info("(5b) https-first upgrade downgrade");
    433 
    434  await setPrefsAndResetFog(
    435    false /* aHTTPSOnlyPref */,
    436    true /* aHTTPSFirstPref */,
    437    false /* aSchemeLessPref */
    438  );
    439 
    440  await runUpgradeTest(
    441    NO_HTTPS_SUPPORT_SITE + "?test5b",
    442    "(5b) https-first upgrade downgrade",
    443    "http://"
    444  );
    445 
    446  verifyGleanValues("(5) https-first upgrade", {
    447    httpsFirstUpgrade: 1,
    448    httpsFirstUpgradeDowngrade: 1,
    449  });
    450 });
    451 
    452 add_task(async function () {
    453  info("(6) schemeless https-first upgrade");
    454 
    455  await setPrefsAndResetFog(
    456    false /* aHTTPSOnlyPref */,
    457    false /* aHTTPSFirstPref */,
    458    true /* aSchemeLessPref */
    459  );
    460 
    461  await runSchemelessTest(
    462    "example.com?test6",
    463    "(6) schemeless https-first upgrade",
    464    "https://"
    465  );
    466 
    467  verifyGleanValues("(6) schemeless https-first upgrade", {
    468    httpsFirstSchemelessUpgrade: 1,
    469  });
    470 
    471  info("(6b) schemeless https-first upgrade downgrade");
    472 
    473  await setPrefsAndResetFog(
    474    false /* aHTTPSOnlyPref */,
    475    false /* aHTTPSFirstPref */,
    476    true /* aSchemeLessPref */
    477  );
    478 
    479  await runSchemelessTest(
    480    NO_HTTPS_SUPPORT_SITE_SCHEMELESS + "?test6b",
    481    "(6) schemeless https-first upgrade downgrade",
    482    "http://"
    483  );
    484 
    485  verifyGleanValues("(6b) schemeless https-first upgrade downgrade", {
    486    httpsFirstSchemelessUpgrade: 1,
    487    httpsFirstSchemelessUpgradeDowngrade: 1,
    488  });
    489 });
    490 
    491 add_task(async function () {
    492  info("(7) https-rr upgrade");
    493 
    494  Services.fog.testResetFOG();
    495 
    496  await SpecialPowers.pushPrefEnv({
    497    set: [
    498      ["dom.security.https_only_mode", false],
    499      ["dom.security.https_first", false],
    500      ["dom.security.https_first_schemeless", false],
    501      ["network.dns.force_use_https_rr", true],
    502      ["network.dns.mock_HTTPS_RR_domain", "example.org"],
    503    ],
    504  });
    505 
    506  await runUpgradeTest(
    507    "http://example.org",
    508    "(7) https-rr upgrade",
    509    "https://"
    510  );
    511 
    512  verifyGleanValues("(7) https-rr upgrade", { httpsRR: 1 });
    513 });
    514 
    515 add_task(async function () {
    516  info("(8) upgrade/downgrade/reload");
    517  // This test performs an upgrade-downgrade and then reloads
    518  // the document which then triggers an upgrade_exception.
    519 
    520  await setPrefsAndResetFog(
    521    false /* aHTTPSOnlyPref */,
    522    true /* aHTTPSFirstPref */,
    523    false /* aSchemeLessPref */
    524  );
    525 
    526  await BrowserTestUtils.withNewTab("about:blank", async function (browser) {
    527    // First, perform the upgrade/downgrade
    528    const upgradeDowngradeLoaded = BrowserTestUtils.browserLoaded(
    529      browser,
    530      false,
    531      null,
    532      true
    533    );
    534    BrowserTestUtils.startLoadingURIString(
    535      browser,
    536      NO_HTTPS_SUPPORT_SITE + "?test8"
    537    );
    538    await upgradeDowngradeLoaded;
    539 
    540    await SpecialPowers.spawn(browser, [], async function () {
    541      ok(
    542        content.document.location.href.startsWith("http://"),
    543        "(8) upgrade/downgrade/reload"
    544      );
    545    });
    546 
    547    // Before reloading the doc we have to reset the fog
    548    Services.fog.testResetFOG();
    549 
    550    const reloadLoaded = BrowserTestUtils.browserLoaded(
    551      browser,
    552      false,
    553      null,
    554      true
    555    );
    556 
    557    await SpecialPowers.spawn(browser, [], async function () {
    558      content.location.reload();
    559    });
    560 
    561    await reloadLoaded;
    562 
    563    await SpecialPowers.spawn(browser, [], async function () {
    564      ok(
    565        content.document.location.href.startsWith("http://"),
    566        "(8) upgrade/downgrade/reload"
    567      );
    568    });
    569  });
    570 
    571  verifyGleanValues("(8) upgrade/downgrade/reload", { upgradeException: 1 });
    572 });