tor-browser

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

commit 51bb09d070987c87690fb57de9f171b36e17789b
parent 84504d1bb6af26fbc84d8eff7aa33c4d7cf3e921
Author: Meg Viar <lmegviar@gmail.com>
Date:   Thu, 16 Oct 2025 21:32:43 +0000

Bug 1994735 - Don't allow legacy telemetry upload if a notification if currently in progress r=toolkit-telemetry-reviewers,dmose,janerik

Differential Revision: https://phabricator.services.mozilla.com/D268883

Diffstat:
Mtoolkit/components/telemetry/app/TelemetryReportingPolicy.sys.mjs | 25++++++++++++++++++++++---
Mtoolkit/components/telemetry/tests/unit/test_TOUNotificationFlow.js | 50+++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/toolkit/components/telemetry/app/TelemetryReportingPolicy.sys.mjs b/toolkit/components/telemetry/app/TelemetryReportingPolicy.sys.mjs @@ -221,6 +221,13 @@ export var TelemetryReportingPolicy = { }, /** + * Test only method, used simulate a notification being in-progress. + */ + testNotificationInProgress(inProgress) { + TelemetryReportingPolicyImpl._notificationInProgress = inProgress; + }, + + /** * Test only method, used to get TOS on-train release dates by channel. */ get fullOnTrainReleaseDates() { @@ -760,9 +767,12 @@ var TelemetryReportingPolicyImpl = { * Check if we are allowed to upload data. * Prerequisite: data submission is enabled (this.dataSubmissionEnabled). * - * For upload to be allowed from a data reporting standpoint, the user should - * not qualify to see the legacy policy notification flow and also not qualify - * to see the Terms of Use acceptance flow. + * If a notification is currently in progress, the user should not be allowed + * to upload data. + * + * Otherwise, for upload to be allowed from a data reporting standpoint, the + * user should not qualify to see the legacy policy notification flow and also + * not qualify to see the Terms of Use acceptance flow. * @return {Boolean} True if we are allowed to upload data, false otherwise. */ canUpload() { @@ -772,6 +782,15 @@ var TelemetryReportingPolicyImpl = { return false; } + // If a notification is in progress, such as when the TOU modal is currently + // showing and user has not yet accepted, do not allow upload. The legacy + // flow doesn't require interaction, so the notification is only considered + // to be in progress for the brief period between when the infobar or + // privacy notice tab is shown and when the notification is recorded. + if (this._notificationInProgress) { + return false; + } + return !this._shouldNotifyDataReportingPolicy() && !this._shouldShowTOU(); }, diff --git a/toolkit/components/telemetry/tests/unit/test_TOUNotificationFlow.js b/toolkit/components/telemetry/tests/unit/test_TOUNotificationFlow.js @@ -43,6 +43,8 @@ function fakeResetAcceptedPolicy() { // Fake dismissing a modal dialog. function fakeInteractWithModal() { Services.obs.notifyObservers(null, "termsofuse:interacted"); + // Mark that notification is no longer in progress + TelemetryReportingPolicy.testNotificationInProgress(false); } function unsetMinimumPolicyVersion() { @@ -123,7 +125,7 @@ add_setup(() => { "datareporting.policy.dataSubmissionPolicyAcceptedVersion" ); Services.prefs.clearUserPref(TelemetryUtils.Preferences.BypassNotification); - + TelemetryReportingPolicy.testNotificationInProgress(false); TelemetryReportingPolicy.reset(); }); }); @@ -575,13 +577,21 @@ add_task( let p = Policy.delayedSetup(); Policy.fakeSessionRestoreNotification(); + // Mark that notification is in progress + TelemetryReportingPolicy.testNotificationInProgress(true); // Spin the event loop once – the notification should *not* have fired yet. await TestUtils.waitForTick(); + Assert.ok( !notificationSeen, "Notification should not be dispatched before the user interacts" ); + Assert.ok( + !TelemetryReportingPolicy.canUpload(), + "canUpload() is false while TOU modal is showing (notification in progress)" + ); + Assert.equal( modalStub.callCount, 1, @@ -593,12 +603,18 @@ add_task( await p; Assert.ok( + TelemetryReportingPolicy.canUpload(), + "canUpload() is true after the user accepts the TOU via the modal" + ); + + Assert.ok( notificationSeen, "Notification fires after the user accepts the ToU in this session" ); // Clean-up. fakeResetAcceptedPolicy(); + TelemetryReportingPolicy.testNotificationInProgress(false); await doCleanup(); sinon.restore(); } @@ -622,6 +638,8 @@ add_task( let p = Policy.delayedSetup(); Policy.fakeSessionRestoreNotification(); + // Mark that notification is in progress + TelemetryReportingPolicy.testNotificationInProgress(true); // Spin the event loop once – the notification should *not* have fired yet. await TestUtils.waitForTick(); Assert.ok( @@ -635,10 +653,20 @@ add_task( "showModal should be invoked exactly once when prompting the user" ); + Assert.ok( + !TelemetryReportingPolicy.canUpload(), + "canUpload() is false while TOU modal is showing (notification in progress)" + ); + await TestUtils.waitForTick(); await p; Assert.ok( + !TelemetryReportingPolicy.canUpload(), + "canUpload() remains false if the user never accepts and no bypass applies" + ); + + Assert.ok( !notificationSeen, "Notification should still not be dispatched if never interacted with" ); @@ -646,6 +674,7 @@ add_task( // Clean-up. fakeResetAcceptedPolicy(); await doCleanup(); + TelemetryReportingPolicy.testNotificationInProgress(false); sinon.restore(); } ); @@ -668,6 +697,8 @@ add_task( let p = Policy.delayedSetup(); Policy.fakeSessionRestoreNotification(); + // Mark that notification is in progress + TelemetryReportingPolicy.testNotificationInProgress(true); // Spin the event loop once – the notification should *not* have fired yet. await TestUtils.waitForTick(); Assert.ok( @@ -681,6 +712,11 @@ add_task( "showModal should be invoked exactly once when prompting the user" ); + Assert.ok( + !TelemetryReportingPolicy.canUpload(), + "canUpload() is false while modal is displayed" + ); + await TestUtils.waitForTick(); await p; @@ -688,16 +724,28 @@ add_task( !notificationSeen, "Notification should still not be dispatched if never interacted with" ); + + Assert.ok( + !TelemetryReportingPolicy.canUpload(), + "canUpload() remains false" + ); + fakeInteractWithModal(); await TestUtils.waitForTick(); Assert.ok( + TelemetryReportingPolicy.canUpload(), + "canUpload() becomes true after later acceptance" + ); + + Assert.ok( notificationSeen, "Notification fires after the user accepts the ToU in this session" ); // Clean-up. fakeResetAcceptedPolicy(); + TelemetryReportingPolicy.testNotificationInProgress(false); await doCleanup(); sinon.restore(); }