Bug 1650468 - Protections dashboard accepts entrypoint param r=prathiksha
authorErica Wright <ewright@mozilla.com>
Wed, 05 Aug 2020 16:25:57 +0000
changeset 543420 87c14534121fff5bd4348739ce512f0e335be6a1
parent 543419 c72d8188a88d3b7923f6bd5560bc4026f8ae1a6f
child 543421 330c4fd5259d03cd63291b5d235f35240f98010c
push id37673
push userapavel@mozilla.com
push dateWed, 05 Aug 2020 21:44:54 +0000
treeherdermozilla-central@26de281d4c21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersprathiksha
bugs1650468
milestone81.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1650468 - Protections dashboard accepts entrypoint param r=prathiksha Differential Revision: https://phabricator.services.mozilla.com/D82240
browser/actors/AboutProtectionsParent.jsm
browser/components/BrowserGlue.jsm
browser/components/protections/content/protections.js
browser/components/protections/test/browser/browser_protections_telemetry.js
toolkit/components/telemetry/Events.yaml
toolkit/modules/RemotePageAccessManager.jsm
--- a/browser/actors/AboutProtectionsParent.jsm
+++ b/browser/actors/AboutProtectionsParent.jsm
@@ -62,16 +62,17 @@ const MONITOR_RESPONSE_PROPS = [
   "numBreaches",
   "passwords",
   "numBreachesResolved",
   "passwordsResolved",
 ];
 
 let gTestOverride = null;
 let monitorResponse = null;
+let entrypoint = "direct";
 
 class AboutProtectionsParent extends JSWindowActorParent {
   constructor() {
     super();
   }
 
   // Some tests wish to override certain functions with ones that mostly do nothing.
   static setTestOverride(callback) {
@@ -374,13 +375,20 @@ class AboutProtectionsParent extends JSW
 
       case "ClearMonitorCache":
         monitorResponse = null;
         break;
 
       case "GetShowProxyCard":
         let card = await this.shouldShowProxyCard();
         return card;
+
+      case "RecordEntryPoint":
+        entrypoint = aMessage.data.entrypoint;
+        break;
+
+      case "FetchEntryPoint":
+        return entrypoint;
     }
 
     return undefined;
   }
 }
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -196,17 +196,17 @@ let JSWINDOWACTORS = {
     child: {
       moduleURI: "resource:///actors/AboutProtectionsChild.jsm",
 
       events: {
         DOMWindowCreated: { capture: true },
       },
     },
 
-    matches: ["about:protections"],
+    matches: ["about:protections", "about:protections?*"],
   },
 
   AboutReader: {
     parent: {
       moduleURI: "resource:///actors/AboutReaderParent.jsm",
     },
     child: {
       moduleURI: "resource:///actors/AboutReaderChild.jsm",
--- a/browser/components/protections/content/protections.js
+++ b/browser/components/protections/content/protections.js
@@ -3,22 +3,59 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* eslint-env mozilla/frame-script */
 
 import LockwiseCard from "./lockwise-card.js";
 import MonitorCard from "./monitor-card.js";
 import ProxyCard from "./proxy-card.js";
 
-// We need to send the close telemetry before unload while we still have a connection to RPM.
-window.addEventListener("beforeunload", () => {
-  document.sendTelemetryEvent("close", "protection_report");
-});
+let cbCategory = RPMGetStringPref("browser.contentblocking.category");
+document.sendTelemetryEvent = (action, object, value = "") => {
+  // eslint-disable-next-line no-undef
+  RPMRecordTelemetryEvent("security.ui.protections", action, object, value, {
+    category: cbCategory,
+  });
+};
+
+let { protocol, pathname, searchParams } = new URL(document.location);
+
+let searchParamsChanged = false;
+if (searchParams.has("entrypoint")) {
+  RPMSendAsyncMessage("RecordEntryPoint", {
+    entrypoint: searchParams.get("entrypoint"),
+  });
+  // Remove this parameter from the URL (after recording above) to make it
+  // cleaner for bookmarking and switch-to-tab and so that bookmarked values
+  // don't skew telemetry.
+  searchParams.delete("entrypoint");
+  searchParamsChanged = true;
+}
 
 document.addEventListener("DOMContentLoaded", e => {
+  if (searchParamsChanged) {
+    let newURL = protocol + pathname;
+    let params = searchParams.toString();
+    if (params) {
+      newURL += "?" + params;
+    }
+    window.location.replace(newURL);
+    return;
+  }
+
+  RPMSendQuery("FetchEntryPoint", {}).then(entrypoint => {
+    // Send telemetry on arriving on this page
+    document.sendTelemetryEvent("show", "protection_report", entrypoint);
+  });
+
+  // We need to send the close telemetry before unload while we still have a connection to RPM.
+  window.addEventListener("beforeunload", () => {
+    document.sendTelemetryEvent("close", "protection_report");
+  });
+
   let todayInMs = Date.now();
   let weekAgoInMs = todayInMs - 6 * 24 * 60 * 60 * 1000;
 
   let dataTypes = [
     "cryptominer",
     "fingerprinter",
     "tracker",
     "cookie",
@@ -48,32 +85,20 @@ document.addEventListener("DOMContentLoa
   manageProtectionsLink.addEventListener("click", protectionSettingsEvtHandler);
   manageProtectionsLink.addEventListener(
     "keypress",
     protectionSettingsEvtHandler
   );
   manageProtections.addEventListener("click", protectionSettingsEvtHandler);
   manageProtections.addEventListener("keypress", protectionSettingsEvtHandler);
 
-  let cbCategory = RPMGetStringPref("browser.contentblocking.category");
-
   let legend = document.getElementById("legend");
   legend.style.gridTemplateAreas =
     "'social cookie tracker fingerprinter cryptominer'";
 
-  document.sendTelemetryEvent = (action, object, value = "") => {
-    // eslint-disable-next-line no-undef
-    RPMRecordTelemetryEvent("security.ui.protections", action, object, value, {
-      category: cbCategory,
-    });
-  };
-
-  // Send telemetry on arriving and closing this page
-  document.sendTelemetryEvent("show", "protection_report");
-
   let createGraph = data => {
     let graph = document.getElementById("graph");
     let summary = document.getElementById("graph-total-summary");
     let weekSummary = document.getElementById("graph-week-summary");
 
     // User is in private mode, show no data on the graph
     if (data.isPrivate) {
       graph.classList.add("private-window");
--- a/browser/components/protections/test/browser/browser_protections_telemetry.js
+++ b/browser/components/protections/test/browser/browser_protections_telemetry.js
@@ -815,8 +815,95 @@ add_task(async function test_save_teleme
 
   const scalars = Services.telemetry.getSnapshotForScalars("main", false)
     .parent;
   is(scalars["contentblocking.trackers_blocked_count"], 6);
 
   // Use the TrackingDBService API to delete the data.
   await TrackingDBService.clearAll();
 });
+
+// Test that telemetry is sent if entrypoint param is included,
+// and test that it is recorded as default if entrypoint param is not properly included
+add_task(async function checkTelemetryLoadEventForEntrypoint() {
+  // There's an arbitrary interval of 2 seconds in which the content
+  // processes sync their event data with the parent process, we wait
+  // this out to ensure that we clear everything that is left over from
+  // previous tests and don't receive random events in the middle of our tests.
+  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+  await new Promise(c => setTimeout(c, 2000));
+
+  // Clear everything.
+  Services.telemetry.clearEvents();
+  await TestUtils.waitForCondition(() => {
+    let events = Services.telemetry.snapshotEvents(
+      Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+      true
+    ).content;
+    return !events || !events.length;
+  });
+
+  Services.telemetry.setEventRecordingEnabled("security.ui.protections", true);
+
+  info("Typo in 'entrypoint' should not be recorded");
+  let tab = await BrowserTestUtils.openNewForegroundTab({
+    url: "about:protections?entryPoint=newPage",
+    gBrowser,
+  });
+
+  let loadEvents = await TestUtils.waitForCondition(() => {
+    let events = Services.telemetry.snapshotEvents(
+      Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+      true
+    ).content;
+    if (events && events.length) {
+      events = events.filter(
+        e =>
+          e[1] == "security.ui.protections" &&
+          e[2] == "show" &&
+          e[4] == "direct"
+      );
+      if (events.length == 1) {
+        return events;
+      }
+    }
+    return null;
+  }, "recorded telemetry for showing the report contains default 'direct' entrypoint");
+
+  is(
+    loadEvents.length,
+    1,
+    `recorded telemetry for showing the report contains default 'direct' entrypoint`
+  );
+
+  await BrowserTestUtils.removeTab(tab);
+
+  tab = await BrowserTestUtils.openNewForegroundTab({
+    url: "about:protections?entrypoint=page",
+    gBrowser,
+  });
+
+  loadEvents = await TestUtils.waitForCondition(() => {
+    let events = Services.telemetry.snapshotEvents(
+      Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+      true
+    ).content;
+    if (events && events.length) {
+      events = events.filter(
+        e =>
+          e[1] == "security.ui.protections" && e[2] == "show" && e[4] == "page"
+      );
+      if (events.length == 1) {
+        return events;
+      }
+    }
+    return null;
+  }, "recorded telemetry for showing the report contains correct entrypoint");
+
+  is(
+    loadEvents.length,
+    1,
+    "recorded telemetry for showing the report contains correct entrypoint"
+  );
+
+  // Clean up.
+  await BrowserTestUtils.removeTab(tab);
+});
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -1820,18 +1820,19 @@ security.ui.protections:
   show:
     objects: [
       "protection_report",
     ]
     bug_numbers:
       - 1557050
       - 1610897
       - 1643428
+      - 1650468
     description: >
-      User arrived on the protection report.
+      User arrived on the protection report. This also includes a 'value' attribute which defaults to 'direct' or will be the value that a referring website addds to the url.
     expiry_version: "86"
     record_in_processes: ["content"]
     release_channel_collection: opt-out
     notification_emails:
       - ewright@mozilla.com
       - chsiang@mozilla.com
       - seceng-telemetry@mozilla.com
     products:
--- a/toolkit/modules/RemotePageAccessManager.jsm
+++ b/toolkit/modules/RemotePageAccessManager.jsm
@@ -125,23 +125,25 @@ let RemotePageAccessManager = {
       RPMIsWindowPrivate: ["*"],
     },
     "about:protections": {
       RPMSendAsyncMessage: [
         "OpenContentBlockingPreferences",
         "OpenAboutLogins",
         "OpenSyncPreferences",
         "ClearMonitorCache",
+        "RecordEntryPoint",
       ],
       RPMSendQuery: [
         "FetchUserLoginsData",
         "FetchMonitorData",
         "FetchContentBlockingEvents",
         "FetchMobileDeviceConnected",
         "GetShowProxyCard",
+        "FetchEntryPoint",
       ],
       RPMAddMessageListener: ["*"],
       RPMRemoveMessageListener: ["*"],
       RPMSetBoolPref: [
         "browser.contentblocking.report.hide_lockwise_app",
         "browser.contentblocking.report.show_mobile_app",
       ],
       RPMGetBoolPref: [