Chrome · Google Lens › Lens-overlay
CVE-2026-106224
Authorization Error in Google Lens (Lens-overlay)
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
LensOverlayControllerNonBlockingPrivacyNoticeBrowserTestchrome/browser/ui/lens/lens_overlay_controller_browsertest.cc |
modified | |
EXPECT_TRUEchrome/browser/ui/lens/lens_overlay_controller_browsertest.cc |
modified | |
LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTestchrome/browser/ui/lens/lens_overlay_controller_browsertest.cc |
modified |
Files Changed
chrome/browser/ui/lens/overlay_base_controller.hchrome/browser/ui/lens/overlay_base_controller.ccchrome/browser/ui/lens/lens_overlay_controller_browsertest.ccchrome/browser/ui/lens/lens_overlay_controller.cc
Patch
From a3e4912c80540df9646d14e377cff405d3935587 Mon Sep 17 00:00:00 2001 From: Juan Mojica <[email protected]> Date: Wed, 09 Sep 2026 17:26:01 -0700 Subject: [PATCH] [lens-overlay] Validate user activation for privacy notice Ensure that AcceptPrivacyNotice() and DismissPrivacyNotice() in LensOverlayController verify that the non-blocking privacy notice feature is enabled before processing. Additionally, require transient user activation on the overlay RenderFrameHost prior to granting permissions and contextualizing page content in AcceptPrivacyNotice(). If the feature flag is disabled or if AcceptPrivacyNotice() is called without transient user activation during Mojo message dispatch, report a bad Mojo message and return early. Also expose GetOverlayWebView() on OverlayBaseController to access the overlay RenderFrameHost, and add browser test coverage with ContextualTasksSidePanel enabled verifying valid acceptance, dismissal, and bad message reporting. Bug: 502278429 Change-Id: Ia6ad194cc708f1c7f97f570fc39eef76678ded36 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8381945 Reviewed-by: Bryan Nguyen <[email protected]> Commit-Queue: Juan Mojica <[email protected]> Cr-Commit-Position: refs/heads/main@{#1695035} --- diff --git a/chrome/browser/ui/lens/lens_overlay_controller.cc b/chrome/browser/ui/lens/lens_overlay_controller.cc index 6bad95a8..60e3b79 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller.cc +++ b/chrome/browser/ui/lens/lens_overlay_controller.cc @@ -103,6 +103,7 @@ #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_ui.h" +#include "mojo/public/cpp/bindings/message.h" #include "net/base/network_change_notifier.h" #include "pdf/buildflags.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -2295,6 +2296,28 @@ } void LensOverlayController::AcceptPrivacyNotice() { + if (!lens::features::IsLensOverlayNonBlockingPrivacyNoticeEnabled()) { + if (mojo::IsInMessageDispatch()) { + receiver_.ReportBadMessage( + "AcceptPrivacyNotice called when non-blocking privacy notice is not " + "enabled."); + } + return; + } + + views::WebView* overlay_web_view = GetOverlayWebView(); + content::RenderFrameHost* rfh = + overlay_web_view && overlay_web_view->GetWebContents() + ? overlay_web_view->GetWebContents()->GetPrimaryMainFrame() + : nullptr; + if (!rfh || !rfh->HasTransientUserActivation()) { + if (mojo::IsInMessageDispatch()) { + receiver_.ReportBadMessage( + "AcceptPrivacyNotice called without user activation."); + } + return; + } + // Permanently grant permissions, then restart the query flow and upload page // content for contextualization. Profile* profile = @@ -2311,6 +2334,14 @@ } void LensOverlayController::DismissPrivacyNotice() { + if (!lens::features::IsLensOverlayNonBlockingPrivacyNoticeEnabled()) { + if (mojo::IsInMessageDispatch()) { + receiver_.ReportBadMessage( + "DismissPrivacyNotice called when non-blocking privacy notice is not " + "enabled."); + } + return; + } lens::RecordNonBlockingPrivacyNoticeAccepted( lens::LensOverlayNonBlockingPrivacyNoticeUserAction::kDismissed, invocation_source_); diff --git a/chrome/browser/ui/lens/overlay_base_controller.cc b/chrome/browser/ui/lens/overlay_base_controller.cc index c8f297e2..c7c61e4d 100644 --- a/chrome/browser/ui/lens/overlay_base_controller.cc +++ b/chrome/browser/ui/lens/overlay_base_controller.cc @@ -107,12 +107,20 @@ return overlay_blur_layer_delegate_.get(); } +views::WebView* OverlayBaseController::GetOverlayWebView() const { + if (IsOverlayViewShared()) { + return overlay_web_view_.get(); + } + return overlay_web_view_ ? overlay_web_view_.get() + : owned_overlay_web_view_.get(); +} + views::View* OverlayBaseController::GetOverlayViewForTesting() { return overlay_view_.get(); } views::WebView* OverlayBaseController::GetOverlayWebViewForTesting() { - return overlay_web_view_.get(); + return GetOverlayWebView(); } void OverlayBaseController::OnViewBoundsChanged(views::View* observed_view) { @@ -856,13 +864,7 @@ } void OverlayBaseController::SetOverlayRoundedCorner() { - views::WebView* overlay_web_view = nullptr; - if (IsOverlayViewShared()) { - overlay_web_view = overlay_web_view_.get(); - } else { - overlay_web_view = !!overlay_web_view_ ? overlay_web_view_.get() - : owned_overlay_web_view_.get(); - } + views::WebView* overlay_web_view = GetOverlayWebView(); CHECK(overlay_web_view); // Only tab-scoped overlays (where `!IsOverlayViewShared()`) live inside a diff --git a/chrome/browser/ui/lens/overlay_base_controller.h b/chrome/browser/ui/lens/overlay_base_controller.h index c7b2bb9..4925a57 100644 --- a/chrome/browser/ui/lens/overlay_base_controller.h +++ b/chrome/browser/ui/lens/overlay_base_controller.h @@ -358,6 +358,9 @@ // Close the preselection bubble. void ClosePreselectionBubbleImpl(); + // Returns the web view hosting the overlay WebUI if it exists. + views::WebView* GetOverlayWebView() const; + // Returns the host view that the overlay should be attached to. Can be null. views::View* GetHostView() const; diff --git a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc index 7d93351..0e8d3981 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc +++ b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc @@ -110,6 +110,7 @@ #include "components/lens/lens_overlay_dismissal_source.h" #include "components/lens/lens_overlay_invocation_source.h" #include "components/lens/lens_overlay_mime_type.h" +#include "components/lens/lens_overlay_non_blocking_privacy_notice_user_action.h" #include "components/lens/lens_overlay_permission_utils.h" #include "components/lens/lens_overlay_side_panel_menu_option.h" #include "components/lens/lens_overlay_side_panel_result.h" @@ -10028,3 +10029,243 @@ l10n_util::GetStringUTF16( IDS_LENS_OVERLAY_INITIAL_TOAST_MESSAGE_SIMPLIFIED)); } + +class LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest + : public LensOverlayControllerBrowserTest { + public: + LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest() = default; + + void SetupFeatureList() override { + feature_list_.InitWithFeatures( + /*enabled_features=*/ + {lens::features::kLensOverlayNonBlockingPrivacyNotice, + lens::features::kLensOverlayContextualSearchbox, + contextual_tasks::kContextualTasksSidePanel}, + /*disabled_features=*/{contextual_tasks::kContextualTasks}); + } + + void SetUpOnMainThread() override { + LensOverlayControllerBrowserTest::SetUpOnMainThread(); + browser()->GetProfile()->GetPrefs()->SetBoolean( + lens::prefs::kLensSharingPageScreenshotEnabled, false); + browser()->GetProfile()->GetPrefs()->SetBoolean( + lens::prefs::kLensSharingPageContentEnabled, false); + } +}; + +IN_PROC_BROWSER_TEST_F(LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest, + AcceptPrivacyNoticeWithoutUserActivation_Rejected) { + WaitForPaint(); + + base::HistogramTester histogram_tester; + + auto* controller = GetLensOverlayController(); + EXPECT_EQ(controller->state(), State::kOff); + + auto* prefs = browser()->GetProfile()->GetPrefs(); + EXPECT_FALSE( + prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled)); + EXPECT_FALSE(prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled)); + + // Open the overlay. + OpenLensOverlay(LensOverlayInvocationSource::kAppMenu); + ASSERT_TRUE(base::test::RunUntil( + [&]() { return controller->state() == State::kOverlay; })); + + content::WebContents* overlay_web_contents = GetOverlayWebContents(); + ASSERT_NE(overlay_web_contents, nullptr); + EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents)); + + content::RenderFrameHost* rfh = overlay_web_contents->GetPrimaryMainFrame(); + ASSERT_NE(rfh, nullptr); + EXPECT_FALSE(rfh->HasTransientUserActivation()); + + content::RenderProcessHostBadMojoMessageWaiter bad_message_waiter( + rfh->GetProcess()); + + // Invoke AcceptPrivacyNotice via JavaScript without user activation. + content::ExecuteScriptAsyncWithoutUserGesture( + overlay_web_contents, + "document.querySelector('lens-overlay-app').browserProxy.handler." + "acceptPrivacyNotice();"); + + EXPECT_EQ( + "Received bad user message: AcceptPrivacyNotice called without user " + "activation.", + bad_message_waiter.Wait()); + + // Permissions should not be granted. + EXPECT_FALSE( + prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled)); + EXPECT_FALSE(prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled)); + + histogram_tester.ExpectTotalCount( + "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", 0); +} + +IN_PROC_BROWSER_TEST_F( + LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest, + AcceptPrivacyNoticeWithUserActivation_GrantsPermissions) { + WaitForPaint(); + + base::HistogramTester histogram_tester; + + auto* controller = GetLensOverlayController(); + EXPECT_EQ(controller->state(), State::kOff); + + auto* prefs = browser()->GetProfile()->GetPrefs(); + EXPECT_FALSE( + prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled)); + EXPECT_FALSE(prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled)); + + // Open the overlay. + OpenLensOverlay(LensOverlayInvocationSource::kAppMenu); + ASSERT_TRUE(base::test::RunUntil( + [&]() { return controller->state() == State::kOverlay; })); + + content::WebContents* overlay_web_contents = GetOverlayWebContents(); + ASSERT_NE(overlay_web_contents, nullptr); + EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents)); + + // Invoke AcceptPrivacyNotice with user activation via ExecJs (default option + // includes user gesture). + EXPECT_TRUE(content::ExecJs( + overlay_web_contents, + "document.querySelector('lens-overlay-app').browserProxy.handler." + "acceptPrivacyNotice();")); + + // Wait for permissions to be granted. + EXPECT_TRUE(base::test::RunUntil([&]() { + return prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled) && + prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled); + })); + + histogram_tester.ExpectUniqueSample( + "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", + lens::LensOverlayNonBlockingPrivacyNoticeUserAction::kAccepted, 1); +} + +IN_PROC_BROWSER_TEST_F(LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest, + DismissPrivacyNotice_Success) { + WaitForPaint(); + + base::HistogramTester histogram_tester; + + auto* controller = GetLensOverlayController(); + EXPECT_EQ(controller->state(), State::kOff); + + // Open the overlay. + OpenLensOverlay(LensOverlayInvocationSource::kAppMenu); + ASSERT_TRUE(base::test::RunUntil( + [&]() { return controller->state() == State::kOverlay; })); + + content::WebContents* overlay_web_contents = GetOverlayWebContents(); + ASSERT_NE(overlay_web_contents, nullptr); + EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents)); + + // Invoke DismissPrivacyNotice via JavaScript. + EXPECT_TRUE(content::ExecJs( + overlay_web_contents, + "document.querySelector('lens-overlay-app').browserProxy.handler." + "dismissPrivacyNotice();")); + + histogram_tester.ExpectUniqueSample( + "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", + lens::LensOverlayNonBlockingPrivacyNoticeUserAction::kDismissed, 1); +} + +class LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest + : public LensOverlayControllerBrowserTest { + public: + LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest() = default; + + void SetupFeatureList() override { + feature_list_.InitWithFeatures( + /*enabled_features=*/ + {lens::features::kLensOverlayContextualSearchbox, + contextual_tasks::kContextualTasksSidePanel}, + /*disabled_features=*/{ + lens::features::kLensOverlayNonBlockingPrivacyNotice, + contextual_tasks::kContextualTasks}); + } +}; + +IN_PROC_BROWSER_TEST_F( + LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest, + AcceptPrivacyNoticeWhenFeatureDisabled_ReportsBadMessage) { + WaitForPaint(); + + base::HistogramTester histogram_tester; + + auto* controller = GetLensOverlayController(); + EXPECT_EQ(controller->state(), State::kOff); + + // Open the overlay with non-blocking privacy notice disabled. + OpenLensOverlay(LensOverlayInvocationSource::kAppMenu); + ASSERT_TRUE(base::test::RunUntil( + [&]() { return controller->state() == State::kOverlay; })); + + content::WebContents* overlay_web_contents = GetOverlayWebContents(); + ASSERT_NE(overlay_web_contents, nullptr); + EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents)); + + content::RenderFrameHost* rfh = overlay_web_contents->GetPrimaryMainFrame(); + ASSERT_NE(rfh, nullptr); + + content::RenderProcessHostBadMojoMessageWaiter bad_message_waiter( + rfh->GetProcess()); + + // Invoke AcceptPrivacyNotice when feature is disabled. + content::ExecuteScriptAsync( + overlay_web_contents, + "document.querySelector('lens-overlay-app').browserProxy.handler." + "acceptPrivacyNotice();"); + + EXPECT_EQ( + "Received bad user message: AcceptPrivacyNotice called when " + "non-blocking privacy notice is not enabled.", + bad_message_waiter.Wait()); + + histogram_tester.ExpectTotalCount( + "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", 0); +} + +IN_PROC_BROWSER_TEST_F( + LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest, + DismissPrivacyNoticeWhenFeatureDisabled_ReportsBadMessage) { + WaitForPaint(); + + base::HistogramTester histogram_tester; + + auto* controller = GetLensOverlayController(); + EXPECT_EQ(controller->state(), State::kOff); + + // Open the overlay with non-blocking privacy notice disabled. + OpenLensOverlay(LensOverlayInvocationSource::kAppMenu); + ASSERT_TRUE(base::test::RunUntil( + [&]() { return controller->state() == State::kOverlay; })); + + content::WebContents* overlay_web_contents = GetOverlayWebContents(); + ASSERT_NE(overlay_web_contents, nullptr); + EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents)); + + content::RenderFrameHost* rfh = overlay_web_contents->GetPrimaryMainFrame(); + ASSERT_NE(rfh, nullptr); + + content::RenderProcessHostBadMojoMessageWaiter bad_message_waiter( + rfh->GetProcess()); + + // Invoke DismissPrivacyNotice when feature is disabled. + content::ExecuteScriptAsync( + overlay_web_contents, + "document.querySelector('lens-overlay-app').browserProxy.handler." + "dismissPrivacyNotice();"); + + EXPECT_EQ( + "Received bad user message: DismissPrivacyNotice called when " + "non-blocking privacy notice is not enabled.", + bad_message_waiter.Wait()); + + histogram_tester.ExpectTotalCount( + "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", 0); +}
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
index 7d93351..0e8d3981 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
@@ -110,6 +110,7 @@
#include "components/lens/lens_overlay_dismissal_source.h"
#include "components/lens/lens_overlay_invocation_source.h"
#include "components/lens/lens_overlay_mime_type.h"
+#include "components/lens/lens_overlay_non_blocking_privacy_notice_user_action.h"
#include "components/lens/lens_overlay_permission_utils.h"
#include "components/lens/lens_overlay_side_panel_menu_option.h"
#include "components/lens/lens_overlay_side_panel_result.h"
@@ -10028,3 +10029,243 @@
l10n_util::GetStringUTF16(
IDS_LENS_OVERLAY_INITIAL_TOAST_MESSAGE_SIMPLIFIED));
}
+
+class LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest
+ : public LensOverlayControllerBrowserTest {
+ public:
+ LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest() = default;
+
+ void SetupFeatureList() override {
+ feature_list_.InitWithFeatures(
+ /*enabled_features=*/
+ {lens::features::kLensOverlayNonBlockingPrivacyNotice,
+ lens::features::kLensOverlayContextualSearchbox,
+ contextual_tasks::kContextualTasksSidePanel},
+ /*disabled_features=*/{contextual_tasks::kContextualTasks});
+ }
+
+ void SetUpOnMainThread() override {
+ LensOverlayControllerBrowserTest::SetUpOnMainThread();
+ browser()->GetProfile()->GetPrefs()->SetBoolean(
+ lens::prefs::kLensSharingPageScreenshotEnabled, false);
+ browser()->GetProfile()->GetPrefs()->SetBoolean(
+ lens::prefs::kLensSharingPageContentEnabled, false);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest,
+ AcceptPrivacyNoticeWithoutUserActivation_Rejected) {
+ WaitForPaint();
+
+ base::HistogramTester histogram_tester;
+
+ auto* controller = GetLensOverlayController();
+ EXPECT_EQ(controller->state(), State::kOff);
+
+ auto* prefs = browser()->GetProfile()->GetPrefs();
+ EXPECT_FALSE(
+ prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled));
+ EXPECT_FALSE(prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled));
+
+ // Open the overlay.
+ OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
+ ASSERT_TRUE(base::test::RunUntil(
+ [&]() { return controller->state() == State::kOverlay; }));
+
+ content::WebContents* overlay_web_contents = GetOverlayWebContents();
+ ASSERT_NE(overlay_web_contents, nullptr);
+ EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents));
+
+ content::RenderFrameHost* rfh = overlay_web_contents->GetPrimaryMainFrame();
+ ASSERT_NE(rfh, nullptr);
+ EXPECT_FALSE(rfh->HasTransientUserActivation());
+
+ content::RenderProcessHostBadMojoMessageWaiter bad_message_waiter(
+ rfh->GetProcess());
+
+ // Invoke AcceptPrivacyNotice via JavaScript without user activation.
+ content::ExecuteScriptAsyncWithoutUserGesture(
+ overlay_web_contents,
+ "document.querySelector('lens-overlay-app').browserProxy.handler."
+ "acceptPrivacyNotice();");
+
+ EXPECT_EQ(
+ "Received bad user message: AcceptPrivacyNotice called without user "
+ "activation.",
+ bad_message_waiter.Wait());
+
+ // Permissions should not be granted.
+ EXPECT_FALSE(
+ prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled));
+ EXPECT_FALSE(prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled));
+
+ histogram_tester.ExpectTotalCount(
+ "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", 0);
+}
+
+IN_PROC_BROWSER_TEST_F(
+ LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest,
+ AcceptPrivacyNoticeWithUserActivation_GrantsPermissions) {
+ WaitForPaint();
+
+ base::HistogramTester histogram_tester;
+
+ auto* controller = GetLensOverlayController();
+ EXPECT_EQ(controller->state(), State::kOff);
+
+ auto* prefs = browser()->GetProfile()->GetPrefs();
+ EXPECT_FALSE(
+ prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled));
+ EXPECT_FALSE(prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled));
+
+ // Open the overlay.
+ OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
+ ASSERT_TRUE(base::test::RunUntil(
+ [&]() { return controller->state() == State::kOverlay; }));
+
+ content::WebContents* overlay_web_contents = GetOverlayWebContents();
+ ASSERT_NE(overlay_web_contents, nullptr);
+ EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents));
+
+ // Invoke AcceptPrivacyNotice with user activation via ExecJs (default option
+ // includes user gesture).
+ EXPECT_TRUE(content::ExecJs(
+ overlay_web_contents,
+ "document.querySelector('lens-overlay-app').browserProxy.handler."
+ "acceptPrivacyNotice();"));
+
+ // Wait for permissions to be granted.
+ EXPECT_TRUE(base::test::RunUntil([&]() {
+ return prefs->GetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled) &&
+ prefs->GetBoolean(lens::prefs::kLensSharingPageContentEnabled);
+ }));
+
+ histogram_tester.ExpectUniqueSample(
+ "Lens.Overlay.NonBlockingPrivacyNotice.Accepted",
+ lens::LensOverlayNonBlockingPrivacyNoticeUserAction::kAccepted, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(LensOverlayControllerNonBlockingPrivacyNoticeBrowserTest,
+ DismissPrivacyNotice_Success) {
+ WaitForPaint();
+
+ base::HistogramTester histogram_tester;
+
+ auto* controller = GetLensOverlayController();
+ EXPECT_EQ(controller->state(), State::kOff);
+
+ // Open the overlay.
+ OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
+ ASSERT_TRUE(base::test::RunUntil(
+ [&]() { return controller->state() == State::kOverlay; }));
+
+ content::WebContents* overlay_web_contents = GetOverlayWebContents();
+ ASSERT_NE(overlay_web_contents, nullptr);
+ EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents));
+
+ // Invoke DismissPrivacyNotice via JavaScript.
+ EXPECT_TRUE(content::ExecJs(
+ overlay_web_contents,
+ "document.querySelector('lens-overlay-app').browserProxy.handler."
+ "dismissPrivacyNotice();"));
+
+ histogram_tester.ExpectUniqueSample(
+ "Lens.Overlay.NonBlockingPrivacyNotice.Accepted",
+ lens::LensOverlayNonBlockingPrivacyNoticeUserAction::kDismissed, 1);
+}
+
+class LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest
+ : public LensOverlayControllerBrowserTest {
+ public:
+ LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest() = default;
+
+ void SetupFeatureList() override {
+ feature_list_.InitWithFeatures(
+ /*enabled_features=*/
+ {lens::features::kLensOverlayContextualSearchbox,
+ contextual_tasks::kContextualTasksSidePanel},
+ /*disabled_features=*/{
+ lens::features::kLensOverlayNonBlockingPrivacyNotice,
+ contextual_tasks::kContextualTasks});
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(
+ LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest,
+ AcceptPrivacyNoticeWhenFeatureDisabled_ReportsBadMessage) {
+ WaitForPaint();
+
+ base::HistogramTester histogram_tester;
+
+ auto* controller = GetLensOverlayController();
+ EXPECT_EQ(controller->state(), State::kOff);
+
+ // Open the overlay with non-blocking privacy notice disabled.
+ OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
+ ASSERT_TRUE(base::test::RunUntil(
+ [&]() { return controller->state() == State::kOverlay; }));
+
+ content::WebContents* overlay_web_contents = GetOverlayWebContents();
+ ASSERT_NE(overlay_web_contents, nullptr);
+ EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents));
+
+ content::RenderFrameHost* rfh = overlay_web_contents->GetPrimaryMainFrame();
+ ASSERT_NE(rfh, nullptr);
+
+ content::RenderProcessHostBadMojoMessageWaiter bad_message_waiter(
+ rfh->GetProcess());
+
+ // Invoke AcceptPrivacyNotice when feature is disabled.
+ content::ExecuteScriptAsync(
+ overlay_web_contents,
+ "document.querySelector('lens-overlay-app').browserProxy.handler."
+ "acceptPrivacyNotice();");
+
+ EXPECT_EQ(
+ "Received bad user message: AcceptPrivacyNotice called when "
+ "non-blocking privacy notice is not enabled.",
+ bad_message_waiter.Wait());
+
+ histogram_tester.ExpectTotalCount(
+ "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", 0);
+}
+
+IN_PROC_BROWSER_TEST_F(
+ LensOverlayControllerPrivacyNoticeFeatureDisabledBrowserTest,
+ DismissPrivacyNoticeWhenFeatureDisabled_ReportsBadMessage) {
+ WaitForPaint();
+
+ base::HistogramTester histogram_tester;
+
+ auto* controller = GetLensOverlayController();
+ EXPECT_EQ(controller->state(), State::kOff);
+
+ // Open the overlay with non-blocking privacy notice disabled.
+ OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
+ ASSERT_TRUE(base::test::RunUntil(
+ [&]() { return controller->state() == State::kOverlay; }));
+
+ content::WebContents* overlay_web_contents = GetOverlayWebContents();
+ ASSERT_NE(overlay_web_contents, nullptr);
+ EXPECT_TRUE(content::WaitForLoadStop(overlay_web_contents));
+
+ content::RenderFrameHost* rfh = overlay_web_contents->GetPrimaryMainFrame();
+ ASSERT_NE(rfh, nullptr);
+
+ content::RenderProcessHostBadMojoMessageWaiter bad_message_waiter(
+ rfh->GetProcess());
+
+ // Invoke DismissPrivacyNotice when feature is disabled.
+ content::ExecuteScriptAsync(
+ overlay_web_contents,
+ "document.querySelector('lens-overlay-app').browserProxy.handler."
+ "dismissPrivacyNotice();");
+
+ EXPECT_EQ(
+ "Received bad user message: DismissPrivacyNotice called when "
+ "non-blocking privacy notice is not enabled.",
+ bad_message_waiter.Wait());
+
+ histogram_tester.ExpectTotalCount(
+ "Lens.Overlay.NonBlockingPrivacyNotice.Accepted", 0);
+}
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page