| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/page_info/chrome_page_info_delegate.h" |
| |
| #include "base/metrics/histogram_functions.h" |
| #include "build/build_config.h" |
| #include "build/buildflag.h" |
| #include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/content_settings/cookie_settings_factory.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/permissions/permission_actions_history_factory.h" |
| #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" |
| #include "chrome/browser/permissions/permission_manager_factory.h" |
| #include "chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h" |
| #include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h" |
| #include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h" |
| #include "chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" |
| #include "chrome/browser/ssl/chrome_security_state_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/url_identity.h" |
| #include "chrome/browser/usb/usb_chooser_context.h" |
| #include "chrome/browser/usb/usb_chooser_context_factory.h" |
| #include "chrome/browser/vr/vr_tab_helper.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "components/content_settings/browser/page_specific_content_settings.h" |
| #include "components/content_settings/core/common/pref_names.h" |
| #include "components/infobars/content/content_infobar_manager.h" |
| #include "components/page_info/core/features.h" |
| #include "components/permissions/contexts/bluetooth_chooser_context.h" |
| #include "components/permissions/object_permission_context_base.h" |
| #include "components/permissions/permission_manager.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.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/permission_controller.h" |
| #include "content/public/browser/permission_descriptor_util.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/content_features.h" |
| #include "media/base/media_switches.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "ui/base/window_open_disposition_utils.h" |
| #include "url/origin.h" |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "chrome/grit/branded_strings.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #else |
| #include "chrome/browser/certificate_viewer.h" |
| #include "chrome/browser/hid/hid_chooser_context.h" |
| #include "chrome/browser/hid/hid_chooser_context_factory.h" |
| #include "chrome/browser/lookalikes/safety_tip_ui_helper.h" |
| #include "chrome/browser/serial/serial_chooser_context.h" |
| #include "chrome/browser/serial/serial_chooser_context_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/chrome_pages.h" |
| #include "chrome/browser/ui/hats/trust_safety_sentiment_service.h" |
| #include "chrome/browser/ui/hats/trust_safety_sentiment_service_factory.h" |
| #include "chrome/browser/ui/page_info/page_info_infobar_delegate.h" |
| #include "chrome/browser/ui/tab_dialogs.h" |
| #include "chrome/browser/ui/web_applications/app_browser_controller.h" |
| #include "chrome/browser/ui/web_applications/web_app_ui_utils.h" |
| #include "chrome/browser/web_applications/web_app_provider.h" |
| #include "chrome/browser/web_applications/web_app_registrar.h" |
| #include "chrome/browser/web_applications/web_app_tab_helper.h" |
| #include "components/webapps/common/web_app_id.h" |
| #include "ui/events/event.h" |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| #include "chrome/browser/smart_card/smart_card_permission_context.h" |
| #include "chrome/browser/smart_card/smart_card_permission_context_factory.h" |
| #include "chrome/browser/ui/webui/ash/settings/app_management/app_management_uma.h" |
| #endif |
| |
| namespace { |
| |
| // Expected URL types for `UrlIdentity::CreateFromUrl()`. |
| constexpr UrlIdentity::TypeSet kUrlIdentityAllowedTypes = { |
| UrlIdentity::Type::kDefault, UrlIdentity::Type::kFile, |
| UrlIdentity::Type::kIsolatedWebApp, UrlIdentity::Type::kChromeExtension}; |
| |
| constexpr UrlIdentity::FormatOptions kUrlIdentityOptions{ |
| .default_options = {UrlIdentity::DefaultFormatOptions:: |
| kOmitSchemePathAndTrivialSubdomains}}; |
| |
| } // namespace |
| |
| ChromePageInfoDelegate::ChromePageInfoDelegate( |
| content::WebContents* web_contents) |
| : web_contents_(web_contents) { |
| #if !BUILDFLAG(IS_ANDROID) |
| sentiment_service_ = |
| TrustSafetySentimentServiceFactory::GetForProfile(GetProfile()); |
| #endif |
| base::UmaHistogramBoolean("Security.PageInfo.AboutThisSiteLanguageSupported", |
| page_info::IsAboutThisSiteFeatureEnabled( |
| g_browser_process->GetApplicationLocale())); |
| } |
| |
| Profile* ChromePageInfoDelegate::GetProfile() const { |
| return Profile::FromBrowserContext(web_contents_->GetBrowserContext()); |
| } |
| |
| permissions::ObjectPermissionContextBase* |
| ChromePageInfoDelegate::GetChooserContext(ContentSettingsType type) { |
| switch (type) { |
| case ContentSettingsType::USB_CHOOSER_DATA: |
| return UsbChooserContextFactory::GetForProfile(GetProfile()); |
| case ContentSettingsType::BLUETOOTH_CHOOSER_DATA: |
| if (base::FeatureList::IsEnabled( |
| features::kWebBluetoothNewPermissionsBackend)) { |
| return BluetoothChooserContextFactory::GetForProfile(GetProfile()); |
| } |
| return nullptr; |
| case ContentSettingsType::SERIAL_CHOOSER_DATA: |
| #if !BUILDFLAG(IS_ANDROID) |
| return SerialChooserContextFactory::GetForProfile(GetProfile()); |
| #else |
| NOTREACHED(); |
| #endif |
| case ContentSettingsType::HID_CHOOSER_DATA: |
| #if !BUILDFLAG(IS_ANDROID) |
| return HidChooserContextFactory::GetForProfile(GetProfile()); |
| #else |
| NOTREACHED(); |
| #endif |
| case ContentSettingsType::SMART_CARD_DATA: |
| #if BUILDFLAG(IS_CHROMEOS) |
| if (base::FeatureList::IsEnabled(blink::features::kSmartCard)) { |
| return &SmartCardPermissionContextFactory::GetForProfile(*GetProfile()); |
| } |
| #endif |
| return nullptr; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| #if BUILDFLAG(FULL_SAFE_BROWSING) |
| safe_browsing::ChromePasswordProtectionService* |
| ChromePageInfoDelegate::GetChromePasswordProtectionService() const { |
| return safe_browsing::ChromePasswordProtectionService:: |
| GetPasswordProtectionService(GetProfile()); |
| } |
| |
| safe_browsing::PasswordProtectionService* |
| ChromePageInfoDelegate::GetPasswordProtectionService() const { |
| return GetChromePasswordProtectionService(); |
| } |
| |
| void ChromePageInfoDelegate::OnUserActionOnPasswordUi( |
| safe_browsing::WarningAction action) { |
| auto* chrome_password_protection_service = |
| GetChromePasswordProtectionService(); |
| DCHECK(chrome_password_protection_service); |
| |
| chrome_password_protection_service->OnUserAction( |
| web_contents_, |
| chrome_password_protection_service |
| ->reused_password_account_type_for_last_shown_warning(), |
| safe_browsing::RequestOutcome::UNKNOWN, |
| safe_browsing::LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, |
| /*verdict_token=*/"", safe_browsing::WarningUIType::PAGE_INFO, action); |
| } |
| |
| std::u16string ChromePageInfoDelegate::GetWarningDetailText() { |
| auto* chrome_password_protection_service = |
| GetChromePasswordProtectionService(); |
| |
| // |password_protection_service| may be null in test. |
| return chrome_password_protection_service |
| ? chrome_password_protection_service->GetWarningDetailText( |
| chrome_password_protection_service |
| ->reused_password_account_type_for_last_shown_warning()) |
| : std::u16string(); |
| } |
| #endif |
| |
| content::PermissionResult ChromePageInfoDelegate::GetPermissionResult( |
| blink::PermissionType permission, |
| const url::Origin& origin, |
| const std::optional<url::Origin>& requesting_origin) { |
| auto* controller = GetProfile()->GetPermissionController(); |
| auto descriptor = content::PermissionDescriptorUtil:: |
| CreatePermissionDescriptorForPermissionType(permission); |
| if (requesting_origin.has_value()) { |
| return controller->GetPermissionResultForOriginWithoutContext( |
| descriptor, *requesting_origin, origin); |
| } else { |
| return controller->GetPermissionResultForOriginWithoutContext(descriptor, |
| origin); |
| } |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| void ChromePageInfoDelegate::FocusWebContents() { |
| Browser* browser = chrome::FindBrowserWithTab(web_contents_); |
| browser->ActivateContents(web_contents_); |
| } |
| |
| std::optional<std::u16string> ChromePageInfoDelegate::GetRwsOwner( |
| const GURL& site_url) { |
| return PrivacySandboxServiceFactory::GetForProfile(GetProfile()) |
| ->GetRelatedWebsiteSetOwnerForDisplay(site_url); |
| } |
| |
| bool ChromePageInfoDelegate::IsRwsManaged(const GURL& site_url) { |
| return PrivacySandboxServiceFactory::GetForProfile(GetProfile()) |
| ->IsPartOfManagedRelatedWebsiteSet(net::SchemefulSite(site_url)); |
| } |
| |
| bool ChromePageInfoDelegate::CreateInfoBarDelegate( |
| content::ReloadType reload_type) { |
| infobars::ContentInfoBarManager* infobar_manager = |
| infobars::ContentInfoBarManager::FromWebContents(web_contents_); |
| if (infobar_manager) { |
| PageInfoInfoBarDelegate::Create(infobar_manager, reload_type); |
| return true; |
| } |
| return false; |
| } |
| |
| std::unique_ptr<content_settings::CookieControlsController> |
| ChromePageInfoDelegate::CreateCookieControlsController() { |
| Profile* profile = GetProfile(); |
| return std::make_unique<content_settings::CookieControlsController>( |
| CookieSettingsFactory::GetForProfile(profile), |
| profile->IsOffTheRecord() |
| ? CookieSettingsFactory::GetForProfile(profile->GetOriginalProfile()) |
| : nullptr, |
| HostContentSettingsMapFactory::GetForProfile(profile), |
| TrackingProtectionSettingsFactory::GetForProfile(profile), |
| profile->IsIncognitoProfile()); |
| } |
| |
| bool ChromePageInfoDelegate::IsIsolatedWebApp() { |
| CHECK(web_contents_); |
| web_app::WebAppProvider* provider = |
| web_app::WebAppProvider::GetForWebContents(web_contents_); |
| if (!provider) { |
| return false; |
| } |
| |
| const webapps::AppId* app_id = |
| web_app::WebAppTabHelper::GetAppId(web_contents_); |
| return app_id && provider->registrar_unsafe().IsIsolated(*app_id); |
| } |
| |
| void ChromePageInfoDelegate::ShowSiteSettings(const GURL& site_url) { |
| if (web_app::HandleAppManagementLinkClickedInPageInfo(web_contents_)) { |
| return; |
| } |
| |
| Browser* browser = chrome::FindBrowserWithTab(web_contents_); |
| chrome::ShowSiteSettings(browser, site_url); |
| } |
| |
| void ChromePageInfoDelegate::ShowCookiesSettings() { |
| Browser* browser = chrome::FindBrowserWithTab(web_contents_); |
| chrome::ShowSettingsSubPage(browser, chrome::kCookieSettingsSubPage); |
| } |
| |
| void ChromePageInfoDelegate::ShowIncognitoSettings() { |
| Browser* browser = chrome::FindBrowserWithTab(web_contents_); |
| chrome::ShowSettingsSubPage(browser, chrome::kIncognitoSettingsSubPage); |
| } |
| |
| void ChromePageInfoDelegate::ShowAllSitesSettingsFilteredByRwsOwner( |
| const std::u16string& rws_owner) { |
| Browser* browser = chrome::FindBrowserWithTab(web_contents_); |
| chrome::ShowAllSitesSettingsFilteredByRwsOwner(browser, |
| base::UTF16ToUTF8(rws_owner)); |
| } |
| |
| void ChromePageInfoDelegate::ShowSyncSettings() { |
| Browser* browser = chrome::FindBrowserWithTab(web_contents_); |
| chrome::ShowSettingsSubPage(browser, chrome::kSyncSetupSubPage); |
| } |
| |
| void ChromePageInfoDelegate::OpenCookiesDialog() { |
| FocusWebContents(); |
| TabDialogs::FromWebContents(web_contents_)->ShowCollectedCookies(); |
| } |
| |
| void ChromePageInfoDelegate::OpenCertificateDialog( |
| net::X509Certificate* certificate) { |
| gfx::NativeWindow top_window = web_contents_->GetTopLevelNativeWindow(); |
| DCHECK(certificate); |
| DCHECK(top_window); |
| |
| FocusWebContents(); |
| ShowCertificateViewer(web_contents_, top_window, certificate); |
| } |
| |
| void ChromePageInfoDelegate::OpenConnectionHelpCenterPage( |
| const ui::Event& event) { |
| web_contents_->OpenURL( |
| content::OpenURLParams( |
| GURL(chrome::kPageInfoHelpCenterURL), content::Referrer(), |
| ui::DispositionFromEventFlags( |
| event.flags(), WindowOpenDisposition::NEW_FOREGROUND_TAB), |
| ui::PAGE_TRANSITION_LINK, false), |
| /*navigation_handle_callback=*/{}); |
| } |
| |
| void ChromePageInfoDelegate::OpenSafetyTipHelpCenterPage() { |
| OpenHelpCenterFromSafetyTip(web_contents_); |
| } |
| |
| void ChromePageInfoDelegate::OpenSafeBrowsingHelpCenterPage( |
| const ui::Event& event) { |
| web_contents_->OpenURL( |
| content::OpenURLParams( |
| GURL(chrome::kSafeBrowsingHelpCenterURL), content::Referrer(), |
| ui::DispositionFromEventFlags( |
| event.flags(), WindowOpenDisposition::NEW_FOREGROUND_TAB), |
| ui::PAGE_TRANSITION_LINK, false), |
| /*navigation_handle_callback=*/{}); |
| } |
| |
| void ChromePageInfoDelegate::OpenContentSettingsExceptions( |
| ContentSettingsType content_settings_type) { |
| if (content_settings_type == ContentSettingsType::FILE_SYSTEM_WRITE_GUARD) { |
| const GURL& url = web_contents_->GetLastCommittedURL(); |
| chrome::ShowSiteSettingsFileSystem(GetProfile(), url); |
| return; |
| } |
| chrome::ShowContentSettingsExceptionsForProfile(GetProfile(), |
| content_settings_type); |
| } |
| |
| void ChromePageInfoDelegate::OnPageInfoActionOccurred( |
| page_info::PageInfoAction action) { |
| if (sentiment_service_) { |
| if (action == page_info::PAGE_INFO_OPENED) { |
| sentiment_service_->PageInfoOpened(); |
| } else { |
| sentiment_service_->InteractedWithPageInfo(); |
| } |
| } |
| } |
| |
| void ChromePageInfoDelegate::OnUIClosing() { |
| if (sentiment_service_) { |
| sentiment_service_->PageInfoClosed(); |
| } |
| } |
| #endif |
| |
| std::u16string ChromePageInfoDelegate::GetSubjectName(const GURL& url) { |
| CHECK(web_contents_); |
| return UrlIdentity::CreateFromUrl(GetProfile(), url, kUrlIdentityAllowedTypes, |
| kUrlIdentityOptions) |
| .name; |
| } |
| |
| permissions::PermissionDecisionAutoBlocker* |
| ChromePageInfoDelegate::GetPermissionDecisionAutoblocker() { |
| return PermissionDecisionAutoBlockerFactory::GetForProfile(GetProfile()); |
| } |
| |
| permissions::PermissionActionsHistory* |
| ChromePageInfoDelegate::GetPermissionActionsHistory() { |
| return PermissionActionsHistoryFactory::GetForProfile(GetProfile()); |
| } |
| |
| StatefulSSLHostStateDelegate* |
| ChromePageInfoDelegate::GetStatefulSSLHostStateDelegate() { |
| return StatefulSSLHostStateDelegateFactory::GetForProfile(GetProfile()); |
| } |
| |
| HostContentSettingsMap* ChromePageInfoDelegate::GetContentSettings() { |
| return HostContentSettingsMapFactory::GetForProfile(GetProfile()); |
| } |
| |
| bool ChromePageInfoDelegate::IsSubresourceFilterActivated( |
| const GURL& site_url) { |
| subresource_filter::SubresourceFilterContentSettingsManager* |
| settings_manager = |
| SubresourceFilterProfileContextFactory::GetForProfile(GetProfile()) |
| ->settings_manager(); |
| |
| return settings_manager->GetSiteActivationFromMetadata(site_url); |
| } |
| |
| bool ChromePageInfoDelegate::HasAutoPictureInPictureBeenRegistered() { |
| #if BUILDFLAG(IS_ANDROID) |
| if (!base::FeatureList::IsEnabled(media::kAutoPictureInPictureAndroid)) { |
| return false; |
| } |
| #endif |
| auto* auto_pip_tab_helper = |
| AutoPictureInPictureTabHelper::FromWebContents(web_contents_); |
| return auto_pip_tab_helper && |
| auto_pip_tab_helper->HasAutoPictureInPictureBeenRegistered(); |
| } |
| |
| bool ChromePageInfoDelegate::IsContentDisplayedInVrHeadset() { |
| return vr::VrTabHelper::IsContentDisplayedInHeadset(web_contents_); |
| } |
| |
| security_state::SecurityLevel ChromePageInfoDelegate::GetSecurityLevel() { |
| if (security_state_for_tests_set_) { |
| return security_level_for_tests_; |
| } |
| |
| // This is a no-op if a SecurityStateTabHelper already exists for |
| // |web_contents|. |
| ChromeSecurityStateTabHelper::CreateForWebContents(web_contents_); |
| |
| auto* helper = SecurityStateTabHelper::FromWebContents(web_contents_); |
| DCHECK(helper); |
| return helper->GetSecurityLevel(); |
| } |
| |
| security_state::VisibleSecurityState |
| ChromePageInfoDelegate::GetVisibleSecurityState() { |
| if (security_state_for_tests_set_) { |
| return visible_security_state_for_tests_; |
| } |
| |
| // This is a no-op if a SecurityStateTabHelper already exists for |
| // |web_contents|. |
| ChromeSecurityStateTabHelper::CreateForWebContents(web_contents_); |
| |
| auto* helper = SecurityStateTabHelper::FromWebContents(web_contents_); |
| DCHECK(helper); |
| return *helper->GetVisibleSecurityState(); |
| } |
| |
| void ChromePageInfoDelegate::OnCookiesPageOpened() { |
| auto* profile = GetProfile(); |
| auto cookie_settings = CookieSettingsFactory::GetForProfile(profile); |
| // Don't record the preference if 3PC are allowed by default. Since then |
| // cookie controls are not available in the cookies page. |
| if (!cookie_settings || !cookie_settings->ShouldBlockThirdPartyCookies()) { |
| return; |
| } |
| |
| profile->GetPrefs()->SetBoolean(prefs::kInContextCookieControlsOpened, true); |
| } |
| |
| std::unique_ptr<content_settings::PageSpecificContentSettings::Delegate> |
| ChromePageInfoDelegate::GetPageSpecificContentSettingsDelegate() { |
| auto delegate = |
| std::make_unique<PageSpecificContentSettingsDelegate>(web_contents_); |
| return std::move(delegate); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| const std::u16string ChromePageInfoDelegate::GetClientApplicationName() { |
| return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME); |
| } |
| #endif |
| |
| bool ChromePageInfoDelegate::IsHttpsFirstModeEnabled() { |
| bool https_first_mode_fully_enabled = |
| GetProfile()->GetPrefs()->GetBoolean(prefs::kHttpsOnlyModeEnabled); |
| bool https_first_mode_enabled_in_incognito = |
| base::FeatureList::IsEnabled(features::kHttpsFirstModeIncognito) && |
| GetProfile()->GetPrefs()->GetBoolean(prefs::kHttpsFirstModeIncognito); |
| return https_first_mode_fully_enabled || |
| (GetProfile()->IsIncognitoProfile() && |
| https_first_mode_enabled_in_incognito); |
| } |
| |
| bool ChromePageInfoDelegate::IsIncognitoProfile() { |
| return GetProfile()->IsIncognitoProfile(); |
| } |
| |
| void ChromePageInfoDelegate::SetSecurityStateForTests( |
| security_state::SecurityLevel security_level, |
| security_state::VisibleSecurityState visible_security_state) { |
| security_state_for_tests_set_ = true; |
| security_level_for_tests_ = security_level; |
| visible_security_state_for_tests_ = visible_security_state; |
| } |