tor-browser

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

browser_aboutCertError_telemetry.js (6928B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 requestLongerTimeout(4);
      7 
      8 const BAD_CERT = "https://expired.example.com/";
      9 const BAD_STS_CERT =
     10  "https://badchain.include-subdomains.pinning.example.com:443";
     11 
     12 async function checkTelemetryClickEvents(useFelt) {
     13  info("Loading a bad cert page and verifying telemetry click events arrive.");
     14  await SpecialPowers.pushPrefEnv({
     15    set: [["security.certerrors.felt-privacy-v1", useFelt]],
     16  });
     17 
     18  let oldCanRecord = Services.telemetry.canRecordExtended;
     19  Services.telemetry.canRecordExtended = true;
     20 
     21  registerCleanupFunction(() => {
     22    Services.telemetry.canRecordExtended = oldCanRecord;
     23  });
     24 
     25  // For obvious reasons event telemetry in the content processes updates with
     26  // the main processs asynchronously, so we need to wait for the main process
     27  // to catch up through the entire test.
     28 
     29  // There's an arbitrary interval of 2 seconds in which the content
     30  // processes sync their event data with the parent process, we wait
     31  // this out to ensure that we clear everything that is left over from
     32  // previous tests and don't receive random events in the middle of our tests.
     33  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
     34  await new Promise(c => setTimeout(c, 2000));
     35 
     36  // Clear everything.
     37  Services.telemetry.clearEvents();
     38  await TestUtils.waitForCondition(() => {
     39    let events = Services.telemetry.snapshotEvents(
     40      Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
     41      true
     42    ).content;
     43    return !events || !events.length;
     44  });
     45 
     46  for (let useFrame of [false, true]) {
     47    let recordedObjects = [
     48      "advanced_button",
     49      "learn_more_link",
     50      "error_code_link",
     51      "clipboard_button_top",
     52      "clipboard_button_bot",
     53    ];
     54 
     55    const mapRecordObjectsFelt = {
     56      advanced_button: "advancedButton",
     57      learn_more_link: "learnMoreLink",
     58      error_code_link: "errorCode",
     59      clipboard_button_top: "copyButtonTop",
     60      clipboard_button_bot: "copyButtonBot",
     61      return_button_adv: "returnButton",
     62      exception_button: "exceptionButton",
     63    };
     64 
     65    recordedObjects.push("return_button_adv");
     66    if (!useFrame) {
     67      recordedObjects.push("exception_button");
     68    }
     69    if (!useFelt) {
     70      recordedObjects.push("return_button_top");
     71    }
     72 
     73    for (let object of recordedObjects) {
     74      let tab = await openErrorPage(BAD_CERT, useFrame);
     75      let browser = tab.linkedBrowser;
     76 
     77      let loadEvents = await TestUtils.waitForCondition(() => {
     78        let events = Services.telemetry.snapshotEvents(
     79          Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
     80          true
     81        ).content;
     82        if (events && events.length) {
     83          events = events.filter(
     84            e => e[1] == "security.ui.certerror" && e[2] == "load"
     85          );
     86          if (
     87            events.length == 1 &&
     88            events[0][5].is_frame == useFrame.toString()
     89          ) {
     90            return events;
     91          }
     92        }
     93        return null;
     94      }, "recorded telemetry for the load");
     95 
     96      is(
     97        loadEvents.length,
     98        1,
     99        `recorded telemetry for the load testing ${object}, useFrame: ${useFrame}`
    100      );
    101 
    102      let bc = browser.browsingContext;
    103      if (useFrame) {
    104        bc = bc.children[0];
    105      }
    106 
    107      await SpecialPowers.spawn(
    108        bc,
    109        [object, useFelt, mapRecordObjectsFelt],
    110        async function (objectId, use_felt, mapFelt) {
    111          let doc = content.document;
    112 
    113          if (use_felt) {
    114            const netErrorCard =
    115              doc.querySelector("net-error-card").wrappedJSObject;
    116            const advancedButton = netErrorCard.advancedButton;
    117            if (
    118              !netErrorCard.advancedContainer &&
    119              objectId !== "advanced_button"
    120            ) {
    121              advancedButton.scrollIntoView(true);
    122              EventUtils.synthesizeMouseAtCenter(advancedButton, {}, content);
    123 
    124              await ContentTaskUtils.waitForCondition(
    125                () => netErrorCard.advancedContainer,
    126                "Advanced section should be rendered for revoked certificate"
    127              );
    128            }
    129            if (
    130              ["clipboard_button_top", "clipboard_button_bot"].includes(
    131                objectId
    132              )
    133            ) {
    134              netErrorCard.errorCode.click();
    135              await ContentTaskUtils.waitForCondition(
    136                () => netErrorCard[mapFelt[objectId]],
    137                "Wait for component to render."
    138              );
    139            }
    140            if (objectId === "exception_button") {
    141              await ContentTaskUtils.waitForCondition(
    142                () =>
    143                  netErrorCard.exceptionButton &&
    144                  !netErrorCard.exceptionButton.disabled,
    145                "Wait for the exception button to be created."
    146              );
    147            }
    148            const el = netErrorCard[mapFelt[objectId]];
    149            el.scrollIntoView(true);
    150            EventUtils.synthesizeMouseAtCenter(el, {}, content);
    151          } else {
    152            await ContentTaskUtils.waitForCondition(
    153              () => doc.body.classList.contains("certerror"),
    154              "Wait for certerror to be loaded"
    155            );
    156            let domElement = doc.querySelector(
    157              `[data-telemetry-id='${objectId}']`
    158            );
    159            domElement.click();
    160          }
    161        }
    162      );
    163 
    164      let clickEvents = await TestUtils.waitForCondition(() => {
    165        let events = Services.telemetry.snapshotEvents(
    166          Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
    167          true
    168        ).content;
    169        if (events && events.length) {
    170          events = events.filter(
    171            e =>
    172              e[1] == "security.ui.certerror" &&
    173              e[2] == "click" &&
    174              e[3] == object
    175          );
    176          if (
    177            events.length == 1 &&
    178            events[0][5].is_frame == useFrame.toString()
    179          ) {
    180            return events;
    181          }
    182        }
    183        return null;
    184      }, "Has captured telemetry events.");
    185 
    186      is(
    187        clickEvents.length,
    188        1,
    189        `recorded telemetry for the click on ${object}, useFrame: ${useFrame}`
    190      );
    191 
    192      // We opened an extra tab for the SUMO page, need to close it.
    193      if (object == "learn_more_link") {
    194        BrowserTestUtils.removeTab(gBrowser.selectedTab);
    195      }
    196 
    197      if (object == "exception_button") {
    198        let certOverrideService = Cc[
    199          "@mozilla.org/security/certoverride;1"
    200        ].getService(Ci.nsICertOverrideService);
    201        certOverrideService.clearValidityOverride(
    202          "expired.example.com",
    203          -1,
    204          {}
    205        );
    206      }
    207 
    208      BrowserTestUtils.removeTab(gBrowser.selectedTab);
    209    }
    210  }
    211 }
    212 
    213 add_task(async function runCheckTelemetryClickEvents() {
    214  for (const useFelt of [true, false]) {
    215    await checkTelemetryClickEvents(useFelt);
    216  }
    217 });