| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/page_info/page_info.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/at_exit.h" |
| #include "base/functional/bind.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| #include "chrome/browser/content_settings/page_specific_content_settings_delegate.h" |
| #include "chrome/browser/file_system_access/file_system_access_features.h" |
| #include "chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h" |
| #include "chrome/browser/ssl/stateful_ssl_host_state_delegate_factory.h" |
| #include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h" |
| #include "chrome/browser/ui/page_info/chrome_page_info_delegate.h" |
| #include "chrome/browser/ui/page_info/chrome_page_info_ui_delegate.h" |
| #include "chrome/browser/usb/usb_chooser_context.h" |
| #include "chrome/browser/usb/usb_chooser_context_factory.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "components/content_settings/core/common/content_settings.h" |
| #include "components/content_settings/core/common/content_settings_constraints.h" |
| #include "components/content_settings/core/common/content_settings_types.h" |
| #include "components/content_settings/core/common/cookie_blocking_3pcd_status.h" |
| #include "components/infobars/content/content_infobar_manager.h" |
| #include "components/infobars/core/infobar.h" |
| #include "components/page_info/core/features.h" |
| #include "components/page_info/page_info_ui.h" |
| #include "components/permissions/features.h" |
| #include "components/permissions/permission_recovery_success_rate_tracker.h" |
| #include "components/safe_browsing/buildflags.h" |
| #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h" |
| #include "components/subresource_filter/content/browser/subresource_filter_profile_context.h" |
| #include "content/public/browser/ssl_host_state_delegate.h" |
| #include "content/public/browser/ssl_status.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/web_contents_tester.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "net/base/features.h" |
| #include "net/base/net_errors.h" |
| #include "net/cert/cert_status_flags.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/ssl/ssl_connection_status_flags.h" |
| #include "net/test/cert_test_util.h" |
| #include "net/test/test_certificate_data.h" |
| #include "net/test/test_data_directory.h" |
| #include "services/device/public/cpp/test/fake_usb_device_manager.h" |
| #include "services/device/public/mojom/usb_device.mojom.h" |
| #include "services/media_session/public/mojom/media_session.mojom.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "url/origin.h" |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "chrome/browser/android/android_theme_resources.h" |
| #include "media/base/media_switches.h" |
| #else |
| #include "chrome/browser/ui/views/chrome_layout_provider.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/prefs/pref_service.h" |
| #include "media/base/media_switches.h" |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" |
| #include "components/user_manager/scoped_user_manager.h" |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| using content::SSLStatus; |
| using content_settings::SettingSource; |
| using testing::_; |
| using testing::AnyNumber; |
| using testing::Invoke; |
| using testing::Mock; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::SetArgPointee; |
| |
| namespace { |
| |
| // SSL cipher suite like specified in RFC5246 Appendix A.5. "The Cipher Suite". |
| // Without the CR_ prefix, this clashes with the OS X 10.8 headers. |
| int CR_TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3D; |
| |
| int SetSSLVersion(int connection_status, int version) { |
| // Clear SSL version bits (Bits 20, 21 and 22). |
| connection_status &= |
| ~(net::SSL_CONNECTION_VERSION_MASK << net::SSL_CONNECTION_VERSION_SHIFT); |
| int bitmask = version << net::SSL_CONNECTION_VERSION_SHIFT; |
| return bitmask | connection_status; |
| } |
| |
| int SetSSLCipherSuite(int connection_status, int cipher_suite) { |
| // Clear cipher suite bits (the 16 lowest bits). |
| connection_status &= ~net::SSL_CONNECTION_CIPHERSUITE_MASK; |
| return cipher_suite | connection_status; |
| } |
| |
| class MockPageInfoUI : public PageInfoUI { |
| public: |
| ~MockPageInfoUI() override = default; |
| MOCK_METHOD(void, SetCookieInfo, (const CookiesInfo& cookie_info)); |
| MOCK_METHOD(void, SetPermissionInfoStub, ()); |
| MOCK_METHOD(void, SetIdentityInfo, (const IdentityInfo& identity_info)); |
| MOCK_METHOD(void, SetPageFeatureInfo, (const PageFeatureInfo& info)); |
| MOCK_METHOD(void, |
| SetAdPersonalizationInfo, |
| (const AdPersonalizationInfo& info)); |
| |
| void SetPermissionInfo( |
| const PermissionInfoList& permission_info_list, |
| ChosenObjectInfoList chosen_object_info_list) override { |
| SetPermissionInfoStub(); |
| if (set_permission_info_callback_) { |
| set_permission_info_callback_.Run(permission_info_list, |
| std::move(chosen_object_info_list)); |
| } |
| } |
| |
| base::RepeatingCallback<void(const PermissionInfoList& permission_info_list, |
| ChosenObjectInfoList chosen_object_info_list)> |
| set_permission_info_callback_; |
| }; |
| |
| class PageInfoTest : public ChromeRenderViewHostTestHarness { |
| public: |
| PageInfoTest() { SetURL("http://www.example.com"); } |
| |
| ~PageInfoTest() override = default; |
| |
| void SetUp() override { |
| // TODO(crbug.com/40231917): Fix tests and enable the feature. |
| scoped_feature_list_.InitWithFeatures( |
| { |
| #if !BUILDFLAG(IS_ANDROID) |
| features::kFileSystemAccessPersistentPermissions, |
| #endif |
| }, |
| {}); |
| |
| ChromeRenderViewHostTestHarness::SetUp(); |
| |
| // Setup stub security info. |
| security_level_ = security_state::NONE; |
| |
| // Create the certificate. |
| cert_ = |
| net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); |
| ASSERT_TRUE(cert_); |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| fake_user_manager_->AddUserWithAffiliation( |
| AccountId::FromUserEmail(profile()->GetProfileUserName()), |
| /*is_affiliated=*/true); |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| CreateWebContentsUserData(web_contents()); |
| |
| // Setup mock ui. |
| ResetMockUI(); |
| } |
| |
| void TearDown() override { |
| ASSERT_TRUE(page_info_ || incognito_page_info_) |
| << "No PageInfo instance created."; |
| incognito_web_contents_.reset(); |
| page_info_.reset(); |
| incognito_page_info_.reset(); |
| ChromeRenderViewHostTestHarness::TearDown(); |
| } |
| |
| TestingProfile::TestingFactories GetTestingFactories() const override { |
| return {TestingProfile::TestingFactory{ |
| StatefulSSLHostStateDelegateFactory::GetInstance(), |
| StatefulSSLHostStateDelegateFactory::GetDefaultFactoryForTesting()}}; |
| } |
| |
| void SetDefaultUIExpectations(MockPageInfoUI* mock_ui) { |
| // During creation |PageInfo| makes the following calls to the ui. |
| EXPECT_CALL(*mock_ui, SetPermissionInfoStub()); |
| EXPECT_CALL(*mock_ui, SetIdentityInfo(_)); |
| ExpectInitialSetCookieInfoCall(mock_ui); |
| } |
| |
| void ExpectInitialSetCookieInfoCall(MockPageInfoUI* mock_ui) { |
| #if !BUILDFLAG(IS_ANDROID) |
| EXPECT_CALL(*mock_ui, SetCookieInfo(_)).Times(1); |
| #else |
| EXPECT_CALL(*mock_ui, SetCookieInfo(_)); |
| #endif |
| } |
| |
| void SetURL(const std::string& url) { |
| url_ = GURL(url); |
| origin_ = url::Origin::Create(url_); |
| } |
| |
| void SetPermissionInfo(const PermissionInfoList& permission_info_list, |
| ChosenObjectInfoList chosen_object_info_list) { |
| last_chosen_object_info_.clear(); |
| for (auto& chosen_object_info : chosen_object_info_list) { |
| last_chosen_object_info_.push_back(std::move(chosen_object_info)); |
| } |
| last_permission_info_list_ = permission_info_list; |
| } |
| |
| void ResetMockUI() { |
| mock_ui_ = std::make_unique<NiceMock<MockPageInfoUI>>(); |
| // Use this rather than gmock's ON_CALL.WillByDefault(Invoke(... because |
| // gmock doesn't handle move-only types well. |
| mock_ui_->set_permission_info_callback_ = base::BindRepeating( |
| &PageInfoTest::SetPermissionInfo, base::Unretained(this)); |
| } |
| |
| void ClearPageInfo() { page_info_.reset(nullptr); } |
| |
| void SetCertToSHA1() { |
| cert_ = |
| net::ImportCertFromFile(net::GetTestCertsDirectory(), "sha1_leaf.pem"); |
| ASSERT_TRUE(cert_); |
| } |
| |
| const GURL& url() const { return url_; } |
| const url::Origin& origin() const { return origin_; } |
| scoped_refptr<net::X509Certificate> cert() { return cert_; } |
| MockPageInfoUI* mock_ui() { return mock_ui_.get(); } |
| const std::vector<std::unique_ptr<PageInfoUI::ChosenObjectInfo>>& |
| last_chosen_object_info() { |
| return last_chosen_object_info_; |
| } |
| const PermissionInfoList& last_permission_info_list() { |
| return last_permission_info_list_; |
| } |
| infobars::ContentInfoBarManager* infobar_manager() { |
| return infobars::ContentInfoBarManager::FromWebContents(web_contents()); |
| } |
| |
| PageInfo* page_info() { |
| if (!page_info_.get()) { |
| auto delegate = std::make_unique<ChromePageInfoDelegate>(web_contents()); |
| delegate->SetSecurityStateForTests(security_level_, |
| visible_security_state_); |
| page_info_ = std::make_unique<PageInfo>(std::move(delegate), |
| web_contents(), url()); |
| base::RunLoop run_loop; |
| page_info_->InitializeUiState(mock_ui(), run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| return page_info_.get(); |
| } |
| |
| content::WebContents* incognito_web_contents() { |
| if (!incognito_web_contents_) { |
| TestingProfile::Builder incognito_profile_builder; |
| incognito_profile_builder.AddTestingFactories(GetTestingFactories()); |
| incognito_profile_builder.BuildIncognito(profile()); |
| |
| incognito_web_contents_ = |
| content::WebContentsTester::CreateTestWebContents( |
| profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), |
| nullptr); |
| CreateWebContentsUserData(incognito_web_contents_.get()); |
| } |
| return incognito_web_contents_.get(); |
| } |
| |
| PageInfo* incognito_page_info() { |
| if (!incognito_page_info_.get()) { |
| incognito_mock_ui_ = std::make_unique<NiceMock<MockPageInfoUI>>(); |
| incognito_mock_ui_->set_permission_info_callback_ = base::BindRepeating( |
| &PageInfoTest::SetPermissionInfo, base::Unretained(this)); |
| |
| auto delegate = |
| std::make_unique<ChromePageInfoDelegate>(incognito_web_contents()); |
| delegate->SetSecurityStateForTests(security_level_, |
| visible_security_state_); |
| incognito_page_info_ = std::make_unique<PageInfo>( |
| std::move(delegate), incognito_web_contents(), url()); |
| base::RunLoop run_loop; |
| incognito_page_info_->InitializeUiState(incognito_mock_ui_.get(), |
| run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| return incognito_page_info_.get(); |
| } |
| |
| void CreateWebContentsUserData(content::WebContents* contents) { |
| // The test WebContents don't have all the helpers attached, so add in the |
| // missing ones needed by these tests. |
| infobars::ContentInfoBarManager::CreateForWebContents(contents); |
| content_settings::PageSpecificContentSettings::CreateForWebContents( |
| contents, |
| std::make_unique<PageSpecificContentSettingsDelegate>(contents)); |
| permissions::PermissionRecoverySuccessRateTracker::CreateForWebContents( |
| contents); |
| } |
| |
| security_state::SecurityLevel security_level_; |
| security_state::VisibleSecurityState visible_security_state_; |
| |
| private: |
| std::unique_ptr<PageInfo> page_info_; |
| std::unique_ptr<MockPageInfoUI> mock_ui_; |
| |
| std::unique_ptr<content::WebContents> incognito_web_contents_; |
| std::unique_ptr<PageInfo> incognito_page_info_; |
| std::unique_ptr<NiceMock<MockPageInfoUI>> incognito_mock_ui_; |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| ChromeLayoutProvider layout_provider_; |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| user_manager::TypedScopedUserManager<ash::FakeChromeUserManager> |
| fake_user_manager_{std::make_unique<ash::FakeChromeUserManager>()}; |
| #endif |
| |
| scoped_refptr<net::X509Certificate> cert_; |
| GURL url_; |
| url::Origin origin_; |
| std::vector<std::unique_ptr<PageInfoUI::ChosenObjectInfo>> |
| last_chosen_object_info_; |
| PermissionInfoList last_permission_info_list_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| void ExpectPermissionInfoList( |
| const std::set<ContentSettingsType>& expected_types, |
| const PermissionInfoList& permissions, |
| const base::Location& location = FROM_HERE) { |
| std::set<ContentSettingsType> actual_types; |
| std::ranges::transform(permissions, |
| std::inserter(actual_types, actual_types.end()), |
| [](const auto& p) { return p.type; }); |
| |
| EXPECT_THAT(actual_types, expected_types) |
| << "(expected at " << location.ToString() << ")"; |
| } |
| |
| } // namespace |
| |
| TEST_F(PageInfoTest, PermissionStringsHaveMidSentenceVersion) { |
| page_info(); |
| for (const PageInfoUI::PermissionUIInfo& info : |
| PageInfoUI::GetContentSettingsUIInfoForTesting()) { |
| std::u16string normal = l10n_util::GetStringUTF16(info.string_id); |
| std::u16string mid_sentence = |
| l10n_util::GetStringUTF16(info.string_id_mid_sentence); |
| switch (info.type) { |
| case ContentSettingsType::MIDI_SYSEX: |
| case ContentSettingsType::NFC: |
| case ContentSettingsType::USB_GUARD: |
| #if !BUILDFLAG(IS_ANDROID) |
| case ContentSettingsType::HID_GUARD: |
| #endif |
| EXPECT_EQ(normal, mid_sentence); |
| break; |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) |
| case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER: |
| EXPECT_NE(normal, mid_sentence); |
| EXPECT_EQ(base::ToLowerASCII(normal), base::ToLowerASCII(mid_sentence)); |
| break; |
| #endif |
| default: |
| EXPECT_NE(normal, mid_sentence); |
| EXPECT_EQ(base::ToLowerASCII(normal), mid_sentence); |
| break; |
| } |
| } |
| } |
| |
| TEST_F(PageInfoTest, NonFactoryDefaultAndRecentlyChangedPermissionsShown) { |
| GURL kEmbedded1("https://embedded1.com"); |
| GURL kEmbedded2("https://embedded2.com"); |
| |
| page_info()->PresentSitePermissionsForTesting(); |
| std::set<ContentSettingsType> expected_visible_permissions; |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // Geolocation is always allowed to pass through to Android-specific logic to |
| // check for DSE settings (so expect 1 item), but isn't actually shown later |
| // on because this test isn't testing with a default search engine origin. |
| expected_visible_permissions.insert(ContentSettingsType::GEOLOCATION); |
| #endif |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Change some default-ask settings away from the default. |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| expected_visible_permissions.insert(ContentSettingsType::GEOLOCATION); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::NOTIFICATIONS, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| expected_visible_permissions.insert(ContentSettingsType::NOTIFICATIONS); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| expected_visible_permissions.insert(ContentSettingsType::MEDIASTREAM_MIC); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::STORAGE_ACCESS, |
| CONTENT_SETTING_ALLOW, |
| url::Origin::Create(kEmbedded1), |
| /*is_one_time=*/false); |
| expected_visible_permissions.insert(ContentSettingsType::STORAGE_ACCESS); |
| #if !BUILDFLAG(IS_ANDROID) |
| page_info()->OnSitePermissionChanged( |
| ContentSettingsType::FILE_SYSTEM_WRITE_GUARD, CONTENT_SETTING_ALLOW, |
| url::Origin::Create(kEmbedded1), |
| /*is_one_time=*/false); |
| expected_visible_permissions.insert( |
| ContentSettingsType::FILE_SYSTEM_WRITE_GUARD); |
| #endif |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| expected_visible_permissions.insert(ContentSettingsType::POPUPS); |
| // Change a default-block setting to a user-preference block instead. |
| page_info()->OnSitePermissionChanged(ContentSettingsType::POPUPS, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| expected_visible_permissions.insert(ContentSettingsType::JAVASCRIPT); |
| // Change a default-allow setting away from the default. |
| page_info()->OnSitePermissionChanged(ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Make sure changing a setting to its default causes it to show up, since it |
| // has been recently changed. |
| expected_visible_permissions.insert(ContentSettingsType::MEDIASTREAM_CAMERA); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_CAMERA, |
| std::nullopt, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Set the Javascript setting to default should keep it shown. |
| page_info()->OnSitePermissionChanged(ContentSettingsType::JAVASCRIPT, |
| /*value=*/std::nullopt, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Change the default setting for Javascript away from the factory default. |
| HostContentSettingsMapFactory::GetForProfile(profile()) |
| ->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_BLOCK); |
| page_info()->PresentSitePermissionsForTesting(); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Change it back to ALLOW, which is its factory default, but has a source |
| // from the user preference (i.e. it counts as non-factory default). |
| page_info()->OnSitePermissionChanged(ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Adding another storage access permission for a different embedded origin |
| // adds an additional entry. |
| page_info()->OnSitePermissionChanged(ContentSettingsType::STORAGE_ACCESS, |
| CONTENT_SETTING_ALLOW, |
| url::Origin::Create(kEmbedded2), |
| /*is_one_time=*/false); |
| EXPECT_EQ(expected_visible_permissions.size() + 1, |
| last_permission_info_list().size()); |
| } |
| |
| TEST_F(PageInfoTest, StorageAccessGrantsAreFiltered) { |
| GURL kEmbedded1("https://embedded1.com"); |
| ContentSettingsType type = ContentSettingsType::STORAGE_ACCESS; |
| |
| std::set<ContentSettingsType> expected_visible_permissions; |
| |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| // First-party exceptions are hidden. |
| map->SetContentSettingDefaultScope(url(), url(), type, CONTENT_SETTING_ALLOW); |
| // First-party-set exceptions are hidden based on their |
| // `decided_by_related_website_sets`. |
| content_settings::ContentSettingConstraints constraint; |
| constraint.set_session_model(content_settings::mojom::SessionModel::DURABLE); |
| constraint.set_decided_by_related_website_sets(true); |
| map->SetContentSettingDefaultScope(kEmbedded1, url(), type, |
| CONTENT_SETTING_ALLOW, constraint); |
| page_info()->PresentSitePermissionsForTesting(); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // Geolocation is always allowed to pass through to Android-specific logic to |
| // check for DSE settings (so expect 1 item), but isn't actually shown later |
| // on because this test isn't testing with a default search engine origin. |
| expected_visible_permissions.insert(ContentSettingsType::GEOLOCATION); |
| #endif |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| map->SetContentSettingDefaultScope(kEmbedded1, url(), type, |
| CONTENT_SETTING_ALLOW); |
| page_info()->PresentSitePermissionsForTesting(); |
| expected_visible_permissions.insert(type); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| } |
| |
| TEST_F(PageInfoTest, StorageAccessGrantsDisplayedWhenDefaultBlocked) { |
| GURL kEmbedded1("https://embedded1.com"); |
| ContentSettingsType type = ContentSettingsType::STORAGE_ACCESS; |
| |
| std::set<ContentSettingsType> expected_visible_permissions; |
| |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| // Nothing is displayed for default permissions. |
| map->SetDefaultContentSetting(type, CONTENT_SETTING_BLOCK); |
| page_info()->PresentSitePermissionsForTesting(); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // Geolocation is always allowed to pass through to Android-specific logic to |
| // check for DSE settings (so expect 1 item), but isn't actually shown later |
| // on because this test isn't testing with a default search engine origin. |
| expected_visible_permissions.insert(ContentSettingsType::GEOLOCATION); |
| #endif |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Until the permission is accessed and blocked. |
| auto* pscs = content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| pscs->OnTwoSitePermissionChanged(ContentSettingsType::STORAGE_ACCESS, |
| net::SchemefulSite(kEmbedded1), |
| CONTENT_SETTING_BLOCK); |
| page_info()->PresentSitePermissionsForTesting(); |
| expected_visible_permissions.insert(type); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| } |
| |
| TEST_F(PageInfoTest, ShowAutograntedRWSPermissions) { |
| std::set<ContentSettingsType> expected_visible_permissions; |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| permissions::features::kShowRelatedWebsiteSetsPermissionGrants); |
| SetURL("https://firstparty.com"); |
| constexpr char kToplevelURL[] = "https://firstparty.com"; |
| constexpr char kEmbeddedURL[] = "https://embedded.com"; |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| content_settings::ContentSettingConstraints constraint; |
| constraint.set_session_model(content_settings::mojom::SessionModel::DURABLE); |
| constraint.set_decided_by_related_website_sets(true); |
| map->SetContentSettingDefaultScope(GURL(kEmbeddedURL), GURL(kToplevelURL), |
| ContentSettingsType::STORAGE_ACCESS, |
| CONTENT_SETTING_BLOCK, constraint); |
| page_info()->PresentSitePermissionsForTesting(); |
| expected_visible_permissions.insert(ContentSettingsType::STORAGE_ACCESS); |
| #if BUILDFLAG(IS_ANDROID) |
| // Geolocation is always allowed to pass through to Android-specific logic to |
| // check for DSE settings (so expect 1 item), but isn't actually shown later |
| // on because this test isn't testing with a default search engine origin. |
| expected_visible_permissions.insert(ContentSettingsType::GEOLOCATION); |
| #endif |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| } |
| |
| TEST_F(PageInfoTest, HideAutograntedRWSPermissions) { |
| std::set<ContentSettingsType> expected_visible_permissions; |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndDisableFeature( |
| permissions::features::kShowRelatedWebsiteSetsPermissionGrants); |
| SetURL("https://firstparty.com"); |
| constexpr char kToplevelURL[] = "https://firstparty.com"; |
| constexpr char kEmbeddedURL[] = "https://embedded.com"; |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| content_settings::ContentSettingConstraints constraint; |
| constraint.set_session_model(content_settings::mojom::SessionModel::DURABLE); |
| constraint.set_decided_by_related_website_sets(true); |
| map->SetContentSettingDefaultScope(GURL(kEmbeddedURL), GURL(kToplevelURL), |
| ContentSettingsType::STORAGE_ACCESS, |
| CONTENT_SETTING_ALLOW, constraint); |
| page_info()->PresentSitePermissionsForTesting(); |
| #if BUILDFLAG(IS_ANDROID) |
| // Geolocation is always allowed to pass through to Android-specific logic to |
| // check for DSE settings (so expect 1 item), but isn't actually shown later |
| // on because this test isn't testing with a default search engine origin. |
| expected_visible_permissions.insert(ContentSettingsType::GEOLOCATION); |
| #endif |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| // TODO(https://crbug.com/421606013): Enable test for Android once the |
| // permission is available for that platform. |
| TEST_F(PageInfoTest, AutoPictureInPicturePermissionShownOnChange) { |
| std::set<ContentSettingsType> expected_visible_permissions; |
| |
| // Enable auto-pip feature. |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| {blink::features::kMediaSessionEnterPictureInPicture}, {}); |
| |
| // Create the tab helper. |
| AutoPictureInPictureTabHelper::CreateForWebContents(web_contents()); |
| |
| // Initially, the permission should not be shown. |
| page_info()->PresentSitePermissionsForTesting(); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // Simulate the page registering for auto-pip. |
| auto* tab_helper = |
| AutoPictureInPictureTabHelper::FromWebContents(web_contents()); |
| std::vector<media_session::mojom::MediaSessionAction> actions; |
| actions.push_back( |
| media_session::mojom::MediaSessionAction::kEnterAutoPictureInPicture); |
| tab_helper->MediaSessionActionsChanged(actions); |
| |
| // Now the permission should be shown. |
| expected_visible_permissions.insert( |
| ContentSettingsType::AUTO_PICTURE_IN_PICTURE); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| // After unregistering, the permission should still be shown. |
| actions.clear(); |
| tab_helper->MediaSessionActionsChanged(actions); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| } |
| #endif // !BUILDFLAG(IS_ANDROID) |
| |
| TEST_F(PageInfoTest, IncognitoPermissionsEmptyByDefault) { |
| incognito_page_info()->PresentSitePermissionsForTesting(); |
| EXPECT_EQ(0u, last_permission_info_list().size()); |
| } |
| |
| TEST_F(PageInfoTest, IncognitoPermissionsDontShowAsk) { |
| page_info()->PresentSitePermissionsForTesting(); |
| std::set<ContentSettingsType> expected_permissions; |
| std::set<ContentSettingsType> expected_incognito_permissions; |
| #if BUILDFLAG(IS_ANDROID) |
| // Geolocation is always allowed to pass through to Android-specific logic to |
| // check for DSE settings (so expect 1 item), but isn't actually shown later |
| // on because this test isn't testing with a default search engine origin. |
| expected_permissions.insert(ContentSettingsType::GEOLOCATION); |
| #endif |
| ExpectPermissionInfoList(expected_permissions, last_permission_info_list()); |
| |
| // Add some permissions to regular page info. |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| expected_permissions.insert(ContentSettingsType::MEDIASTREAM_MIC); |
| expected_incognito_permissions.insert(ContentSettingsType::MEDIASTREAM_MIC); |
| |
| // Both permissions should show in regular page info. |
| EXPECT_EQ(2u, last_permission_info_list().size()); |
| |
| // Only the block permissions should show in incognito mode as ALLOW |
| // permissions are inherited as ASK. |
| incognito_page_info()->PresentSitePermissionsForTesting(); |
| ExpectPermissionInfoList(expected_incognito_permissions, |
| last_permission_info_list()); |
| |
| // Changing the permission to BLOCK should show it. |
| incognito_page_info()->OnSitePermissionChanged( |
| ContentSettingsType::GEOLOCATION, CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| expected_incognito_permissions.insert(ContentSettingsType::GEOLOCATION); |
| ExpectPermissionInfoList(expected_incognito_permissions, |
| last_permission_info_list()); |
| |
| // Switching a permission back to default should not hide the permission. |
| incognito_page_info()->OnSitePermissionChanged( |
| ContentSettingsType::GEOLOCATION, /*value=*/std::nullopt, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| ExpectPermissionInfoList(expected_incognito_permissions, |
| last_permission_info_list()); |
| } |
| |
| TEST_F(PageInfoTest, OnPermissionsChanged) { |
| GURL kEmbedded("https://embedded.com"); |
| |
| // Setup site permissions. |
| HostContentSettingsMap* content_settings = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| ContentSetting setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::POPUPS); |
| EXPECT_EQ(setting, CONTENT_SETTING_BLOCK); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::GEOLOCATION); |
| EXPECT_EQ(setting, CONTENT_SETTING_ASK); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::NOTIFICATIONS); |
| EXPECT_EQ(setting, CONTENT_SETTING_ASK); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::MEDIASTREAM_MIC); |
| EXPECT_EQ(setting, CONTENT_SETTING_ASK); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::MEDIASTREAM_CAMERA); |
| EXPECT_EQ(setting, CONTENT_SETTING_ASK); |
| setting = content_settings->GetContentSetting( |
| kEmbedded, url(), ContentSettingsType::STORAGE_ACCESS); |
| EXPECT_EQ(setting, CONTENT_SETTING_ASK); |
| #if !BUILDFLAG(IS_ANDROID) |
| setting = content_settings->GetContentSetting( |
| kEmbedded, url(), ContentSettingsType::FILE_SYSTEM_WRITE_GUARD); |
| EXPECT_EQ(setting, CONTENT_SETTING_ASK); |
| #endif |
| |
| EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); |
| ExpectInitialSetCookieInfoCall(mock_ui()); |
| |
| // SetPermissionInfo() is called once initially, and then again every time |
| // OnSitePermissionChanged() is called. |
| #if !BUILDFLAG(IS_ANDROID) |
| EXPECT_CALL(*mock_ui(), SetPermissionInfoStub()).Times(8); |
| #else |
| EXPECT_CALL(*mock_ui(), SetPermissionInfoStub()).Times(7); |
| #endif |
| |
| // Execute code under tests. |
| page_info()->OnSitePermissionChanged(ContentSettingsType::POPUPS, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::NOTIFICATIONS, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::STORAGE_ACCESS, |
| CONTENT_SETTING_ALLOW, |
| url::Origin::Create(kEmbedded), |
| /*is_one_time=*/false); |
| #if !BUILDFLAG(IS_ANDROID) |
| page_info()->OnSitePermissionChanged( |
| ContentSettingsType::FILE_SYSTEM_WRITE_GUARD, CONTENT_SETTING_ALLOW, |
| url::Origin::Create(kEmbedded), |
| /*is_one_time=*/false); |
| #endif |
| |
| // Verify that the site permissions were changed correctly. |
| setting = content_settings->GetContentSetting(url(), url(), |
| ContentSettingsType::POPUPS); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::GEOLOCATION); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::NOTIFICATIONS); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::MEDIASTREAM_MIC); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| setting = content_settings->GetContentSetting( |
| url(), url(), ContentSettingsType::MEDIASTREAM_CAMERA); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| setting = content_settings->GetContentSetting( |
| kEmbedded, url(), ContentSettingsType::STORAGE_ACCESS); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| #if !BUILDFLAG(IS_ANDROID) |
| setting = content_settings->GetContentSetting( |
| kEmbedded, url(), ContentSettingsType::FILE_SYSTEM_WRITE_GUARD); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| #endif |
| } |
| |
| TEST_F(PageInfoTest, OnChosenObjectDeleted) { |
| // Connect the UsbChooserContext with FakeUsbDeviceManager. |
| device::FakeUsbDeviceManager usb_device_manager; |
| mojo::PendingRemote<device::mojom::UsbDeviceManager> device_manager; |
| usb_device_manager.AddReceiver( |
| device_manager.InitWithNewPipeAndPassReceiver()); |
| UsbChooserContext* store = UsbChooserContextFactory::GetForProfile(profile()); |
| store->SetDeviceManagerForTesting(std::move(device_manager)); |
| |
| auto device_info = usb_device_manager.CreateAndAddDevice( |
| 0, 0, "Google", "Gizmo", "1234567890"); |
| store->GrantDevicePermission(origin(), *device_info); |
| |
| EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); |
| ExpectInitialSetCookieInfoCall(mock_ui()); |
| |
| // Access PageInfo so that SetPermissionInfo is called once to populate |
| // |last_chosen_object_info_|. It will be called again by |
| // OnSiteChosenObjectDeleted. |
| EXPECT_CALL(*mock_ui(), SetPermissionInfoStub()).Times(2); |
| page_info(); |
| |
| ASSERT_EQ(1u, last_chosen_object_info().size()); |
| const PageInfoUI::ChosenObjectInfo* info = last_chosen_object_info()[0].get(); |
| page_info()->OnSiteChosenObjectDeleted( |
| *info->ui_info, base::Value(info->chooser_object->value.Clone())); |
| |
| EXPECT_FALSE(store->HasDevicePermission(origin(), *device_info)); |
| EXPECT_EQ(0u, last_chosen_object_info().size()); |
| } |
| |
| TEST_F(PageInfoTest, Malware) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_MALWARE; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_MALWARE, |
| page_info()->safe_browsing_status()); |
| } |
| |
| TEST_F(PageInfoTest, ManagedPolicyBlock) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_MANAGED_POLICY_BLOCK; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_MANAGED_POLICY_BLOCK, |
| page_info()->safe_browsing_status()); |
| } |
| |
| TEST_F(PageInfoTest, ManagedPolicyWarn) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_MANAGED_POLICY_WARN; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_MANAGED_POLICY_WARN, |
| page_info()->safe_browsing_status()); |
| } |
| |
| TEST_F(PageInfoTest, SocialEngineering) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_SOCIAL_ENGINEERING, |
| page_info()->safe_browsing_status()); |
| } |
| |
| TEST_F(PageInfoTest, UnwantedSoftware) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_UNWANTED_SOFTWARE; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_UNWANTED_SOFTWARE, |
| page_info()->safe_browsing_status()); |
| } |
| |
| #if BUILDFLAG(FULL_SAFE_BROWSING) |
| TEST_F(PageInfoTest, SignInPasswordReuse) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_SIGNED_IN_SYNC_PASSWORD_REUSE; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_SIGNED_IN_SYNC_PASSWORD_REUSE, |
| page_info()->safe_browsing_status()); |
| } |
| |
| TEST_F(PageInfoTest, SavedPasswordReuse) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_SAVED_PASSWORD_REUSE; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_SAVED_PASSWORD_REUSE, |
| page_info()->safe_browsing_status()); |
| } |
| |
| TEST_F(PageInfoTest, EnterprisePasswordReuse) { |
| security_level_ = security_state::DANGEROUS; |
| visible_security_state_.malicious_content_status = |
| security_state::MALICIOUS_CONTENT_STATUS_ENTERPRISE_PASSWORD_REUSE; |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SAFE_BROWSING_STATUS_ENTERPRISE_PASSWORD_REUSE, |
| page_info()->safe_browsing_status()); |
| } |
| #endif |
| |
| TEST_F(PageInfoTest, HTTPConnection) { |
| SetDefaultUIExpectations(mock_ui()); |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_NO_CERT, |
| page_info()->site_identity_status()); |
| } |
| |
| TEST_F(PageInfoTest, HTTPSConnection) { |
| security_level_ = security_state::SECURE; |
| visible_security_state_.url = GURL("https://scheme-is-cryptographic.test"); |
| visible_security_state_.certificate = cert(); |
| visible_security_state_.cert_status = 0; |
| int status = 0; |
| status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); |
| status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); |
| visible_security_state_.connection_status = status; |
| visible_security_state_.connection_info_initialized = true; |
| |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_CERT, |
| page_info()->site_identity_status()); |
| } |
| |
| // Define some dummy constants for Android-only resources. |
| #if !BUILDFLAG(IS_ANDROID) |
| #define IDR_PAGEINFO_BAD 0 |
| #endif |
| |
| TEST_F(PageInfoTest, InsecureContent) { |
| struct TestCase { |
| security_state::SecurityLevel security_level; |
| net::CertStatus cert_status; |
| bool ran_mixed_content; |
| bool displayed_mixed_content; |
| bool contained_mixed_form; |
| bool ran_content_with_cert_errors; |
| bool displayed_content_with_cert_errors; |
| PageInfo::SiteConnectionStatus expected_site_connection_status; |
| PageInfo::SiteIdentityStatus expected_site_identity_status; |
| }; |
| |
| const TestCase kTestCases[] = { |
| // Passive mixed content. |
| {security_state::NONE, 0, false /* ran_mixed_content */, |
| true /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Passive mixed content with a nonsecure form. The nonsecure form is the |
| // more severe problem. |
| {security_state::NONE, 0, false /* ran_mixed_content */, |
| true /* displayed_mixed_content */, true, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Only nonsecure form. |
| {security_state::NONE, 0, false /* ran_mixed_content */, |
| false /* displayed_mixed_content */, true, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Passive mixed content with a cert error on the main resource. |
| {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, |
| false /* ran_mixed_content */, true /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_ERROR}, |
| // Active and passive mixed content. |
| {security_state::DANGEROUS, 0, true /* ran_mixed_content */, |
| true /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Active mixed content and nonsecure form. |
| {security_state::DANGEROUS, 0, true /* ran_mixed_content */, |
| true /* displayed_mixed_content */, true, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Active and passive mixed content with a cert error on the main |
| // resource. |
| {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, |
| true /* ran_mixed_content */, true /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_ERROR}, |
| // Active mixed content. |
| {security_state::DANGEROUS, 0, true /* ran_mixed_content */, |
| false /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Active mixed content with a cert error on the main resource. |
| {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, |
| true /* ran_mixed_content */, false /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_ERROR}, |
| |
| // Passive subresources with cert errors. |
| {security_state::NONE, 0, false /* ran_mixed_content */, |
| false /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| true /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Passive subresources with cert errors, with a cert error on the |
| // main resource also. In this case, the subresources with |
| // certificate errors are ignored: if the main resource had a cert |
| // error, it's not that useful to warn about subresources with cert |
| // errors as well. |
| {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, |
| false /* ran_mixed_content */, false /* displayed_mixed_content */, |
| false, false /* ran_content_with_cert_errors */, |
| true /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED, |
| PageInfo::SITE_IDENTITY_STATUS_ERROR}, |
| // Passive and active subresources with cert errors. |
| {security_state::DANGEROUS, 0, false /* ran_mixed_content */, |
| false /* displayed_mixed_content */, false, |
| true /* ran_content_with_cert_errors */, |
| true /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Passive and active subresources with cert errors, with a cert |
| // error on the main resource also. |
| {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, |
| false /* ran_mixed_content */, false /* displayed_mixed_content */, |
| false, true /* ran_content_with_cert_errors */, |
| true /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED, |
| PageInfo::SITE_IDENTITY_STATUS_ERROR}, |
| // Active subresources with cert errors. |
| {security_state::DANGEROUS, 0, false /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, false, |
| true /* ran_mixed_content */, false /* displayed_mixed_content */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Active subresources with cert errors, with a cert error on the main |
| // resource also. |
| {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, |
| false /* ran_mixed_content */, false /* displayed_mixed_content */, |
| false, true /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED, |
| PageInfo::SITE_IDENTITY_STATUS_ERROR}, |
| |
| // Passive mixed content and subresources with cert errors. |
| {security_state::NONE, 0, false /* ran_content_with_cert_errors */, |
| true /* displayed_content_with_cert_errors */, false, |
| false /* ran_mixed_content */, true /* displayed_mixed_content */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Passive mixed content, a nonsecure form, and subresources with cert |
| // errors. |
| {security_state::NONE, 0, false /* ran_mixed_content */, |
| true /* displayed_mixed_content */, true, |
| false /* ran_content_with_cert_errors */, |
| true /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Passive mixed content and active subresources with cert errors. |
| {security_state::DANGEROUS, 0, false /* ran_mixed_content */, |
| true /* displayed_mixed_content */, false, |
| true /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Active mixed content and passive subresources with cert errors. |
| {security_state::DANGEROUS, 0, true /* ran_mixed_content */, |
| false /* displayed_mixed_content */, false, |
| false /* ran_content_with_cert_errors */, |
| true /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_CERT}, |
| // Passive mixed content, active subresources with cert errors, and a cert |
| // error on the main resource. |
| {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, |
| false /* ran_mixed_content */, true /* displayed_mixed_content */, false, |
| true /* ran_content_with_cert_errors */, |
| false /* displayed_content_with_cert_errors */, |
| PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, |
| PageInfo::SITE_IDENTITY_STATUS_ERROR}, |
| }; |
| |
| for (const auto& test : kTestCases) { |
| ClearPageInfo(); |
| ResetMockUI(); |
| security_level_ = test.security_level; |
| visible_security_state_.url = GURL("https://scheme-is-cryptographic.test"); |
| visible_security_state_.certificate = cert(); |
| visible_security_state_.cert_status = test.cert_status; |
| visible_security_state_.displayed_mixed_content = |
| test.displayed_mixed_content; |
| visible_security_state_.ran_mixed_content = test.ran_mixed_content; |
| visible_security_state_.contained_mixed_form = test.contained_mixed_form; |
| visible_security_state_.displayed_content_with_cert_errors = |
| test.displayed_content_with_cert_errors; |
| visible_security_state_.ran_content_with_cert_errors = |
| test.ran_content_with_cert_errors; |
| int status = 0; |
| status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); |
| status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); |
| visible_security_state_.connection_status = status; |
| visible_security_state_.connection_info_initialized = true; |
| |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(test.expected_site_connection_status, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(test.expected_site_identity_status, |
| page_info()->site_identity_status()); |
| } |
| } |
| |
| TEST_F(PageInfoTest, HTTPSEVCert) { |
| scoped_refptr<net::X509Certificate> ev_cert = |
| net::X509Certificate::CreateFromBytes(google_der); |
| ASSERT_TRUE(ev_cert); |
| |
| security_level_ = security_state::NONE; |
| visible_security_state_.url = GURL("https://scheme-is-cryptographic.test"); |
| visible_security_state_.certificate = ev_cert; |
| visible_security_state_.cert_status = net::CERT_STATUS_IS_EV; |
| visible_security_state_.displayed_mixed_content = true; |
| int status = 0; |
| status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); |
| status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); |
| visible_security_state_.connection_status = status; |
| visible_security_state_.connection_info_initialized = true; |
| |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_EV_CERT, |
| page_info()->site_identity_status()); |
| } |
| |
| TEST_F(PageInfoTest, HTTPSConnectionError) { |
| security_level_ = security_state::SECURE; |
| visible_security_state_.url = GURL("https://scheme-is-cryptographic.test"); |
| visible_security_state_.certificate = cert(); |
| visible_security_state_.cert_status = 0; |
| int status = 0; |
| status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); |
| status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); |
| visible_security_state_.connection_status = status; |
| |
| // Simulate a failed connection. |
| visible_security_state_.connection_info_initialized = false; |
| |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_CERT, |
| page_info()->site_identity_status()); |
| } |
| |
| TEST_F(PageInfoTest, HTTPSSHA1) { |
| SetCertToSHA1(); |
| security_level_ = security_state::NONE; |
| visible_security_state_.url = GURL("https://scheme-is-cryptographic.test"); |
| visible_security_state_.certificate = cert(); |
| visible_security_state_.cert_status = net::CERT_STATUS_SHA1_SIGNATURE_PRESENT; |
| int status = 0; |
| status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1); |
| status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256); |
| visible_security_state_.connection_status = status; |
| visible_security_state_.connection_info_initialized = true; |
| |
| SetDefaultUIExpectations(mock_ui()); |
| |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM, |
| page_info()->site_identity_status()); |
| #if BUILDFLAG(IS_ANDROID) |
| EXPECT_EQ(IDR_PAGEINFO_BAD, |
| PageInfoUI::GetIdentityIconID(page_info()->site_identity_status())); |
| #endif |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| TEST_F(PageInfoTest, NoInfoBar) { |
| SetDefaultUIExpectations(mock_ui()); |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| bool unused; |
| page_info()->OnUIClosing(&unused); |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| } |
| |
| TEST_F(PageInfoTest, ShowInfoBar) { |
| EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); |
| ExpectInitialSetCookieInfoCall(mock_ui()); |
| |
| EXPECT_CALL(*mock_ui(), SetPermissionInfoStub()).Times(2); |
| |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| bool unused; |
| page_info()->OnUIClosing(&unused); |
| ASSERT_EQ(1u, infobar_manager()->infobars().size()); |
| |
| infobar_manager()->RemoveInfoBar(infobar_manager()->infobars()[0]); |
| } |
| |
| TEST_F(PageInfoTest, NoInfoBarWhenSoundSettingChanged) { |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| page_info()->OnSitePermissionChanged( |
| ContentSettingsType::SOUND, CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, /*is_one_time=*/false); |
| bool unused; |
| page_info()->OnUIClosing(&unused); |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| } |
| |
| TEST_F(PageInfoTest, ShowInfoBarWhenSoundSettingAndAnotherSettingChanged) { |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged( |
| ContentSettingsType::SOUND, CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, /*is_one_time=*/false); |
| bool unused; |
| page_info()->OnUIClosing(&unused); |
| EXPECT_EQ(1u, infobar_manager()->infobars().size()); |
| |
| infobar_manager()->RemoveInfoBar(infobar_manager()->infobars()[0]); |
| } |
| |
| TEST_F(PageInfoTest, ShowInfobarWhenMediaChanged) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| HostContentSettingsMap* map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_BLOCK); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_BLOCK); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(1u, infobar_manager()->infobars().size()); |
| |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.VideoCapture.ReloadInfobarShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.AudioCapture.ReloadInfobarShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| } |
| |
| // Camera and Mic permissions should suppress the infobar when changed to BLOCK. |
| TEST_F(PageInfoTest, SuppressInfobarWhenMediaChangedToBlock) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| // The infobar can be suppressed only if an origin subscribed to permission |
| // status change. |
| page_info()->SetSubscribedToPermissionChangeForTesting(); |
| HostContentSettingsMap* map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_BLOCK); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_BLOCK); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.VideoCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.AudioCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| } |
| |
| TEST_F(PageInfoTest, SuppressInfobarWhenMediaChangedToAllow) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| // The infobar can be suppressed only if an origin subscribed to permission |
| // status change. |
| page_info()->SetSubscribedToPermissionChangeForTesting(); |
| |
| HostContentSettingsMap* map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_BLOCK); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_BLOCK); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.VideoCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.AudioCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| } |
| |
| // Camera and Mic permissions should suppress the infobar when changed to |
| // DEFAULT. |
| TEST_F(PageInfoTest, SuppressInfobarWhenMediaChangedToDefault) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| HostContentSettingsMap* map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_BLOCK); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_BLOCK); |
| |
| // The infobar can be suppressed only if an origin subscribed to permission |
| // status change. |
| page_info()->SetSubscribedToPermissionChangeForTesting(); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_CAMERA, |
| std::nullopt, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| std::nullopt, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.VideoCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::RESET_FROM_DENIED, 1); |
| |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.AudioCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::RESET_FROM_DENIED, 1); |
| } |
| |
| // Only Camera and Mic permissions can suppress the infobar. |
| TEST_F(PageInfoTest, ShowInfobarWhenGeolocationChangedToAllow) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| HostContentSettingsMap* map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| map->SetContentSettingDefaultScope( |
| url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_BLOCK); |
| |
| // The infobar can be suppressed only if an origin subscribed to permission |
| // status change. |
| page_info()->SetSubscribedToPermissionChangeForTesting(); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(1u, infobar_manager()->infobars().size()); |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.Geolocation.ReloadInfobarShown", |
| permissions::PermissionChangeAction::REALLOWED, 0); |
| } |
| |
| // Geolocation permission change to BLOCK should show the infobar. Only |
| // Camera & Mic should suppress the infobar when changed. |
| TEST_F(PageInfoTest, NotSuppressedInfobarWhenGeolocationChangedToBlock) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| // The infobar can be suppressed only if an origin subscribed to permission |
| // status change. |
| page_info()->SetSubscribedToPermissionChangeForTesting(); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(1u, infobar_manager()->infobars().size()); |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.Geolocation.ReloadInfobarShown", |
| permissions::PermissionChangeAction::REVOKED, 0); |
| } |
| |
| TEST_F(PageInfoTest, ShowInfobarWhenGeolocationChangedToDefault) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| // The infobar can be suppressed only if an origin subscribed to permission |
| // status change. |
| page_info()->SetSubscribedToPermissionChangeForTesting(); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| /*value=*/std::nullopt, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(1u, infobar_manager()->infobars().size()); |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.Geolocation.ReloadInfobarShown", |
| permissions::PermissionChangeAction::RESET_FROM_ALLOWED, 0); |
| } |
| |
| // If at least one permission requires to show the infobar, we show it. |
| TEST_F(PageInfoTest, ShowInfobarWhenGeolocationAndMediaChangedToBlock) { |
| base::HistogramTester histograms; |
| |
| ASSERT_EQ(0u, infobar_manager()->infobars().size()); |
| |
| HostContentSettingsMap* map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_BLOCK); |
| map->SetContentSettingDefaultScope(url(), url(), |
| ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_BLOCK); |
| |
| // The infobar can be suppressed only if an origin subscribed to permission |
| // status change. |
| page_info()->SetSubscribedToPermissionChangeForTesting(); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::GEOLOCATION, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_CAMERA, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| page_info()->OnSitePermissionChanged(ContentSettingsType::MEDIASTREAM_MIC, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| page_info()->OnUIClosing(nullptr); |
| EXPECT_EQ(1u, infobar_manager()->infobars().size()); |
| |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.Geolocation.ReloadInfobarShown", |
| permissions::PermissionChangeAction::REVOKED, 0); |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.VideoCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| histograms.ExpectUniqueSample( |
| "Permissions.PageInfo.Changed.AudioCapture.ReloadInfobarNotShown", |
| permissions::PermissionChangeAction::REALLOWED, 1); |
| } |
| |
| TEST_F(PageInfoTest, ShowInfoBarWhenAllowingThirdPartyCookies) { |
| SetDefaultUIExpectations(mock_ui()); |
| NavigateAndCommit(url()); |
| |
| // Calls to `PresentSiteDataInternal` from `PresentSiteData` are synchronous |
| // which makes calls to `SetCookieInfo` appear as they're called. |
| // This call is needed to satisfy the default expectations after navigation. |
| page_info(); |
| Mock::VerifyAndClearExpectations(mock_ui()); |
| // `SetCookieInfo` is called once through `OnStatusChanged` and another time |
| // through `OnThirdPartyToggleClicked` which calls `OnStatusChanged` down |
| // its call chain. |
| EXPECT_CALL(*mock_ui(), SetCookieInfo(_)).Times(2); |
| |
| page_info()->OnStatusChanged(CookieControlsState::kBlocked3pc, |
| CookieControlsEnforcement::kNoEnforcement, |
| CookieBlocking3pcdStatus::kNotIn3pcd, |
| base::Time()); |
| |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| page_info()->OnThirdPartyToggleClicked(/*block_third_party_cookies=*/false); |
| page_info()->OnUIClosing(nullptr); |
| ASSERT_EQ(1u, infobar_manager()->infobars().size()); |
| |
| infobar_manager()->RemoveInfoBar(infobar_manager()->infobars()[0]); |
| } |
| |
| TEST_F(PageInfoTest, ShowInfoBarWhenBlockingThirdPartyCookies) { |
| SetDefaultUIExpectations(mock_ui()); |
| NavigateAndCommit(url()); |
| |
| // As in `ShowInfoBarWhenAllowingThirdPartyCookies` above, expectations need |
| // to be cleared. |
| page_info(); |
| Mock::VerifyAndClearExpectations(mock_ui()); |
| EXPECT_CALL(*mock_ui(), SetCookieInfo(_)).Times(2); |
| |
| page_info()->OnStatusChanged(CookieControlsState::kAllowed3pc, |
| CookieControlsEnforcement::kNoEnforcement, |
| CookieBlocking3pcdStatus::kNotIn3pcd, |
| base::Time()); |
| |
| EXPECT_EQ(0u, infobar_manager()->infobars().size()); |
| page_info()->OnThirdPartyToggleClicked(/*block_third_party_cookies=*/true); |
| page_info()->OnUIClosing(nullptr); |
| ASSERT_EQ(1u, infobar_manager()->infobars().size()); |
| |
| infobar_manager()->RemoveInfoBar(infobar_manager()->infobars()[0]); |
| } |
| |
| #endif |
| |
| TEST_F(PageInfoTest, AboutBlankPage) { |
| SetURL(url::kAboutBlankURL); |
| SetDefaultUIExpectations(mock_ui()); |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_NO_CERT, |
| page_info()->site_identity_status()); |
| } |
| |
| // On desktop, internal URLs aren't handled by PageInfo class. Instead, a |
| // custom and simpler bubble is shown, so no need to test. |
| #if BUILDFLAG(IS_ANDROID) |
| TEST_F(PageInfoTest, InternalPage) { |
| SetURL("chrome://bookmarks"); |
| SetDefaultUIExpectations(mock_ui()); |
| EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_INTERNAL_PAGE, |
| page_info()->site_connection_status()); |
| EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE, |
| page_info()->site_identity_status()); |
| } |
| #endif |
| |
| // Tests that "Re-Enable Warnings" button on PageInfo both removes certificate |
| // exceptions and logs metrics correctly. |
| TEST_F(PageInfoTest, ReEnableWarnings) { |
| struct TestCase { |
| const std::string url; |
| const bool button_visible; |
| const bool button_clicked; |
| }; |
| |
| const TestCase kTestCases[] = { |
| {"https://example.test", false, false}, |
| {"https://example.test", true, false}, |
| {"https://example.test", true, true}, |
| }; |
| const char kGenericHistogram[] = |
| "interstitial.ssl.did_user_revoke_decisions2"; |
| auto* storage_partition = |
| web_contents()->GetPrimaryMainFrame()->GetStoragePartition(); |
| for (const auto& test : kTestCases) { |
| base::HistogramTester histograms; |
| StatefulSSLHostStateDelegate* ssl_state = |
| StatefulSSLHostStateDelegateFactory::GetForProfile(profile()); |
| const std::string host = GURL(test.url).host(); |
| |
| ssl_state->RevokeUserAllowExceptionsHard(host); |
| ResetMockUI(); |
| SetURL(test.url); |
| if (test.button_visible) { |
| // In the case where the button should be visible, add an exception to |
| // the profile settings for the site (since the exception is what |
| // will make the button visible). |
| ssl_state->AllowCert(host, *cert(), net::ERR_CERT_DATE_INVALID, |
| storage_partition); |
| page_info(); |
| if (test.button_clicked) { |
| page_info()->OnRevokeSSLErrorBypassButtonPressed(); |
| EXPECT_FALSE(ssl_state->HasAllowException(host, storage_partition)); |
| ClearPageInfo(); |
| histograms.ExpectTotalCount(kGenericHistogram, 1); |
| histograms.ExpectBucketCount( |
| kGenericHistogram, |
| PageInfo::SSLCertificateDecisionsDidRevoke:: |
| USER_CERT_DECISIONS_REVOKED, |
| 1); |
| } else { // Case where button is visible but not clicked. |
| ClearPageInfo(); |
| EXPECT_TRUE(ssl_state->HasAllowException(host, storage_partition)); |
| histograms.ExpectTotalCount(kGenericHistogram, 1); |
| histograms.ExpectBucketCount( |
| kGenericHistogram, |
| PageInfo::SSLCertificateDecisionsDidRevoke:: |
| USER_CERT_DECISIONS_NOT_REVOKED, |
| 1); |
| } |
| } else { |
| page_info(); |
| ClearPageInfo(); |
| EXPECT_FALSE(ssl_state->HasAllowException(host, storage_partition)); |
| // Button is not visible, so check histogram is empty after opening and |
| // closing page info. |
| histograms.ExpectTotalCount(kGenericHistogram, 0); |
| } |
| } |
| // Test class expects PageInfo to exist during Teardown. |
| page_info(); |
| } |
| |
| // Tests that the duration of time the PageInfo is open is recorded for pages |
| // with various security levels. |
| TEST_F(PageInfoTest, TimeOpenMetrics) { |
| struct TestCase { |
| const std::string url; |
| const security_state::SecurityLevel security_level; |
| const std::string security_level_name; |
| const page_info::PageInfoAction action; |
| }; |
| |
| const std::string kHistogramPrefix("Security.PageInfo.TimeOpen."); |
| |
| const TestCase kTestCases[] = { |
| // PAGE_INFO_OPENED used as shorthand for "take no action". |
| {"https://example.test", security_state::SECURE, "SECURE", |
| page_info::PAGE_INFO_OPENED}, |
| {"http://example.test", security_state::NONE, "NONE", |
| page_info::PAGE_INFO_OPENED}, |
| {"https://example.test", security_state::SECURE, "SECURE", |
| page_info::PAGE_INFO_SITE_SETTINGS_OPENED}, |
| {"http://example.test", security_state::NONE, "NONE", |
| page_info::PAGE_INFO_SITE_SETTINGS_OPENED}, |
| }; |
| |
| for (const auto& test : kTestCases) { |
| base::HistogramTester histograms; |
| SetURL(test.url); |
| security_level_ = test.security_level; |
| ResetMockUI(); |
| ClearPageInfo(); |
| SetDefaultUIExpectations(mock_ui()); |
| |
| histograms.ExpectTotalCount(kHistogramPrefix + test.security_level_name, 0); |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "Action." + test.security_level_name, 0); |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "NoAction." + test.security_level_name, 0); |
| |
| PageInfo* test_page_info = page_info(); |
| if (test.action != page_info::PAGE_INFO_OPENED) { |
| test_page_info->RecordPageInfoAction(test.action); |
| } |
| ClearPageInfo(); |
| |
| histograms.ExpectTotalCount(kHistogramPrefix + test.security_level_name, 1); |
| |
| if (test.action != page_info::PAGE_INFO_OPENED) { |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "Action." + test.security_level_name, 1); |
| } else { |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "NoAction." + test.security_level_name, 1); |
| } |
| } |
| |
| // PageInfoTest expects a valid PageInfo instance to exist at end of test. |
| ResetMockUI(); |
| SetDefaultUIExpectations(mock_ui()); |
| page_info(); |
| } |
| |
| TEST_F(PageInfoTest, AdPersonalization) { |
| constexpr int kTaxonomyVersion = 1; |
| privacy_sandbox::CanonicalTopic kFirstTopic( |
| browsing_topics::Topic(24), // "Blues" |
| kTaxonomyVersion); |
| privacy_sandbox::CanonicalTopic kSecondTopic( |
| browsing_topics::Topic(23), // "Music & audio" |
| kTaxonomyVersion); |
| |
| std::vector<privacy_sandbox::CanonicalTopic> accessed_topics = {kFirstTopic, |
| kSecondTopic}; |
| EXPECT_CALL(*mock_ui(), |
| SetAdPersonalizationInfo(::testing::Field( |
| &PageInfoUI::AdPersonalizationInfo::accessed_topics, |
| accessed_topics))); |
| |
| content_settings::PageSpecificContentSettings* pscs = |
| content_settings::PageSpecificContentSettings::GetForFrame( |
| web_contents()->GetPrimaryMainFrame()); |
| EXPECT_FALSE(pscs->HasAccessedTopics()); |
| EXPECT_THAT(pscs->GetAccessedTopics(), testing::IsEmpty()); |
| |
| pscs->OnTopicAccessed(url::Origin::Create(GURL("https://foo.com")), false, |
| kSecondTopic); |
| pscs->OnTopicAccessed(url::Origin::Create(GURL("https://foo.com")), false, |
| kFirstTopic); |
| page_info(); |
| } |
| |
| // Tests that metrics are recorded on a PageInfo for pages with |
| // various Safety Tip statuses. |
| // See https://crbug.com/1114659 for why the test is disabled on Android. |
| #if BUILDFLAG(IS_ANDROID) |
| #define MAYBE_SafetyTipMetrics DISABLED_SafetyTipMetrics |
| #else |
| #define MAYBE_SafetyTipMetrics SafetyTipMetrics |
| #endif |
| TEST_F(PageInfoTest, MAYBE_SafetyTipMetrics) { |
| struct TestCase { |
| const security_state::SafetyTipInfo safety_tip_info; |
| }; |
| const char kGenericHistogram[] = "WebsiteSettings.Action"; |
| |
| const TestCase kTestCases[] = { |
| {{security_state::SafetyTipStatus::kNone, GURL()}}, |
| {{security_state::SafetyTipStatus::kLookalike, GURL()}}, |
| }; |
| |
| for (const auto& test : kTestCases) { |
| base::HistogramTester histograms; |
| SetURL("https://example.test"); |
| visible_security_state_.safety_tip_info = test.safety_tip_info; |
| ClearPageInfo(); |
| ResetMockUI(); |
| SetDefaultUIExpectations(mock_ui()); |
| |
| histograms.ExpectTotalCount(kGenericHistogram, 0); |
| |
| page_info()->RecordPageInfoAction(page_info::PAGE_INFO_OPENED); |
| |
| // RecordPageInfoAction() is called during PageInfo |
| // creation in addition to the explicit RecordPageInfoAction() |
| // call, so it is called twice in total. |
| histograms.ExpectTotalCount(kGenericHistogram, 2); |
| histograms.ExpectBucketCount(kGenericHistogram, page_info::PAGE_INFO_OPENED, |
| 2); |
| } |
| } |
| |
| // Tests that the duration of time the PageInfo is open is recorded for pages |
| // with various Safety Tip statuses. |
| TEST_F(PageInfoTest, SafetyTipTimeOpenMetrics) { |
| struct TestCase { |
| const security_state::SafetyTipStatus safety_tip_status; |
| const std::string safety_tip_status_name; |
| const page_info::PageInfoAction action; |
| }; |
| |
| const std::string kHistogramPrefix("Security.PageInfo.TimeOpen."); |
| |
| const TestCase kTestCases[] = { |
| // PAGE_INFO_COUNT used as shorthand for "take no action". |
| {security_state::SafetyTipStatus::kNone, "SafetyTip_None", |
| page_info::PAGE_INFO_OPENED}, |
| {security_state::SafetyTipStatus::kLookalike, "SafetyTip_Lookalike", |
| page_info::PAGE_INFO_OPENED}, |
| {security_state::SafetyTipStatus::kNone, "SafetyTip_None", |
| page_info::PAGE_INFO_SITE_SETTINGS_OPENED}, |
| {security_state::SafetyTipStatus::kLookalike, "SafetyTip_Lookalike", |
| page_info::PAGE_INFO_SITE_SETTINGS_OPENED}, |
| }; |
| |
| for (const auto& test : kTestCases) { |
| base::HistogramTester histograms; |
| SetURL("https://example.test"); |
| visible_security_state_.safety_tip_info.status = test.safety_tip_status; |
| ResetMockUI(); |
| ClearPageInfo(); |
| SetDefaultUIExpectations(mock_ui()); |
| |
| histograms.ExpectTotalCount(kHistogramPrefix + test.safety_tip_status_name, |
| 0); |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "Action." + test.safety_tip_status_name, 0); |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "NoAction." + test.safety_tip_status_name, 0); |
| |
| PageInfo* test_page_info = page_info(); |
| if (test.action != page_info::PAGE_INFO_OPENED) { |
| test_page_info->RecordPageInfoAction(test.action); |
| } |
| ClearPageInfo(); |
| |
| histograms.ExpectTotalCount(kHistogramPrefix + test.safety_tip_status_name, |
| 1); |
| |
| if (test.action != page_info::PAGE_INFO_OPENED) { |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "Action." + test.safety_tip_status_name, 1); |
| } else { |
| histograms.ExpectTotalCount( |
| kHistogramPrefix + "NoAction." + test.safety_tip_status_name, 1); |
| } |
| } |
| |
| // PageInfoTest expects a valid PageInfo instance to exist at end of test. |
| ResetMockUI(); |
| SetDefaultUIExpectations(mock_ui()); |
| page_info(); |
| } |
| |
| // Tests that the SubresourceFilter setting is omitted correctly. |
| TEST_F(PageInfoTest, SubresourceFilterSetting_MatchesActivation) { |
| auto showing_setting = [](const PermissionInfoList& permissions) { |
| return base::Contains( |
| permissions, ContentSettingsType::ADS, |
| [](const auto& permission) { return permission.type; }); |
| }; |
| |
| // By default, the setting should not appear at all. |
| SetURL("https://example.test/"); |
| SetDefaultUIExpectations(mock_ui()); |
| page_info(); |
| EXPECT_FALSE(showing_setting(last_permission_info_list())); |
| |
| // Reset state. |
| ClearPageInfo(); |
| ResetMockUI(); |
| SetDefaultUIExpectations(mock_ui()); |
| |
| // Now, explicitly set site activation metadata to simulate activation on |
| // that origin, which is encoded by the existence of the website setting. The |
| // setting should then appear in page_info. |
| subresource_filter::SubresourceFilterContentSettingsManager* |
| settings_manager = |
| SubresourceFilterProfileContextFactory::GetForProfile(profile()) |
| ->settings_manager(); |
| settings_manager->SetSiteMetadataBasedOnActivation( |
| url(), true, |
| subresource_filter::SubresourceFilterContentSettingsManager:: |
| ActivationSource::kSafeBrowsing); |
| |
| page_info(); |
| EXPECT_TRUE(showing_setting(last_permission_info_list())); |
| } |
| |
| // Tests that permissions substring is empty if permission is blocked. |
| TEST_F(PageInfoTest, PermissionBlockedStrings) { |
| SetURL("https://example.com/"); |
| page_info(); |
| |
| auto web_contents = |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr); |
| ChromePageInfoUiDelegate delegate(web_contents.get(), |
| GURL("http://www.example.com")); |
| |
| PageInfo::PermissionInfo camera_permission; |
| camera_permission.type = ContentSettingsType::MEDIASTREAM_CAMERA; |
| camera_permission.setting = CONTENT_SETTING_BLOCK; |
| camera_permission.default_setting = CONTENT_SETTING_ASK; |
| camera_permission.source = SettingSource::kUser; |
| camera_permission.is_one_time = false; |
| |
| EXPECT_EQ(std::u16string(), PageInfoUI::PermissionMainPageStateToUIString( |
| &delegate, camera_permission)); |
| } |
| |
| // Tests that permissions substring says "Using now" if permission is in use. |
| TEST_F(PageInfoTest, PermissionUsingNowStrings) { |
| SetURL("https://example.com/"); |
| page_info(); |
| |
| auto web_contents = |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr); |
| ChromePageInfoUiDelegate delegate(web_contents.get(), |
| GURL("http://www.example.com")); |
| |
| PageInfo::PermissionInfo camera_permission; |
| camera_permission.type = ContentSettingsType::MEDIASTREAM_CAMERA; |
| camera_permission.setting = CONTENT_SETTING_ALLOW; |
| camera_permission.default_setting = CONTENT_SETTING_ASK; |
| camera_permission.source = SettingSource::kUser; |
| camera_permission.is_one_time = false; |
| camera_permission.is_in_use = true; |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_PERMISSION_USING_NOW), |
| PageInfoUI::PermissionMainPageStateToUIString(&delegate, |
| camera_permission)); |
| } |
| |
| // Tests that permissions substring says "Recently used" if permission was used |
| // less than 1 minute ago. |
| TEST_F(PageInfoTest, PermissionRecentlyUsedStrings) { |
| SetURL("https://example.com/"); |
| page_info(); |
| |
| auto web_contents = |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr); |
| ChromePageInfoUiDelegate delegate(web_contents.get(), |
| GURL("http://www.example.com")); |
| |
| PageInfo::PermissionInfo camera_permission; |
| camera_permission.type = ContentSettingsType::MEDIASTREAM_CAMERA; |
| camera_permission.setting = CONTENT_SETTING_ALLOW; |
| camera_permission.default_setting = CONTENT_SETTING_ASK; |
| camera_permission.source = SettingSource::kUser; |
| camera_permission.is_one_time = false; |
| camera_permission.is_in_use = false; |
| camera_permission.last_used = base::Time::Now() - base::Seconds(30); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_PERMISSION_RECENTLY_USED), |
| PageInfoUI::PermissionMainPageStateToUIString(&delegate, |
| camera_permission)); |
| } |
| |
| // Tests that permissions substring says "Used X minutes/hours ago" if |
| // permission was used more than 1 minute ago. |
| TEST_F(PageInfoTest, PermissionUsed30MinutesAgoStrings) { |
| SetURL("https://example.com/"); |
| page_info(); |
| |
| auto web_contents = |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr); |
| ChromePageInfoUiDelegate delegate(web_contents.get(), |
| GURL("http://www.example.com")); |
| |
| PageInfo::PermissionInfo camera_permission; |
| camera_permission.type = ContentSettingsType::MEDIASTREAM_CAMERA; |
| camera_permission.setting = CONTENT_SETTING_ALLOW; |
| camera_permission.default_setting = CONTENT_SETTING_ASK; |
| camera_permission.source = SettingSource::kUser; |
| camera_permission.is_one_time = false; |
| camera_permission.is_in_use = false; |
| camera_permission.last_used = base::Time::Now() - base::Minutes(30); |
| |
| EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_PAGE_INFO_PERMISSION_USED_TIME_AGO, |
| u"30 minutes"), |
| PageInfoUI::PermissionMainPageStateToUIString(&delegate, |
| camera_permission)); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| TEST_F(PageInfoTest, AutoPictureInPicturePermissionNotShownIfNotRegistered) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(media::kAutoPictureInPictureAndroid); |
| page_info()->PresentSitePermissionsForTesting(); |
| const auto& permissions = last_permission_info_list(); |
| auto it = |
| std::find_if(permissions.begin(), permissions.end(), [](const auto& p) { |
| return p.type == ContentSettingsType::AUTO_PICTURE_IN_PICTURE; |
| }); |
| // If the site hasn't registered for auto-pip, and the setting is default, |
| // the permission should not be shown. |
| EXPECT_EQ(it, permissions.end()); |
| } |
| |
| TEST_F(PageInfoTest, AutoPictureInPicturePermissionShownIfPreviouslySet) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(media::kAutoPictureInPictureAndroid); |
| |
| // The site is NOT registered for Auto-PiP, but the user has previously set |
| // the permission for this site. |
| HostContentSettingsMap* content_settings = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| content_settings->SetContentSettingDefaultScope( |
| url(), url(), ContentSettingsType::AUTO_PICTURE_IN_PICTURE, |
| CONTENT_SETTING_BLOCK); |
| |
| page_info()->PresentSitePermissionsForTesting(); |
| const auto& permissions = last_permission_info_list(); |
| auto it = |
| std::find_if(permissions.begin(), permissions.end(), [](const auto& p) { |
| return p.type == ContentSettingsType::AUTO_PICTURE_IN_PICTURE; |
| }); |
| |
| // The permission should be shown because it has a non-default setting. |
| ASSERT_NE(it, permissions.end()); |
| EXPECT_EQ(std::get<ContentSetting>(it->setting.value()), |
| CONTENT_SETTING_BLOCK); |
| } |
| |
| TEST_F(PageInfoTest, AutoPictureInPicturePermissionInfoIncognito) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(media::kAutoPictureInPictureAndroid); |
| |
| AutoPictureInPictureTabHelper::CreateForWebContents(incognito_web_contents()); |
| auto* tab_helper = |
| AutoPictureInPictureTabHelper::FromWebContents(incognito_web_contents()); |
| std::vector<media_session::mojom::MediaSessionAction> actions; |
| actions.push_back( |
| media_session::mojom::MediaSessionAction::kEnterAutoPictureInPicture); |
| tab_helper->MediaSessionActionsChanged(actions); |
| |
| incognito_page_info()->PresentSitePermissionsForTesting(); |
| const auto& permissions = last_permission_info_list(); |
| auto it = |
| std::find_if(permissions.begin(), permissions.end(), [](const auto& p) { |
| return p.type == ContentSettingsType::AUTO_PICTURE_IN_PICTURE; |
| }); |
| ASSERT_NE(it, permissions.end()); |
| EXPECT_EQ(std::get<ContentSetting>(it->default_setting), |
| CONTENT_SETTING_BLOCK); |
| } |
| |
| TEST_F(PageInfoTest, AutoPictureInPicturePermissionInfoRegular) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(media::kAutoPictureInPictureAndroid); |
| |
| AutoPictureInPictureTabHelper::CreateForWebContents(web_contents()); |
| auto* tab_helper = |
| AutoPictureInPictureTabHelper::FromWebContents(web_contents()); |
| std::vector<media_session::mojom::MediaSessionAction> actions; |
| actions.push_back( |
| media_session::mojom::MediaSessionAction::kEnterAutoPictureInPicture); |
| tab_helper->MediaSessionActionsChanged(actions); |
| |
| page_info()->PresentSitePermissionsForTesting(); |
| const auto& permissions = last_permission_info_list(); |
| auto it = |
| std::find_if(permissions.begin(), permissions.end(), [](const auto& p) { |
| return p.type == ContentSettingsType::AUTO_PICTURE_IN_PICTURE; |
| }); |
| ASSERT_NE(it, permissions.end()); |
| EXPECT_EQ(std::get<ContentSetting>(it->default_setting), |
| CONTENT_SETTING_ALLOW); |
| } |
| #endif |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| |
| // Unit tests with the unified autoplay sound settings UI enabled. When enabled |
| // the sound settings dropdown on the page info UI will have custom wording. |
| |
| class UnifiedAutoplaySoundSettingsPageInfoTest |
| : public ChromeRenderViewHostTestHarness { |
| public: |
| ~UnifiedAutoplaySoundSettingsPageInfoTest() override = default; |
| |
| void SetUp() override { |
| scoped_feature_list_.InitWithFeatures({media::kAutoplayDisableSettings}, |
| {}); |
| ChromeRenderViewHostTestHarness::SetUp(); |
| } |
| |
| void SetAutoplayPrefValue(bool value) { |
| profile()->GetPrefs()->SetBoolean(prefs::kBlockAutoplayEnabled, value); |
| } |
| |
| void SetDefaultSoundContentSetting(ContentSetting default_setting) { |
| default_setting_ = default_setting; |
| } |
| |
| std::u16string GetDefaultSoundSettingString() { |
| auto web_contents = |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr); |
| ChromePageInfoUiDelegate delegate(web_contents.get(), |
| GURL("http://www.example.com")); |
| PageInfo::PermissionInfo info; |
| info.type = ContentSettingsType::SOUND; |
| info.default_setting = default_setting_; |
| info.source = SettingSource::kUser; |
| info.is_one_time = false; |
| return PageInfoUI::PermissionStateToUIString(&delegate, info); |
| } |
| |
| std::u16string GetSoundSettingString(ContentSetting setting) { |
| auto web_contents = |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr); |
| ChromePageInfoUiDelegate delegate(web_contents.get(), |
| GURL("http://www.example.com")); |
| PageInfo::PermissionInfo info; |
| info.type = ContentSettingsType::SOUND; |
| info.setting = setting; |
| info.default_setting = default_setting_; |
| info.source = SettingSource::kUser; |
| info.is_one_time = false; |
| return PageInfoUI::PermissionStateToUIString(&delegate, info); |
| } |
| |
| private: |
| ContentSetting default_setting_ = CONTENT_SETTING_DEFAULT; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| // This test checks that the strings for the sound settings dropdown when |
| // block autoplay is enabled and the default sound setting is allow. |
| // The three options should be Automatic (default), Allow and Mute. |
| TEST_F(UnifiedAutoplaySoundSettingsPageInfoTest, DefaultAllow_PrefOn) { |
| SetDefaultSoundContentSetting(CONTENT_SETTING_ALLOW); |
| SetAutoplayPrefValue(true); |
| |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAGE_INFO_BUTTON_TEXT_AUTOMATIC_BY_DEFAULT), |
| GetDefaultSoundSettingString()); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_ALLOWED), |
| GetSoundSettingString(CONTENT_SETTING_ALLOW)); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_MUTED), |
| GetSoundSettingString(CONTENT_SETTING_BLOCK)); |
| } |
| |
| // This test checks that the strings for the sound settings dropdown when |
| // block autoplay is disabled and the default sound setting is allow. |
| // The three options should be Allow (default), Allow and Mute. |
| TEST_F(UnifiedAutoplaySoundSettingsPageInfoTest, DefaultAllow_PrefOff) { |
| SetDefaultSoundContentSetting(CONTENT_SETTING_ALLOW); |
| SetAutoplayPrefValue(false); |
| |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_ALLOWED_BY_DEFAULT), |
| GetDefaultSoundSettingString()); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_ALLOWED), |
| GetSoundSettingString(CONTENT_SETTING_ALLOW)); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_MUTED), |
| GetSoundSettingString(CONTENT_SETTING_BLOCK)); |
| } |
| |
| // This test checks the strings for the sound settings dropdown when |
| // the default sound setting is block. The three options should be |
| // Block (default), Allow and Mute. |
| TEST_F(UnifiedAutoplaySoundSettingsPageInfoTest, DefaultBlock_PrefOn) { |
| SetDefaultSoundContentSetting(CONTENT_SETTING_BLOCK); |
| SetAutoplayPrefValue(true); |
| |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAGE_INFO_BUTTON_TEXT_MUTED_BY_DEFAULT), |
| GetDefaultSoundSettingString()); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_ALLOWED), |
| GetSoundSettingString(CONTENT_SETTING_ALLOW)); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_MUTED), |
| GetSoundSettingString(CONTENT_SETTING_BLOCK)); |
| } |
| |
| // This test checks the strings for the sound settings dropdown when |
| // the default sound setting is block. The three options should be |
| // Block (default), Allow and Mute. |
| TEST_F(UnifiedAutoplaySoundSettingsPageInfoTest, DefaultBlock_PrefOff) { |
| SetDefaultSoundContentSetting(CONTENT_SETTING_BLOCK); |
| SetAutoplayPrefValue(false); |
| |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAGE_INFO_BUTTON_TEXT_MUTED_BY_DEFAULT), |
| GetDefaultSoundSettingString()); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_ALLOWED), |
| GetSoundSettingString(CONTENT_SETTING_ALLOW)); |
| |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_MUTED), |
| GetSoundSettingString(CONTENT_SETTING_BLOCK)); |
| } |
| |
| // This test checks that the string for a permission dropdown that is not the |
| // sound setting is unaffected. |
| TEST_F(UnifiedAutoplaySoundSettingsPageInfoTest, NotSoundSetting_Noop) { |
| auto web_contents = |
| content::WebContentsTester::CreateTestWebContents(profile(), nullptr); |
| ChromePageInfoUiDelegate delegate(web_contents.get(), |
| GURL("http://www.example.com")); |
| PageInfo::PermissionInfo info; |
| info.type = ContentSettingsType::ADS; |
| info.default_setting = CONTENT_SETTING_ALLOW; |
| info.source = SettingSource::kUser; |
| info.is_one_time = false; |
| |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAGE_INFO_STATE_TEXT_ALLOWED_BY_DEFAULT), |
| PageInfoUI::PermissionStateToUIString(&delegate, info)); |
| } |
| |
| #endif // !BUILDFLAG(IS_ANDROID) |
| |
| // Unit tests for logic in the PageInfoUI that toggles permission between |
| // allow/block and remember/forget. |
| class PageInfoToggleStatesUnitTest : public ::testing::Test { |
| }; |
| |
| // Helper to compare std::optional<PermissionSetting> with a ContentSetting. |
| #define EXPECT_CONTENT_SETTING_EQ(val1, val2) \ |
| EXPECT_EQ(std::get<ContentSetting>(val1.value_or(CONTENT_SETTING_DEFAULT)), \ |
| val2) |
| |
| // Testing all possible state transitions for a permission that doesn't |
| // support allow once. |
| TEST_F(PageInfoToggleStatesUnitTest, |
| TogglePermissionWithoutAllowOnceDefaultAskTest) { |
| PageInfo::PermissionInfo camera_permission; |
| camera_permission.type = ContentSettingsType::MEDIASTREAM_CAMERA; |
| camera_permission.setting = CONTENT_SETTING_ALLOW; |
| camera_permission.default_setting = CONTENT_SETTING_ASK; |
| camera_permission.source = SettingSource::kUser; |
| camera_permission.is_one_time = false; |
| |
| // Allow -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(camera_permission); |
| EXPECT_CONTENT_SETTING_EQ(camera_permission.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Allow |
| PageInfoUI::ToggleBetweenAllowAndBlock(camera_permission); |
| EXPECT_CONTENT_SETTING_EQ(camera_permission.setting, CONTENT_SETTING_ALLOW); |
| } |
| |
| TEST_F(PageInfoToggleStatesUnitTest, |
| TogglePermissionWithoutAllowOnceDefaultBlockTest) { |
| PageInfo::PermissionInfo camera_permission; |
| camera_permission.type = ContentSettingsType::MEDIASTREAM_CAMERA; |
| camera_permission.setting = CONTENT_SETTING_ALLOW; |
| camera_permission.default_setting = CONTENT_SETTING_BLOCK; |
| camera_permission.source = SettingSource::kUser; |
| camera_permission.is_one_time = false; |
| |
| // Allow -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(camera_permission); |
| EXPECT_CONTENT_SETTING_EQ(camera_permission.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Allow |
| PageInfoUI::ToggleBetweenAllowAndBlock(camera_permission); |
| EXPECT_CONTENT_SETTING_EQ(camera_permission.setting, CONTENT_SETTING_ALLOW); |
| |
| // Allow -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(camera_permission); |
| EXPECT_CONTENT_SETTING_EQ(camera_permission.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block (default) -> Allow |
| camera_permission.setting = CONTENT_SETTING_DEFAULT; |
| PageInfoUI::ToggleBetweenAllowAndBlock(camera_permission); |
| EXPECT_CONTENT_SETTING_EQ(camera_permission.setting, CONTENT_SETTING_ALLOW); |
| } |
| |
| // Testing all possible state transitions for a permission that supports |
| // allow once and default setting ask. |
| TEST_F(PageInfoToggleStatesUnitTest, |
| TogglePermissionWithAllowOnceDefaultAskTest) { |
| PageInfo::PermissionInfo location_permission; |
| location_permission.type = ContentSettingsType::GEOLOCATION; |
| location_permission.setting = CONTENT_SETTING_ALLOW; |
| location_permission.default_setting = CONTENT_SETTING_ASK; |
| location_permission.source = SettingSource::kUser; |
| location_permission.is_one_time = false; |
| |
| // Allow -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Allow |
| PageInfoUI::ToggleBetweenAllowAndBlock(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_ALLOW); |
| |
| // Allow -> Allow once |
| PageInfoUI::ToggleBetweenRememberAndForget(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(location_permission.is_one_time, true); |
| |
| // Allow once -> Allow |
| PageInfoUI::ToggleBetweenRememberAndForget(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(location_permission.is_one_time, false); |
| } |
| |
| // Testing all possible state transitions for a permission that supports |
| // allow once and default setting block. |
| TEST_F(PageInfoToggleStatesUnitTest, |
| TogglePermissionWithAllowOnceDefaultBlockTest) { |
| PageInfo::PermissionInfo location_permission; |
| location_permission.type = ContentSettingsType::GEOLOCATION; |
| location_permission.setting = std::nullopt; |
| location_permission.default_setting = CONTENT_SETTING_BLOCK; |
| location_permission.source = SettingSource::kUser; |
| location_permission.is_one_time = false; |
| |
| // Block (default) -> Allow once |
| PageInfoUI::ToggleBetweenAllowAndBlock(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(location_permission.is_one_time, true); |
| |
| // Allow once -> Allow |
| PageInfoUI::ToggleBetweenRememberAndForget(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(location_permission.is_one_time, false); |
| |
| // Allow -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Allow |
| PageInfoUI::ToggleBetweenAllowAndBlock(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(location_permission.is_one_time, false); |
| |
| // Allow -> Allow once |
| PageInfoUI::ToggleBetweenRememberAndForget(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(location_permission.is_one_time, true); |
| |
| // Allow once -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(location_permission); |
| EXPECT_CONTENT_SETTING_EQ(location_permission.setting, CONTENT_SETTING_BLOCK); |
| EXPECT_EQ(location_permission.is_one_time, false); |
| } |
| |
| // Testing all possible state transitions for a content settings with a default |
| // setting allow. |
| TEST_F(PageInfoToggleStatesUnitTest, TogglePermissionDefaultAllowTest) { |
| PageInfo::PermissionInfo images_permission; |
| images_permission.type = ContentSettingsType::IMAGES; |
| images_permission.setting = std::nullopt; |
| images_permission.default_setting = CONTENT_SETTING_ALLOW; |
| images_permission.source = SettingSource::kUser; |
| images_permission.is_one_time = false; |
| |
| // Allow (default) -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(images_permission); |
| EXPECT_CONTENT_SETTING_EQ(images_permission.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Allow |
| PageInfoUI::ToggleBetweenAllowAndBlock(images_permission); |
| EXPECT_CONTENT_SETTING_EQ(images_permission.setting, CONTENT_SETTING_ALLOW); |
| |
| // Allow -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(images_permission); |
| EXPECT_CONTENT_SETTING_EQ(images_permission.setting, CONTENT_SETTING_BLOCK); |
| } |
| |
| // Testing all possible state transitions for a content settings with a default |
| // setting block. |
| TEST_F(PageInfoToggleStatesUnitTest, TogglePermissionDefaultBlockTest) { |
| PageInfo::PermissionInfo popups_permission; |
| popups_permission.type = ContentSettingsType::POPUPS; |
| popups_permission.setting = std::nullopt; |
| popups_permission.default_setting = CONTENT_SETTING_BLOCK; |
| popups_permission.source = SettingSource::kUser; |
| popups_permission.is_one_time = false; |
| |
| // Block (default) -> Allow |
| PageInfoUI::ToggleBetweenAllowAndBlock(popups_permission); |
| EXPECT_CONTENT_SETTING_EQ(popups_permission.setting, CONTENT_SETTING_ALLOW); |
| |
| // Allow -> Block |
| // The page info always creates a site exception even if the target setting |
| // matches the default. |
| PageInfoUI::ToggleBetweenAllowAndBlock(popups_permission); |
| EXPECT_CONTENT_SETTING_EQ(popups_permission.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Allow |
| PageInfoUI::ToggleBetweenAllowAndBlock(popups_permission); |
| EXPECT_CONTENT_SETTING_EQ(popups_permission.setting, CONTENT_SETTING_ALLOW); |
| } |
| |
| // Testing all possible state transitions for a guard content settings with a |
| // default setting ask. |
| TEST_F(PageInfoToggleStatesUnitTest, ToggleGuardPermissionDefaultAskTest) { |
| PageInfo::PermissionInfo usb_guard; |
| usb_guard.type = ContentSettingsType::USB_GUARD; |
| usb_guard.setting = std::nullopt; |
| usb_guard.default_setting = CONTENT_SETTING_ASK; |
| usb_guard.source = SettingSource::kUser; |
| usb_guard.is_one_time = false; |
| |
| // Ask (default) -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(usb_guard); |
| EXPECT_CONTENT_SETTING_EQ(usb_guard.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Ask |
| // The page info always creates a site exception even if the target setting |
| // matches the default. |
| PageInfoUI::ToggleBetweenAllowAndBlock(usb_guard); |
| EXPECT_CONTENT_SETTING_EQ(usb_guard.setting, CONTENT_SETTING_ASK); |
| |
| // Ask -> Block |
| PageInfoUI::ToggleBetweenAllowAndBlock(usb_guard); |
| EXPECT_CONTENT_SETTING_EQ(usb_guard.setting, CONTENT_SETTING_BLOCK); |
| } |
| |
| // Testing all possible state transitions for a guard content settings with a |
| // default setting block. |
| TEST_F(PageInfoToggleStatesUnitTest, ToggleGuardPermissionDefaultBlockTest) { |
| PageInfo::PermissionInfo hid_guard; |
| hid_guard.type = ContentSettingsType::HID_GUARD; |
| hid_guard.setting = std::nullopt; |
| hid_guard.default_setting = CONTENT_SETTING_BLOCK; |
| hid_guard.source = SettingSource::kUser; |
| hid_guard.is_one_time = false; |
| |
| // Block (default) -> Ask |
| PageInfoUI::ToggleBetweenAllowAndBlock(hid_guard); |
| EXPECT_CONTENT_SETTING_EQ(hid_guard.setting, CONTENT_SETTING_ASK); |
| |
| // Ask -> Block |
| // The page info always creates a site exception even if the target setting |
| // matches the default. |
| PageInfoUI::ToggleBetweenAllowAndBlock(hid_guard); |
| EXPECT_CONTENT_SETTING_EQ(hid_guard.setting, CONTENT_SETTING_BLOCK); |
| |
| // Block -> Ask |
| PageInfoUI::ToggleBetweenAllowAndBlock(hid_guard); |
| EXPECT_CONTENT_SETTING_EQ(hid_guard.setting, CONTENT_SETTING_ASK); |
| } |
| |
| TEST_F(PageInfoTest, WithoutPageSpecificContentSettings) { |
| SetContents(CreateTestWebContents()); |
| EXPECT_FALSE(content_settings::PageSpecificContentSettings::GetForPage( |
| web_contents()->GetPrimaryPage())); |
| page_info(); |
| } |
| |
| TEST_F(PageInfoTest, MidiGrantsAreFilteredWhenAllowSysex) { |
| std::set<ContentSettingsType> expected_visible_permissions; |
| |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| page_info()->PresentSitePermissionsForTesting(); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // Geolocation is always allowed to pass through to Android-specific logic to |
| // check for DSE settings (so expect 1 item), but isn't actually shown later |
| // on because this test isn't testing with a default search engine origin. |
| expected_visible_permissions.insert(ContentSettingsType::GEOLOCATION); |
| #endif |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| |
| map->SetContentSettingDefaultScope( |
| url(), url(), ContentSettingsType::MIDI_SYSEX, CONTENT_SETTING_ALLOW); |
| page_info()->PresentSitePermissionsForTesting(); |
| expected_visible_permissions.insert(ContentSettingsType::MIDI_SYSEX); |
| ExpectPermissionInfoList(expected_visible_permissions, |
| last_permission_info_list()); |
| } |
| |
| TEST_F(PageInfoTest, OriginLevelExceptionScope) { |
| SetURL("https://www.example.com"); |
| |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| page_info()->PresentSitePermissionsForTesting(); |
| map->SetContentSettingDefaultScope(url(), url(), ContentSettingsType::POPUPS, |
| CONTENT_SETTING_ALLOW); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::POPUPS, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| // Page info has created an allow origin-level exception. |
| content_settings::SettingInfo info; |
| ContentSetting setting = |
| map->GetContentSetting(url(), url(), ContentSettingsType::POPUPS, &info); |
| EXPECT_EQ(setting, CONTENT_SETTING_BLOCK); |
| EXPECT_EQ(info.primary_pattern, |
| ContentSettingsPattern::FromURLNoWildcard(url())); |
| EXPECT_EQ(info.secondary_pattern, ContentSettingsPattern::Wildcard()); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::POPUPS, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| // Page info has created a block origin-level exception. |
| setting = |
| map->GetContentSetting(url(), url(), ContentSettingsType::POPUPS, &info); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(info.primary_pattern, |
| ContentSettingsPattern::FromURLNoWildcard(url())); |
| EXPECT_EQ(info.secondary_pattern, ContentSettingsPattern::Wildcard()); |
| } |
| |
| TEST_F(PageInfoTest, CustomExceptionScope) { |
| SetURL("https://www.example.com"); |
| |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| page_info()->PresentSitePermissionsForTesting(); |
| map->SetContentSettingCustomScope( |
| ContentSettingsPattern::FromString("https://*"), |
| ContentSettingsPattern::Wildcard(), ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_BLOCK); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_ALLOW, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| // Page info has created an allow origin-level exception. |
| content_settings::SettingInfo info; |
| ContentSetting setting = map->GetContentSetting( |
| url(), url(), ContentSettingsType::JAVASCRIPT, &info); |
| EXPECT_EQ(setting, CONTENT_SETTING_ALLOW); |
| EXPECT_EQ(info.primary_pattern, |
| ContentSettingsPattern::FromURLNoWildcard(url())); |
| EXPECT_EQ(info.secondary_pattern, ContentSettingsPattern::Wildcard()); |
| |
| // Other origins matching the pattern are not affected. |
| GURL another_url = GURL("https://www.another.com"); |
| EXPECT_EQ(CONTENT_SETTING_BLOCK, |
| map->GetContentSetting(another_url, another_url, |
| ContentSettingsType::JAVASCRIPT)); |
| |
| page_info()->OnSitePermissionChanged(ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_BLOCK, |
| /*requesting_origin=*/std::nullopt, |
| /*is_one_time=*/false); |
| |
| // Page info has created a block origin-level exception. |
| setting = map->GetContentSetting(url(), url(), |
| ContentSettingsType::JAVASCRIPT, &info); |
| EXPECT_EQ(setting, CONTENT_SETTING_BLOCK); |
| EXPECT_EQ(info.primary_pattern, |
| ContentSettingsPattern::FromURLNoWildcard(url())); |
| EXPECT_EQ(info.secondary_pattern, ContentSettingsPattern::Wildcard()); |
| } |
| |
| TEST_F(PageInfoTest, SiteExceptionScopeTypeMetrics) { |
| SetURL("https://www.example.com:443"); |
| |
| constexpr char kScopeTypeHistogram[] = |
| "Privacy.PageInfo.SiteExceptionsScopeType"; |
| base::HistogramTester tester; |
| tester.ExpectTotalCount(kScopeTypeHistogram, 0); |
| |
| auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); |
| map->SetContentSettingCustomScope( |
| ContentSettingsPattern::FromString("https://www.example.com"), |
| ContentSettingsPattern::Wildcard(), ContentSettingsType::JAVASCRIPT, |
| CONTENT_SETTING_BLOCK); |
| map->SetContentSettingCustomScope( |
| ContentSettingsPattern::FromString("https://*"), |
| ContentSettingsPattern::Wildcard(), ContentSettingsType::MIDI_SYSEX, |
| CONTENT_SETTING_ALLOW); |
| |
| page_info()->PresentSitePermissionsForTesting(); |
| |
| tester.ExpectBucketCount(kScopeTypeHistogram, |
| ContentSettingsPattern::Scope::kWithPortWildcard, |
| 1 /* expected_count */); |
| tester.ExpectBucketCount(kScopeTypeHistogram, |
| ContentSettingsPattern::Scope::kCustomScope, |
| 1 /* expected_count */); |
| |
| // Repeated calls of PresentSitePermissions won't rerecord metrics within the |
| // same page info instance. |
| page_info()->PresentSitePermissionsForTesting(); |
| tester.ExpectBucketCount(kScopeTypeHistogram, |
| ContentSettingsPattern::Scope::kWithPortWildcard, |
| 1 /* expected_count */); |
| tester.ExpectBucketCount(kScopeTypeHistogram, |
| ContentSettingsPattern::Scope::kCustomScope, |
| 1 /* expected_count */); |
| } |