diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc index 45001a7a340ec..b131b0af33b34 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc @@ -18,6 +18,7 @@ #include "base/test/gtest_util.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "build/build_config.h" #include "chrome/browser/ui/autofill/autofill_popup_controller.h" @@ -44,6 +45,7 @@ #include "components/autofill/core/browser/suggestions/suggestion_type.h" #include "components/autofill/core/browser/ui/tabbed_pane_enums.h" #include "components/autofill/core/common/aliases.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/feature_engagement/public/feature_constants.h" #include "components/input/native_web_keyboard_event.h" #include "components/strings/grit/components_strings.h" @@ -1463,6 +1465,81 @@ TEST_F(PopupViewViewsTestKeyboard, NoFillOnTabPressedWithModifiers) { /*non_shift_modifier_pressed=*/true); } +// ----------------------------------------------------------------------------- +// POC: VKEY_TAB acceptance path bypasses per-row IsViewVisibleEnough() guard. +// +// With kAutofillPopupDontAcceptNonVisibleEnoughSuggestion enabled (Finch-on for +// all desktop platforms), every acceptance path is supposed to require the +// selected row to have been >=50% visible for >=500ms before AcceptSuggestion() +// is invoked. VKEY_RETURN, mouse-release, and gesture-tap all consult +// PopupRowView::IsViewVisibleEnough(). VKEY_TAB does not: it falls through +// PopupRowView::HandleKeyPressEvent() (which only handles VKEY_RETURN) to +// PopupViewViews::AcceptSelectedContentOrCreditCardCell(), which calls +// controller_->AcceptSuggestion() unconditionally. +// +// This test creates the popup with the per-row guard active, selects a row, +// and -- without letting the 500ms barrier elapse -- shows that VKEY_RETURN is +// blocked but VKEY_TAB is accepted. A user pressing Tab to move between form +// fields can therefore accept an address/credit-card suggestion whose row has +// not been visible long enough to satisfy the per-row anti-clickjacking guard. +class PopupViewViewsTestTabBypassesRowGuard : public PopupViewViewsTest { + public: + PopupViewViewsTestTabBypassesRowGuard() { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillPopupDontAcceptNonVisibleEnoughSuggestion); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +TEST_F(PopupViewViewsTestTabBypassesRowGuard, + TabAcceptsSuggestionEvenWhenRowNotVisibleLongEnough) { + base::HistogramTester histogram_tester; + + // Make the controller report that the per-row visibility threshold is in + // force (i.e. not disabled-for-testing). Combined with the feature flag + // above, this arms PopupRowView::IsViewVisibleEnough(). + ON_CALL(controller(), IsViewVisibilityAcceptingThresholdEnabled()) + .WillByDefault(Return(true)); + + CreateAndShowView({SuggestionType::kAddressEntry}); + view().SetSelectedCell(CellIndex{0u, CellType::kContent}, + PopupCellSelectionSource::kNonUserInput); + ASSERT_EQ(view().GetSelectedCell(), + std::make_optional(0u, CellType::kContent)); + + // Precondition: the per-row 500ms barrier has NOT elapsed, so the row guard + // says "not visible long enough". Under this condition, *no* acceptance path + // should reach AcceptSuggestion(). + // + // VKEY_RETURN is correctly gated: PopupRowView::HandleKeyPressEvent() checks + // IsViewVisibleEnough() and refuses to accept. + EXPECT_CALL(controller(), AcceptSuggestion).Times(0); + SimulateKeyPress(ui::VKEY_RETURN); + Mock::VerifyAndClearExpectations(&controller()); + // Confirm the row guard evaluated to false (sample value 0) on the RETURN + // path -- i.e. the per-row barrier really is blocking acceptance right now. + histogram_tester.ExpectUniqueSample( + "Autofill.AcceptedSuggestionDesktopRowViewVisibleEnough", 0, 1); + + // VULNERABILITY: VKEY_TAB is NOT gated. PopupRowView::HandleKeyPressEvent() + // returns false for TAB, so PopupViewViews::HandleKeyPressEvent() handles it + // via AcceptSelectedContentOrCreditCardCell(), which never consults + // IsViewVisibleEnough(). The suggestion is accepted even though the per-row + // visibility/dwell guard would have blocked every other input modality. + EXPECT_CALL(controller(), + AcceptSuggestion( + 0, AutofillMetrics::SuggestionAcceptedMethod::kKeyboard)) + .Times(1); + SimulateKeyPress(ui::VKEY_TAB); + Mock::VerifyAndClearExpectations(&controller()); + // The TAB path never consulted IsViewVisibleEnough(): no new sample. + histogram_tester.ExpectUniqueSample( + "Autofill.AcceptedSuggestionDesktopRowViewVisibleEnough", 0, 1); +} +// ----------------------------------------------------------------------------- + // Verify that pressing the tab key while the "Manage addresses..." entry is // selected does not trigger "accepting" the entry (which would mean opening // a tab with the autofill settings).