Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / components / page_info / page_info.cc
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/page_info/page_info.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 #include "base/i18n/time_formatting.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/metrics/histogram_functions.h"
18 #include "base/metrics/user_metrics.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "build/build_config.h"
23 #include "components/browser_ui/util/android/url_constants.h"
24 #include "components/browsing_data/content/local_storage_helper.h"
25 #include "components/content_settings/browser/page_specific_content_settings.h"
26 #include "components/content_settings/browser/ui/cookie_controls_controller.h"
27 #include "components/content_settings/core/browser/content_settings_registry.h"
28 #include "components/content_settings/core/browser/content_settings_utils.h"
29 #include "components/content_settings/core/browser/host_content_settings_map.h"
30 #include "components/content_settings/core/common/content_settings.h"
31 #include "components/content_settings/core/common/content_settings_pattern.h"
32 #include "components/content_settings/core/common/content_settings_utils.h"
33 #include "components/page_info/page_info_delegate.h"
34 #include "components/page_info/page_info_ui.h"
35 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
36 #include "components/permissions/object_permission_context_base.h"
37 #include "components/permissions/permission_decision_auto_blocker.h"
38 #include "components/permissions/permission_manager.h"
39 #include "components/permissions/permission_result.h"
40 #include "components/permissions/permission_uma_util.h"
41 #include "components/permissions/permission_util.h"
42 #include "components/permissions/permissions_client.h"
43 #if BUILDFLAG(IS_ANDROID)
44 #include "components/resources/android/theme_resources.h"
45 #endif
46 #include "build/chromeos_buildflags.h"
47 #include "components/page_info/core/features.h"
48 #include "components/privacy_sandbox/privacy_sandbox_features.h"
49 #include "components/safe_browsing/buildflags.h"
50 #include "components/safe_browsing/content/browser/password_protection/password_protection_service.h"
51 #include "components/safe_browsing/core/browser/password_protection/metrics_util.h"
52 #include "components/safe_browsing/core/common/proto/csd.pb.h"
53 #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h"
54 #include "components/signin/public/identity_manager/account_info.h"
55 #include "components/ssl_errors/error_info.h"
56 #include "components/strings/grit/components_chromium_strings.h"
57 #include "components/strings/grit/components_strings.h"
58 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
59 #include "components/url_formatter/elide_url.h"
60 #include "content/public/browser/browser_context.h"
61 #include "content/public/browser/browser_thread.h"
62 #include "content/public/common/content_features.h"
63 #include "content/public/common/url_constants.h"
64 #include "net/cert/cert_status_flags.h"
65 #include "net/cert/x509_certificate.h"
66 #include "net/ssl/ssl_cipher_suite_names.h"
67 #include "net/ssl/ssl_connection_status_flags.h"
68 #include "services/metrics/public/cpp/ukm_builders.h"
69 #include "services/metrics/public/cpp/ukm_recorder.h"
70 #include "third_party/boringssl/src/include/openssl/ssl.h"
71 #include "ui/base/l10n/l10n_util.h"
72 #include "url/origin.h"
73
74 using base::ASCIIToUTF16;
75 using base::UTF16ToUTF8;
76 using base::UTF8ToUTF16;
77 using content::BrowserThread;
78 using safe_browsing::LoginReputationClientResponse;
79 using safe_browsing::RequestOutcome;
80
81 namespace {
82
83 // The list of content settings types to display on the Page Info UI. THE
84 // ORDER OF THESE ITEMS IS IMPORTANT and comes from https://crbug.com/610358. To
85 // propose changing it, email security-dev@chromium.org.
86 ContentSettingsType kPermissionType[] = {
87     ContentSettingsType::GEOLOCATION,
88     ContentSettingsType::MEDIASTREAM_CAMERA,
89     ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
90     ContentSettingsType::MEDIASTREAM_MIC,
91     ContentSettingsType::SENSORS,
92     ContentSettingsType::NOTIFICATIONS,
93     ContentSettingsType::JAVASCRIPT,
94 #if !BUILDFLAG(IS_ANDROID)
95     ContentSettingsType::IMAGES,
96 #endif
97     ContentSettingsType::POPUPS,
98     ContentSettingsType::WINDOW_MANAGEMENT,
99     ContentSettingsType::ADS,
100     ContentSettingsType::BACKGROUND_SYNC,
101     ContentSettingsType::SOUND,
102     ContentSettingsType::AUTOMATIC_DOWNLOADS,
103 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
104     ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
105 #endif
106     ContentSettingsType::MIDI_SYSEX,
107     ContentSettingsType::CLIPBOARD_READ_WRITE,
108 #if BUILDFLAG(IS_ANDROID)
109     ContentSettingsType::NFC,
110 #endif
111     ContentSettingsType::USB_GUARD,
112 #if !BUILDFLAG(IS_ANDROID)
113     ContentSettingsType::HID_GUARD,
114     ContentSettingsType::SERIAL_GUARD,
115     ContentSettingsType::FILE_SYSTEM_WRITE_GUARD,
116     ContentSettingsType::LOCAL_FONTS,
117 #endif
118     ContentSettingsType::BLUETOOTH_GUARD,
119     ContentSettingsType::BLUETOOTH_SCANNING,
120     ContentSettingsType::VR,
121     ContentSettingsType::AR,
122     ContentSettingsType::IDLE_DETECTION,
123     ContentSettingsType::FEDERATED_IDENTITY_API,
124 };
125
126 // Determines whether to show permission |type| in the Page Info UI. Only
127 // applies to permissions listed in |kPermissionType|.
128 bool ShouldShowPermission(const PageInfo::PermissionInfo& info,
129                           const GURL& site_url,
130                           HostContentSettingsMap* content_settings,
131                           content::WebContents* web_contents,
132                           bool changed_since_last_page_load,
133                           bool is_subresource_filter_activated) {
134   // Note |ContentSettingsType::ADS| will show up regardless of its default
135   // value when it has been activated on the current origin.
136   if (info.type == ContentSettingsType::ADS) {
137     if (!base::FeatureList::IsEnabled(
138             subresource_filter::kSafeBrowsingSubresourceFilter)) {
139       return false;
140     }
141
142     return is_subresource_filter_activated;
143   }
144
145   if (info.type == ContentSettingsType::SOUND) {
146     // The sound content setting should always show up when the tab has played
147     // audio.
148     if (web_contents && web_contents->WasEverAudible())
149       return true;
150   }
151
152   const bool is_incognito = web_contents->GetBrowserContext()->IsOffTheRecord();
153 #if BUILDFLAG(IS_ANDROID)
154   // Special geolocation DSE settings apply only on Android, so make sure it
155   // gets checked there regardless of default setting on Desktop.
156   // DSE settings don't apply to incognito mode.
157   if (info.type == ContentSettingsType::GEOLOCATION && !is_incognito)
158     return true;
159
160   // The File System write permission is desktop only at the moment.
161   if (info.type == ContentSettingsType::FILE_SYSTEM_WRITE_GUARD)
162     return false;
163 #else
164   // NFC is Android-only at the moment.
165   if (info.type == ContentSettingsType::NFC)
166     return false;
167
168   // Display the File System Access write permission if the File System Access
169   // API is currently being used.
170   if (info.type == ContentSettingsType::FILE_SYSTEM_WRITE_GUARD &&
171       web_contents->HasFileSystemAccessHandles()) {
172     return true;
173   }
174
175   // Hide camera if camera PTZ is granted or blocked.
176   if (info.type == ContentSettingsType::MEDIASTREAM_CAMERA) {
177     const base::Value value = content_settings->GetWebsiteSetting(
178         site_url, site_url, ContentSettingsType::CAMERA_PAN_TILT_ZOOM, nullptr);
179     DCHECK(value.is_int());
180     ContentSetting camera_ptz_setting =
181         content_settings::ValueToContentSetting(value);
182     if (camera_ptz_setting == CONTENT_SETTING_ALLOW ||
183         camera_ptz_setting == CONTENT_SETTING_BLOCK) {
184       return false;
185     }
186   }
187 #endif
188
189   // Show the content setting if it has been changed by the user since the last
190   // page load.
191   if (changed_since_last_page_load) {
192     return true;
193   }
194
195   // Show the Bluetooth guard permission if the new permissions backend is
196   // enabled.
197   if (info.type == ContentSettingsType::BLUETOOTH_GUARD &&
198       base::FeatureList::IsEnabled(
199           features::kWebBluetoothNewPermissionsBackend) &&
200       !PageInfo::IsPermissionFactoryDefault(info, is_incognito)) {
201     return true;
202   }
203
204   // Show the content setting when it has a non-default value.
205   if (!PageInfo::IsPermissionFactoryDefault(info, is_incognito))
206     return true;
207
208   return false;
209 }
210
211 // If the |visible_security_state| indicates that mixed content or certificate
212 // errors were present, update |connection_status| and |connection_details|.
213 void ReportAnyInsecureContent(
214     const security_state::VisibleSecurityState& visible_security_state,
215     PageInfo::SiteConnectionStatus* connection_status,
216     std::u16string* connection_details) {
217   bool displayed_insecure_content =
218       visible_security_state.displayed_mixed_content;
219   bool ran_insecure_content = visible_security_state.ran_mixed_content;
220   // Only note subresources with certificate errors if the main resource was
221   // loaded without major certificate errors. If the main resource had a
222   // certificate error, then it would not be that useful (and could
223   // potentially be confusing) to warn about subresources that had certificate
224   // errors too.
225   if (!net::IsCertStatusError(visible_security_state.cert_status)) {
226     displayed_insecure_content =
227         displayed_insecure_content ||
228         visible_security_state.displayed_content_with_cert_errors;
229     ran_insecure_content = ran_insecure_content ||
230                            visible_security_state.ran_content_with_cert_errors;
231   }
232
233   // Only one insecure content warning is displayed; show the most severe.
234   if (ran_insecure_content) {
235     *connection_status =
236         PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE;
237     connection_details->assign(l10n_util::GetStringFUTF16(
238         IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK, *connection_details,
239         l10n_util::GetStringUTF16(
240             IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_ERROR)));
241     return;
242   }
243   if (visible_security_state.contained_mixed_form) {
244     *connection_status = PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION;
245     connection_details->assign(l10n_util::GetStringFUTF16(
246         IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK, *connection_details,
247         l10n_util::GetStringUTF16(
248             IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_FORM_WARNING)));
249     return;
250   }
251   if (displayed_insecure_content) {
252     *connection_status =
253         PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE;
254     connection_details->assign(l10n_util::GetStringFUTF16(
255         IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK, *connection_details,
256         l10n_util::GetStringUTF16(
257             IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING)));
258   }
259 }
260
261 // The list of chooser types that need to display entries in the Website
262 // Settings UI. THE ORDER OF THESE ITEMS IS IMPORTANT. To propose changing it,
263 // email security-dev@chromium.org.
264 const PageInfo::ChooserUIInfo kChooserUIInfo[] = {
265     {ContentSettingsType::USB_CHOOSER_DATA,
266      IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL,
267      IDS_PAGE_INFO_USB_DEVICE_ALLOWED_BY_POLICY_LABEL,
268      IDS_PAGE_INFO_DELETE_USB_DEVICE},
269 #if !BUILDFLAG(IS_ANDROID)
270     {ContentSettingsType::HID_CHOOSER_DATA,
271      IDS_PAGE_INFO_HID_DEVICE_SECONDARY_LABEL,
272      IDS_PAGE_INFO_HID_DEVICE_ALLOWED_BY_POLICY_LABEL,
273      IDS_PAGE_INFO_DELETE_HID_DEVICE},
274     {ContentSettingsType::SERIAL_CHOOSER_DATA,
275      IDS_PAGE_INFO_SERIAL_PORT_SECONDARY_LABEL,
276      IDS_PAGE_INFO_SERIAL_PORT_ALLOWED_BY_POLICY_LABEL,
277      IDS_PAGE_INFO_DELETE_SERIAL_PORT},
278 #endif
279     {ContentSettingsType::BLUETOOTH_CHOOSER_DATA,
280      IDS_PAGE_INFO_BLUETOOTH_DEVICE_SECONDARY_LABEL,
281      /*allowed_by_policy_description_string_id=*/-1,
282      IDS_PAGE_INFO_DELETE_BLUETOOTH_DEVICE},
283 };
284
285 void LogTimeOpenHistogram(const std::string& name, base::TimeTicks start_time) {
286   base::UmaHistogramCustomTimes(name, base::TimeTicks::Now() - start_time,
287                                 base::Milliseconds(1), base::Hours(1), 100);
288 }
289
290 // Time open histogram prefixes.
291 const char kPageInfoTimePrefix[] = "Security.PageInfo.TimeOpen";
292 const char kPageInfoTimeActionPrefix[] = "Security.PageInfo.TimeOpen.Action";
293 const char kPageInfoTimeNoActionPrefix[] =
294     "Security.PageInfo.TimeOpen.NoAction";
295
296 }  // namespace
297
298 PageInfo::PageInfo(std::unique_ptr<PageInfoDelegate> delegate,
299                    content::WebContents* web_contents,
300                    const GURL& url)
301     : web_contents_(web_contents->GetWeakPtr()),
302       delegate_(std::move(delegate)),
303       show_info_bar_(false),
304       site_url_(url),
305       site_identity_status_(SITE_IDENTITY_STATUS_UNKNOWN),
306       safe_browsing_status_(SAFE_BROWSING_STATUS_NONE),
307       safety_tip_info_({security_state::SafetyTipStatus::kUnknown, GURL()}),
308       site_connection_status_(SITE_CONNECTION_STATUS_UNKNOWN),
309       show_ssl_decision_revoke_button_(false),
310       did_revoke_user_ssl_decisions_(false),
311       show_change_password_buttons_(false),
312       did_perform_action_(false) {
313   DCHECK(delegate_);
314   security_level_ = delegate_->GetSecurityLevel();
315   visible_security_state_for_metrics_ = delegate_->GetVisibleSecurityState();
316 #if !BUILDFLAG(IS_ANDROID)
317   isolated_web_app_name_ = delegate_->GetWebAppShortName();
318 #endif
319
320   // TabSpecificContentSetting needs to be created before page load.
321   DCHECK(GetPageSpecificContentSettings());
322   ComputeUIInputs(site_url_);
323
324   // Every time this is created, page info dialog is opened.
325   // So this counts how often the page Info dialog is opened.
326   RecordPageInfoAction(PAGE_INFO_OPENED);
327
328   // Record the time when the page info dialog is opened so the total time it is
329   // open can be measured.
330   start_time_ = base::TimeTicks::Now();
331
332 #if !BUILDFLAG(IS_ANDROID)
333   if (web_contents) {
334     controller_ = delegate_->CreateCookieControlsController();
335     observation_.Observe(controller_.get());
336
337     controller_->Update(web_contents);
338   }
339 #endif
340 }
341
342 PageInfo::~PageInfo() {
343   // Check if Re-enable warnings button was visible, if so, log on UMA whether
344   // it was clicked or not.
345   SSLCertificateDecisionsDidRevoke user_decision =
346       did_revoke_user_ssl_decisions_ ? USER_CERT_DECISIONS_REVOKED
347                                      : USER_CERT_DECISIONS_NOT_REVOKED;
348   if (show_ssl_decision_revoke_button_) {
349     base::UmaHistogramEnumeration(
350         "interstitial.ssl.did_user_revoke_decisions2", user_decision,
351         END_OF_SSL_CERTIFICATE_DECISIONS_DID_REVOKE_ENUM);
352   }
353
354   // Record the total time the Page Info UI was open for all opens as well as
355   // split between whether any action was taken.
356   LogTimeOpenHistogram(security_state::GetSecurityLevelHistogramName(
357                            kPageInfoTimePrefix, security_level_),
358                        start_time_);
359   LogTimeOpenHistogram(security_state::GetSafetyTipHistogramName(
360                            kPageInfoTimePrefix, safety_tip_info_.status),
361                        start_time_);
362   if (did_perform_action_) {
363     LogTimeOpenHistogram(security_state::GetSecurityLevelHistogramName(
364                              kPageInfoTimeActionPrefix, security_level_),
365                          start_time_);
366     LogTimeOpenHistogram(
367         security_state::GetSafetyTipHistogramName(kPageInfoTimeActionPrefix,
368                                                   safety_tip_info_.status),
369         start_time_);
370   } else {
371     LogTimeOpenHistogram(security_state::GetSecurityLevelHistogramName(
372                              kPageInfoTimeNoActionPrefix, security_level_),
373                          start_time_);
374     LogTimeOpenHistogram(
375         security_state::GetSafetyTipHistogramName(kPageInfoTimeNoActionPrefix,
376                                                   safety_tip_info_.status),
377         start_time_);
378   }
379 }
380
381 void PageInfo::OnStatusChanged(CookieControlsStatus status,
382                                CookieControlsEnforcement enforcement,
383                                int allowed_cookies,
384                                int blocked_cookies) {
385 #if !BUILDFLAG(IS_ANDROID)
386   if (base::FeatureList::IsEnabled(page_info::kPageInfoCookiesSubpage)) {
387     if (status != status_ || enforcement != enforcement_) {
388       status_ = status;
389       enforcement_ = enforcement;
390       PresentSiteData(base::DoNothing());
391     }
392   }
393 #endif
394 }
395
396 void PageInfo::OnCookiesCountChanged(int allowed_cookies, int blocked_cookies) {
397 }
398
399 void PageInfo::OnThirdPartyToggleClicked(bool block_third_party_cookies) {
400   DCHECK(status_ != CookieControlsStatus::kDisabled);
401   DCHECK(status_ != CookieControlsStatus::kUninitialized);
402   RecordPageInfoAction(block_third_party_cookies
403                            ? PAGE_INFO_COOKIES_BLOCKED_FOR_SITE
404                            : PAGE_INFO_COOKIES_ALLOWED_FOR_SITE);
405   controller_->OnCookieBlockingEnabledForSite(block_third_party_cookies);
406 }
407
408 // static
409 bool PageInfo::IsPermissionFactoryDefault(const PermissionInfo& info,
410                                           bool is_incognito) {
411   const ContentSetting factory_default_setting =
412       content_settings::ContentSettingsRegistry::GetInstance()
413           ->Get(info.type)
414           ->GetInitialDefaultSetting();
415
416   // Settings that are granted in regular mode get reduced to ASK in incognito
417   // mode. These settings should not be displayed either.
418   const bool is_incognito_default =
419       is_incognito && info.setting == CONTENT_SETTING_ASK &&
420       factory_default_setting == CONTENT_SETTING_ASK;
421
422   return info.source == content_settings::SETTING_SOURCE_USER &&
423          factory_default_setting == info.default_setting &&
424          (info.setting == CONTENT_SETTING_DEFAULT || is_incognito_default);
425 }
426
427 // static
428 bool PageInfo::IsFileOrInternalPage(const GURL& url) {
429   return url.SchemeIs(content::kChromeUIScheme) ||
430          url.SchemeIs(content::kChromeDevToolsScheme) ||
431          url.SchemeIs(content::kViewSourceScheme) ||
432          url.SchemeIs(url::kFileScheme);
433 }
434
435 void PageInfo::InitializeUiState(PageInfoUI* ui, base::OnceClosure done) {
436   ui_ = ui;
437   DCHECK(ui_);
438
439   PresentSitePermissions();
440   PresentSiteIdentity();
441   PresentPageFeatureInfo();
442   PresentSiteData(std::move(done));
443   PresentAdPersonalizationData();
444 }
445
446 void PageInfo::UpdateSecurityState() {
447   ComputeUIInputs(site_url_);
448   PresentSiteIdentity();
449 }
450
451 void PageInfo::RecordPageInfoAction(PageInfoAction action) {
452   if (action != PAGE_INFO_OPENED)
453     did_perform_action_ = true;
454
455 #if !BUILDFLAG(IS_ANDROID)
456   delegate_->OnPageInfoActionOccurred(action);
457 #endif
458
459   base::UmaHistogramEnumeration("WebsiteSettings.Action", action);
460
461   if (web_contents_) {
462     ukm::builders::PageInfoBubble(
463         web_contents_->GetPrimaryMainFrame()->GetPageUkmSourceId())
464         .SetActionTaken(action)
465         .Record(ukm::UkmRecorder::Get());
466   }
467
468   base::UmaHistogramEnumeration(
469       security_state::GetSafetyTipHistogramName(
470           "Security.SafetyTips.PageInfo.Action", safety_tip_info_.status),
471       action);
472
473   auto* settings = GetPageSpecificContentSettings();
474   if (!settings)
475     return;
476
477   bool has_topic = settings->HasAccessedTopics();
478   bool has_fledge = settings->HasJoinedUserToInterestGroup();
479   switch (action) {
480     case PageInfoAction::PAGE_INFO_OPENED:
481       base::RecordAction(base::UserMetricsAction("PageInfo.Opened"));
482       base::UmaHistogramBoolean("Security.PageInfo.AdPersonalizationRowShown",
483                                 has_fledge || has_topic);
484       break;
485     case PageInfoAction::PAGE_INFO_AD_PERSONALIZATION_PAGE_OPENED:
486       if (has_fledge && has_topic) {
487         base::RecordAction(base::UserMetricsAction(
488             "PageInfo.AdPersonalization.OpenedWithFledgeAndTopics"));
489       } else if (has_fledge) {
490         base::RecordAction(base::UserMetricsAction(
491             "PageInfo.AdPersonalization.OpenedWithFledge"));
492       } else if (has_topic) {
493         base::RecordAction(base::UserMetricsAction(
494             "PageInfo.AdPersonalization.OpenedWithTopics"));
495       }
496       break;
497     case PageInfoAction::PAGE_INFO_AD_PERSONALIZATION_SETTINGS_OPENED:
498       base::RecordAction(base::UserMetricsAction(
499           "PageInfo.AdPersonalization.ManageInterestClicked"));
500       break;
501     case PAGE_INFO_CERTIFICATE_DIALOG_OPENED:
502       base::RecordAction(
503           base::UserMetricsAction("PageInfo.Security.Certificate.Opened"));
504       break;
505     case PAGE_INFO_CONNECTION_HELP_OPENED:
506       base::RecordAction(
507           base::UserMetricsAction("PageInfo.Security.ConnectionHelp.Opened"));
508       break;
509     case PAGE_INFO_SECURITY_DETAILS_OPENED:
510       base::RecordAction(base::UserMetricsAction("PageInfo.Security.Opened"));
511       break;
512     case PAGE_INFO_SITE_SETTINGS_OPENED:
513       base::RecordAction(
514           base::UserMetricsAction("PageInfo.SiteSettings.Opened"));
515       break;
516     case PAGE_INFO_COOKIES_DIALOG_OPENED:
517       base::RecordAction(base::UserMetricsAction("PageInfo.Cookies.Opened"));
518       break;
519     case PAGE_INFO_COOKIES_ALLOWED_FOR_SITE:
520       base::RecordAction(base::UserMetricsAction("PageInfo.Cookies.Allowed"));
521       break;
522     case PAGE_INFO_COOKIES_BLOCKED_FOR_SITE:
523       base::RecordAction(base::UserMetricsAction("PageInfo.Cookies.Blocked"));
524       break;
525     case PAGE_INFO_COOKIES_CLEARED:
526       base::RecordAction(base::UserMetricsAction("PageInfo.Cookies.Cleared"));
527       break;
528     case PAGE_INFO_PERMISSION_DIALOG_OPENED:
529       base::RecordAction(base::UserMetricsAction("PageInfo.Permission.Opened"));
530       break;
531     case PAGE_INFO_CHANGED_PERMISSION:
532       base::RecordAction(
533           base::UserMetricsAction("PageInfo.Permission.Changed"));
534       break;
535     case PAGE_INFO_PERMISSIONS_CLEARED:
536       base::RecordAction(
537           base::UserMetricsAction("PageInfo.Permission.Cleared"));
538       break;
539     case PAGE_INFO_CHOOSER_OBJECT_DELETED:
540       base::RecordAction(
541           base::UserMetricsAction("PageInfo.Permission.ChooserObjectDeleted"));
542       break;
543     case PAGE_INFO_RESET_DECISIONS_CLICKED:
544       base::RecordAction(
545           base::UserMetricsAction("PageInfo.Permission.ResetDecisions"));
546       break;
547     case PAGE_INFO_FORGET_SITE_OPENED:
548       base::RecordAction(base::UserMetricsAction("PageInfo.ForgetSite.Opened"));
549       break;
550     case PAGE_INFO_FORGET_SITE_CLEARED:
551       base::RecordAction(
552           base::UserMetricsAction("PageInfo.ForgetSite.Cleared"));
553       break;
554     case PAGE_INFO_HISTORY_OPENED:
555       base::RecordAction(base::UserMetricsAction("PageInfo.History.Opened"));
556       break;
557     case PAGE_INFO_HISTORY_ENTRY_REMOVED:
558       base::RecordAction(
559           base::UserMetricsAction("PageInfo.History.EntryRemoved"));
560       break;
561     case PAGE_INFO_HISTORY_ENTRY_CLICKED:
562       base::RecordAction(
563           base::UserMetricsAction("PageInfo.History.EntryClicked"));
564       break;
565     case PAGE_INFO_PASSWORD_REUSE_ALLOWED:
566       base::RecordAction(
567           base::UserMetricsAction("PageInfo.PasswordReuseAllowed"));
568       break;
569     case PAGE_INFO_CHANGE_PASSWORD_PRESSED:
570       base::RecordAction(
571           base::UserMetricsAction("PageInfo.ChangePasswordPressed"));
572       break;
573     case PAGE_INFO_SAFETY_TIP_HELP_OPENED:
574       base::RecordAction(
575           base::UserMetricsAction("PageInfo.SafetyTip.HelpOpened"));
576       break;
577     case PAGE_INFO_STORE_INFO_CLICKED:
578       base::RecordAction(base::UserMetricsAction("PageInfo.StoreInfo.Opened"));
579       break;
580     case PAGE_INFO_ABOUT_THIS_SITE_PAGE_OPENED:
581       base::RecordAction(
582           base::UserMetricsAction("PageInfo.AboutThisSite.Opened"));
583       break;
584     case PAGE_INFO_ABOUT_THIS_SITE_SOURCE_LINK_CLICKED:
585       base::RecordAction(
586           base::UserMetricsAction("PageInfo.AboutThisSite.SourceLinkClicked"));
587       break;
588     case PAGE_INFO_ABOUT_THIS_SITE_MORE_ABOUT_CLICKED:
589       base::RecordAction(
590           base::UserMetricsAction("PageInfo.AboutThisSite.MoreAboutClicked"));
591       break;
592     case PAGE_INFO_COOKIES_PAGE_OPENED:
593       base::RecordAction(
594           base::UserMetricsAction("PageInfo.CookiesSubpage.Opened"));
595       break;
596     case PAGE_INFO_COOKIES_SETTINGS_OPENED:
597       base::RecordAction(base::UserMetricsAction(
598           "PageInfo.CookiesSubpage.SettingsLinkClicked"));
599       break;
600     case PAGE_INFO_ALL_SITES_WITH_FPS_FILTER_OPENED:
601       base::RecordAction(base::UserMetricsAction(
602           "PageInfo.CookiesSubpage.AllSitesFilteredOpened"));
603       break;
604   }
605 }
606
607 void PageInfo::UpdatePermissions() {
608   // Refresh the UI to reflect the new setting.
609   PresentSitePermissions();
610 }
611
612 void PageInfo::OnSitePermissionChanged(ContentSettingsType type,
613                                        ContentSetting setting,
614                                        bool is_one_time) {
615   ContentSettingChangedViaPageInfo(type);
616
617   // Count how often a permission for a specific content type is changed using
618   // the Page Info UI.
619   size_t num_values;
620   int histogram_value = ContentSettingTypeToHistogramValue(type, &num_values);
621   base::UmaHistogramExactLinear("WebsiteSettings.OriginInfo.PermissionChanged",
622                                 histogram_value, num_values);
623
624   if (setting == ContentSetting::CONTENT_SETTING_ALLOW) {
625     base::UmaHistogramExactLinear(
626         "WebsiteSettings.OriginInfo.PermissionChanged.Allowed", histogram_value,
627         num_values);
628   } else if (setting == ContentSetting::CONTENT_SETTING_BLOCK) {
629     base::UmaHistogramExactLinear(
630         "WebsiteSettings.OriginInfo.PermissionChanged.Blocked", histogram_value,
631         num_values);
632   }
633
634   // This is technically redundant given the histogram above, but putting the
635   // total count of permission changes in another histogram makes it easier to
636   // compare it against other kinds of actions in Page Info.
637   RecordPageInfoAction(PAGE_INFO_CHANGED_PERMISSION);
638   HostContentSettingsMap* content_settings = GetContentSettings();
639   if (type == ContentSettingsType::SOUND) {
640     ContentSetting default_setting = content_settings->GetDefaultContentSetting(
641         ContentSettingsType::SOUND, nullptr);
642     bool mute = (setting == CONTENT_SETTING_BLOCK) ||
643                 (setting == CONTENT_SETTING_DEFAULT &&
644                  default_setting == CONTENT_SETTING_BLOCK);
645     if (mute) {
646       base::RecordAction(
647           base::UserMetricsAction("SoundContentSetting.MuteBy.PageInfo"));
648     } else {
649       base::RecordAction(
650           base::UserMetricsAction("SoundContentSetting.UnmuteBy.PageInfo"));
651     }
652   }
653
654   DCHECK(web_contents_);
655   permissions::PermissionUmaUtil::ScopedRevocationReporter
656       scoped_revocation_reporter(web_contents_->GetBrowserContext(), site_url_,
657                                  site_url_, type,
658                                  permissions::PermissionSourceUI::OIB);
659
660   // The permission may have been blocked due to being under embargo, so if it
661   // was changed away from BLOCK, clear embargo status if it exists.
662   if (setting != CONTENT_SETTING_BLOCK) {
663     delegate_->GetPermissionDecisionAutoblocker()->RemoveEmbargoAndResetCounts(
664         site_url_, type);
665   }
666   using Constraints = content_settings::ContentSettingConstraints;
667   content_settings->SetNarrowestContentSetting(
668       site_url_, site_url_, type, setting,
669       is_one_time
670           ? Constraints{base::Time(), content_settings::SessionModel::OneTime}
671           : Constraints{});
672
673   // When the sound setting is changed, no reload is necessary.
674   if (type != ContentSettingsType::SOUND)
675     show_info_bar_ = true;
676
677   // Refresh the UI to reflect the new setting.
678   PresentSitePermissions();
679 }
680
681 void PageInfo::OnSiteChosenObjectDeleted(const ChooserUIInfo& ui_info,
682                                          const base::Value& object) {
683   permissions::ObjectPermissionContextBase* context =
684       delegate_->GetChooserContext(ui_info.content_settings_type);
685   const auto origin = url::Origin::Create(site_url_);
686   context->RevokeObjectPermission(origin, object);
687   show_info_bar_ = true;
688
689   // Refresh the UI to reflect the changed settings.
690   PresentSitePermissions();
691   RecordPageInfoAction(PAGE_INFO_CHOOSER_OBJECT_DELETED);
692 }
693
694 void PageInfo::OnUIClosing(bool* reload_prompt) {
695   if (reload_prompt)
696     *reload_prompt = false;
697 #if BUILDFLAG(IS_ANDROID)
698   NOTREACHED();
699 #else
700   if (show_info_bar_ && web_contents_ && !web_contents_->IsBeingDestroyed()) {
701     if (delegate_->CreateInfoBarDelegate() && reload_prompt)
702       *reload_prompt = true;
703   }
704   delegate_->OnUIClosing();
705 #endif
706 }
707
708 void PageInfo::OnRevokeSSLErrorBypassButtonPressed() {
709   auto* stateful_ssl_host_state_delegate =
710       delegate_->GetStatefulSSLHostStateDelegate();
711   DCHECK(stateful_ssl_host_state_delegate);
712   stateful_ssl_host_state_delegate->RevokeUserAllowExceptionsHard(
713       site_url().host());
714   did_revoke_user_ssl_decisions_ = true;
715   RecordPageInfoAction(PAGE_INFO_RESET_DECISIONS_CLICKED);
716 }
717
718 void PageInfo::OpenSiteSettingsView() {
719 #if BUILDFLAG(IS_ANDROID)
720   NOTREACHED();
721 #else
722   RecordPageInfoAction(PAGE_INFO_SITE_SETTINGS_OPENED);
723   delegate_->ShowSiteSettings(site_url());
724 #endif
725 }
726
727 void PageInfo::OpenCookiesSettingsView() {
728 #if BUILDFLAG(IS_ANDROID)
729   NOTREACHED();
730 #else
731   RecordPageInfoAction(PAGE_INFO_COOKIES_SETTINGS_OPENED);
732   delegate_->ShowCookiesSettings();
733 #endif
734 }
735
736 void PageInfo::OpenAllSitesViewFilteredToFps() {
737 #if BUILDFLAG(IS_ANDROID)
738   NOTREACHED();
739 #else
740   auto fps_owner = delegate_->GetFpsOwner(site_url_);
741   RecordPageInfoAction(PAGE_INFO_ALL_SITES_WITH_FPS_FILTER_OPENED);
742   if (fps_owner)
743     delegate_->ShowAllSitesSettingsFilteredByFpsOwner(*fps_owner);
744   else
745     delegate_->ShowAllSitesSettingsFilteredByFpsOwner(std::u16string());
746
747 #endif
748 }
749
750 void PageInfo::OpenCookiesDialog() {
751 #if BUILDFLAG(IS_ANDROID)
752   NOTREACHED();
753 #else
754   if (!web_contents_ || web_contents_->IsBeingDestroyed())
755     return;
756
757   RecordPageInfoAction(PAGE_INFO_COOKIES_DIALOG_OPENED);
758   delegate_->OpenCookiesDialog();
759 #endif
760 }
761
762 void PageInfo::OpenCertificateDialog(net::X509Certificate* certificate) {
763 #if BUILDFLAG(IS_ANDROID)
764   NOTREACHED();
765 #else
766   if (!web_contents_ || web_contents_->IsBeingDestroyed())
767     return;
768
769   gfx::NativeWindow top_window = web_contents_->GetTopLevelNativeWindow();
770   if (certificate && top_window) {
771     RecordPageInfoAction(PAGE_INFO_CERTIFICATE_DIALOG_OPENED);
772     delegate_->OpenCertificateDialog(certificate);
773   }
774 #endif
775 }
776
777 void PageInfo::OpenSafetyTipHelpCenterPage() {
778 #if BUILDFLAG(IS_ANDROID)
779   NOTREACHED();
780 #else
781   RecordPageInfoAction(PAGE_INFO_SAFETY_TIP_HELP_OPENED);
782   delegate_->OpenSafetyTipHelpCenterPage();
783 #endif
784 }
785
786 void PageInfo::OpenConnectionHelpCenterPage(const ui::Event& event) {
787 #if BUILDFLAG(IS_ANDROID)
788   NOTREACHED();
789 #else
790   RecordPageInfoAction(PAGE_INFO_CONNECTION_HELP_OPENED);
791   delegate_->OpenConnectionHelpCenterPage(event);
792 #endif
793 }
794
795 void PageInfo::OpenContentSettingsExceptions(
796     ContentSettingsType content_settings_type) {
797 #if BUILDFLAG(IS_ANDROID)
798   NOTREACHED();
799 #else
800   RecordPageInfoAction(PAGE_INFO_CONNECTION_HELP_OPENED);
801   delegate_->OpenContentSettingsExceptions(content_settings_type);
802 #endif
803 }
804
805 void PageInfo::OnChangePasswordButtonPressed() {
806 #if BUILDFLAG(FULL_SAFE_BROWSING)
807   RecordPageInfoAction(PAGE_INFO_CHANGE_PASSWORD_PRESSED);
808   delegate_->OnUserActionOnPasswordUi(
809       safe_browsing::WarningAction::CHANGE_PASSWORD);
810 #endif
811 }
812
813 void PageInfo::OnAllowlistPasswordReuseButtonPressed() {
814 #if BUILDFLAG(FULL_SAFE_BROWSING)
815   RecordPageInfoAction(PAGE_INFO_PASSWORD_REUSE_ALLOWED);
816   delegate_->OnUserActionOnPasswordUi(
817       safe_browsing::WarningAction::MARK_AS_LEGITIMATE);
818 #endif
819 }
820
821 permissions::ObjectPermissionContextBase* PageInfo::GetChooserContextFromUIInfo(
822     const ChooserUIInfo& ui_info) const {
823   return delegate_->GetChooserContext(ui_info.content_settings_type);
824 }
825
826 std::u16string PageInfo::GetSimpleSiteName() const {
827   if (!site_name_for_testing_.empty())
828     return site_name_for_testing_;
829
830   return url_formatter::FormatUrlForDisplayOmitSchemePathAndTrivialSubdomains(
831       site_url_);
832 }
833
834 std::u16string PageInfo::GetSiteOriginOrAppNameToDisplay() const {
835   return IsIsolatedWebApp() && !isolated_web_app_name_.empty()
836              ? isolated_web_app_name_
837              : GetSimpleSiteName();
838 }
839
840 void PageInfo::ComputeUIInputs(const GURL& url) {
841   auto security_level = delegate_->GetSecurityLevel();
842   auto visible_security_state = delegate_->GetVisibleSecurityState();
843 #if !BUILDFLAG(IS_ANDROID)
844   // On desktop, internal URLs aren't handled by this class. Instead, a
845   // custom and simpler bubble is shown.
846   DCHECK(!url.SchemeIs(content::kChromeUIScheme) &&
847          !url.SchemeIs(content::kChromeDevToolsScheme) &&
848          !url.SchemeIs(content::kViewSourceScheme) &&
849          !url.SchemeIs(content_settings::kExtensionScheme));
850 #endif
851
852   bool is_chrome_ui_native_scheme = false;
853 #if BUILDFLAG(IS_ANDROID)
854   is_chrome_ui_native_scheme = url.SchemeIs(browser_ui::kChromeUINativeScheme);
855 #endif
856
857   if (url.SchemeIs(url::kAboutScheme)) {
858     // All about: URLs except about:blank are redirected.
859     DCHECK_EQ(url::kAboutBlankURL, url.spec());
860     site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT;
861 #if BUILDFLAG(IS_ANDROID)
862     identity_status_description_android_ =
863         l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY);
864 #endif
865     site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED;
866     site_connection_details_ = l10n_util::GetStringFUTF16(
867         IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
868         UTF8ToUTF16(url.spec()));
869     return;
870   }
871
872   if (url.SchemeIs(content::kChromeUIScheme) || is_chrome_ui_native_scheme) {
873     site_identity_status_ = SITE_IDENTITY_STATUS_INTERNAL_PAGE;
874 #if BUILDFLAG(IS_ANDROID)
875     identity_status_description_android_ =
876         l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE);
877 #endif
878     site_connection_status_ = SITE_CONNECTION_STATUS_INTERNAL_PAGE;
879     return;
880   }
881
882   // Identity section.
883   certificate_ = visible_security_state.certificate;
884
885   if (certificate_ &&
886       (!net::IsCertStatusError(visible_security_state.cert_status))) {
887     // HTTPS with no or minor errors.
888     if (security_level == security_state::SECURE_WITH_POLICY_INSTALLED_CERT) {
889 #if BUILDFLAG(IS_CHROMEOS_ASH)
890       site_identity_status_ = SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT;
891 #else
892       DCHECK(false) << "Policy certificates exist only on ChromeOS";
893 #endif
894     } else {
895       // No major or minor errors.
896       if (visible_security_state.cert_status & net::CERT_STATUS_IS_EV) {
897         // EV HTTPS page.
898         site_identity_status_ = SITE_IDENTITY_STATUS_EV_CERT;
899       } else {
900         // Non-EV OK HTTPS page.
901         site_identity_status_ = SITE_IDENTITY_STATUS_CERT;
902         std::u16string issuer_name(
903             UTF8ToUTF16(certificate_->issuer().GetDisplayName()));
904         if (issuer_name.empty()) {
905           issuer_name.assign(l10n_util::GetStringUTF16(
906               IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
907         }
908
909 #if BUILDFLAG(IS_ANDROID)
910         // This string is shown on all non-error HTTPS sites on Android when
911         // the user taps "Details" link on page info.
912         identity_status_description_android_.assign(l10n_util::GetStringFUTF16(
913             IDS_PAGE_INFO_SECURE_IDENTITY_VERIFIED,
914             delegate_->GetClientApplicationName(), issuer_name));
915 #endif
916       }
917       if (security_state::IsSHA1InChain(visible_security_state)) {
918         site_identity_status_ =
919             SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM;
920
921 #if BUILDFLAG(IS_ANDROID)
922         identity_status_description_android_ +=
923             u"\n\n" +
924             l10n_util::GetStringUTF16(
925                 IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM);
926 #endif
927       }
928     }
929   } else {
930     // HTTP or HTTPS with errors (not warnings).
931     if (!security_state::IsSchemeCryptographic(visible_security_state.url) ||
932         !visible_security_state.certificate) {
933       site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT;
934     } else {
935       site_identity_status_ = SITE_IDENTITY_STATUS_ERROR;
936     }
937 #if BUILDFLAG(IS_ANDROID)
938     const std::u16string bullet = u"\n â€¢ ";
939     std::vector<ssl_errors::ErrorInfo> errors;
940     ssl_errors::ErrorInfo::GetErrorsForCertStatus(
941         certificate_, visible_security_state.cert_status, url, &errors);
942
943     identity_status_description_android_.assign(l10n_util::GetStringUTF16(
944         IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY));
945     for (const ssl_errors::ErrorInfo& error : errors) {
946       identity_status_description_android_ += bullet;
947       identity_status_description_android_ += error.short_description();
948     }
949
950     if (visible_security_state.cert_status & net::CERT_STATUS_NON_UNIQUE_NAME) {
951       identity_status_description_android_ += u"\n\n";
952       identity_status_description_android_ +=
953           l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME);
954     }
955 #endif
956   }
957
958   if (visible_security_state.malicious_content_status !=
959       security_state::MALICIOUS_CONTENT_STATUS_NONE) {
960     // The site has been flagged by Safe Browsing. Takes precedence over TLS.
961     GetSafeBrowsingStatusByMaliciousContentStatus(
962         visible_security_state.malicious_content_status, &safe_browsing_status_,
963         &safe_browsing_details_);
964 #if BUILDFLAG(IS_ANDROID)
965     identity_status_description_android_ = safe_browsing_details_;
966 #endif
967
968 #if BUILDFLAG(FULL_SAFE_BROWSING)
969     bool old_show_change_pw_buttons = show_change_password_buttons_;
970 #endif
971     show_change_password_buttons_ =
972         (visible_security_state.malicious_content_status ==
973              security_state::
974                  MALICIOUS_CONTENT_STATUS_SIGNED_IN_SYNC_PASSWORD_REUSE ||
975          visible_security_state.malicious_content_status ==
976              security_state::
977                  MALICIOUS_CONTENT_STATUS_SIGNED_IN_NON_SYNC_PASSWORD_REUSE ||
978          visible_security_state.malicious_content_status ==
979              security_state::
980                  MALICIOUS_CONTENT_STATUS_ENTERPRISE_PASSWORD_REUSE ||
981          visible_security_state.malicious_content_status ==
982              security_state::MALICIOUS_CONTENT_STATUS_SAVED_PASSWORD_REUSE);
983 #if BUILDFLAG(FULL_SAFE_BROWSING)
984     // Only record password reuse when adding the button, not on updates.
985     if (show_change_password_buttons_ && !old_show_change_pw_buttons) {
986       RecordPasswordReuseEvent();
987     }
988 #endif
989   }
990
991   safety_tip_info_ = visible_security_state.safety_tip_info;
992 #if BUILDFLAG(IS_ANDROID)
993   // identity_status_description_android_ is only displayed on Android when
994   // the user taps "Details" link on the page info. Reuse the description from
995   // page info UI.
996   std::unique_ptr<PageInfoUI::SecurityDescription> security_description =
997       PageInfoUI::CreateSafetyTipSecurityDescription(safety_tip_info_);
998   if (security_description) {
999     identity_status_description_android_ = security_description->details;
1000   }
1001 #endif
1002
1003   // Site Connection
1004   // We consider anything less than 80 bits encryption to be weak encryption.
1005   // TODO(wtc): Bug 1198735: report mixed/unsafe content for unencrypted and
1006   // weakly encrypted connections.
1007   site_connection_status_ = SITE_CONNECTION_STATUS_UNKNOWN;
1008
1009   std::u16string subject_name(GetSimpleSiteName());
1010   if (subject_name.empty()) {
1011     subject_name.assign(
1012         l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
1013   }
1014
1015   if (!visible_security_state.certificate ||
1016       !security_state::IsSchemeCryptographic(visible_security_state.url)) {
1017     // Page is still loading (so SSL status is not yet available) or
1018     // loaded over HTTP or loaded over HTTPS with no cert.
1019     site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED;
1020
1021     site_connection_details_.assign(l10n_util::GetStringFUTF16(
1022         IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
1023         subject_name));
1024   } else if (!visible_security_state.connection_info_initialized) {
1025     DCHECK_NE(security_level, security_state::NONE);
1026     site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
1027   } else {
1028     site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED;
1029
1030     if (net::ObsoleteSSLStatus(
1031             visible_security_state.connection_status,
1032             visible_security_state.peer_signature_algorithm) ==
1033         net::OBSOLETE_SSL_NONE) {
1034       site_connection_details_.assign(l10n_util::GetStringFUTF16(
1035           IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT, subject_name));
1036     } else {
1037       site_connection_details_.assign(l10n_util::GetStringFUTF16(
1038           IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT,
1039           subject_name));
1040     }
1041
1042     ReportAnyInsecureContent(visible_security_state, &site_connection_status_,
1043                              &site_connection_details_);
1044   }
1045
1046   uint16_t cipher_suite = net::SSLConnectionStatusToCipherSuite(
1047       visible_security_state.connection_status);
1048   if (visible_security_state.connection_info_initialized && cipher_suite) {
1049     int ssl_version = net::SSLConnectionStatusToVersion(
1050         visible_security_state.connection_status);
1051     const char* ssl_version_str;
1052     net::SSLVersionToString(&ssl_version_str, ssl_version);
1053     site_connection_details_ += u"\n\n";
1054     site_connection_details_ += l10n_util::GetStringFUTF16(
1055         IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION, ASCIIToUTF16(ssl_version_str));
1056
1057     const char *key_exchange, *cipher, *mac;
1058     bool is_aead, is_tls13;
1059     net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
1060                                  &is_tls13, cipher_suite);
1061
1062     site_connection_details_ += u"\n\n";
1063     if (is_aead) {
1064       if (is_tls13) {
1065         // For TLS 1.3 ciphers, report the group (historically, curve) as the
1066         // key exchange.
1067         key_exchange =
1068             SSL_get_curve_name(visible_security_state.key_exchange_group);
1069         if (!key_exchange) {
1070           NOTREACHED();
1071           key_exchange = "";
1072         }
1073       }
1074       site_connection_details_ += l10n_util::GetStringFUTF16(
1075           IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS_AEAD,
1076           ASCIIToUTF16(cipher), ASCIIToUTF16(key_exchange));
1077     } else {
1078       site_connection_details_ += l10n_util::GetStringFUTF16(
1079           IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS, ASCIIToUTF16(cipher),
1080           ASCIIToUTF16(mac), ASCIIToUTF16(key_exchange));
1081     }
1082   }
1083
1084   // Check if a user decision has been made to allow or deny certificates with
1085   // errors on this site.
1086   StatefulSSLHostStateDelegate* delegate =
1087       delegate_->GetStatefulSSLHostStateDelegate();
1088   DCHECK(delegate);
1089   // Only show an SSL decision revoke button if the user has chosen to bypass
1090   // SSL host errors for this host in the past, and we're not presently on a
1091   // Safe Browsing error (since otherwise it's confusing which warning you're
1092   // re-enabling).
1093   DCHECK(web_contents_);
1094   show_ssl_decision_revoke_button_ =
1095       delegate->HasAllowException(
1096           url.host(),
1097           web_contents_->GetPrimaryMainFrame()->GetStoragePartition()) &&
1098       visible_security_state.malicious_content_status ==
1099           security_state::MALICIOUS_CONTENT_STATUS_NONE;
1100 }
1101
1102 void PageInfo::PresentSitePermissions() {
1103   PermissionInfoList permission_info_list;
1104   ChosenObjectInfoList chosen_object_info_list;
1105
1106   PermissionInfo permission_info;
1107   HostContentSettingsMap* content_settings = GetContentSettings();
1108   DCHECK(web_contents_);
1109   for (const ContentSettingsType type : kPermissionType) {
1110     permission_info.type = type;
1111
1112     content_settings::SettingInfo info;
1113
1114     // TODO(crbug.com/1030245) Investigate why the value is queried from the low
1115     // level routine GetWebsiteSettings.
1116     const base::Value value = content_settings->GetWebsiteSetting(
1117         site_url_, site_url_, permission_info.type, &info);
1118     if (value.is_int()) {
1119       permission_info.setting = content_settings::ValueToContentSetting(value);
1120     } else {
1121       NOTREACHED();
1122     }
1123
1124     permission_info.source = info.source;
1125     permission_info.is_one_time = (info.metadata.session_model ==
1126                                    content_settings::SessionModel::OneTime);
1127
1128     if (info.primary_pattern == ContentSettingsPattern::Wildcard() &&
1129         info.secondary_pattern == ContentSettingsPattern::Wildcard()) {
1130       permission_info.default_setting = permission_info.setting;
1131       permission_info.setting = CONTENT_SETTING_DEFAULT;
1132     } else {
1133       permission_info.default_setting =
1134           content_settings->GetDefaultContentSetting(permission_info.type,
1135                                                      nullptr);
1136     }
1137
1138     // Check embargo status if the content setting supports embargo.
1139     if (permissions::PermissionDecisionAutoBlocker::IsEnabledForContentSetting(
1140             permission_info.type) &&
1141         permission_info.setting == CONTENT_SETTING_DEFAULT &&
1142         permission_info.source ==
1143             content_settings::SettingSource::SETTING_SOURCE_USER) {
1144       permissions::PermissionResult permission_result(
1145           CONTENT_SETTING_DEFAULT,
1146           permissions::PermissionStatusSource::UNSPECIFIED);
1147       if (permissions::PermissionUtil::IsPermission(permission_info.type)) {
1148         permission_result = delegate_->GetPermissionResult(
1149             permissions::PermissionUtil::ContentSettingTypeToPermissionType(
1150                 permission_info.type),
1151             url::Origin::Create(site_url_));
1152       } else if (permission_info.type ==
1153                  ContentSettingsType::FEDERATED_IDENTITY_API) {
1154         absl::optional<permissions::PermissionResult> embargo_result =
1155             delegate_->GetPermissionDecisionAutoblocker()->GetEmbargoResult(
1156                 site_url_, permission_info.type);
1157         if (embargo_result)
1158           permission_result = *embargo_result;
1159       }
1160
1161       // If under embargo, update |permission_info| to reflect that.
1162       if (permission_result.content_setting == CONTENT_SETTING_BLOCK &&
1163           (permission_result.source ==
1164                permissions::PermissionStatusSource::MULTIPLE_DISMISSALS ||
1165            permission_result.source ==
1166                permissions::PermissionStatusSource::MULTIPLE_IGNORES)) {
1167         permission_info.setting = permission_result.content_setting;
1168       }
1169     }
1170
1171     if (ShouldShowPermission(
1172             permission_info, site_url_, content_settings, web_contents_.get(),
1173             HasContentSettingChangedViaPageInfo(permission_info.type),
1174             delegate_->IsSubresourceFilterActivated(site_url_))) {
1175       permission_info_list.push_back(permission_info);
1176     }
1177   }
1178
1179   const auto origin = url::Origin::Create(site_url_);
1180   for (const ChooserUIInfo& ui_info : kChooserUIInfo) {
1181     permissions::ObjectPermissionContextBase* context =
1182         delegate_->GetChooserContext(ui_info.content_settings_type);
1183     if (!context)
1184       continue;
1185     auto chosen_objects = context->GetGrantedObjects(origin);
1186     for (std::unique_ptr<permissions::ObjectPermissionContextBase::Object>&
1187              object : chosen_objects) {
1188       chosen_object_info_list.push_back(
1189           std::make_unique<PageInfoUI::ChosenObjectInfo>(ui_info,
1190                                                          std::move(object)));
1191     }
1192   }
1193
1194   ui_->SetPermissionInfo(permission_info_list,
1195                          std::move(chosen_object_info_list));
1196 }
1197
1198 void PageInfo::PresentSiteDataInternal(base::OnceClosure done) {
1199   // Since this is called asynchronously, the associated `WebContents` object
1200   // might no longer be available.
1201   if (!web_contents_ || web_contents_->IsBeingDestroyed())
1202     return;
1203
1204   bool is_cookies_subpage_enabled = false;
1205 #if !BUILDFLAG(IS_ANDROID)
1206   is_cookies_subpage_enabled =
1207       base::FeatureList::IsEnabled(page_info::kPageInfoCookiesSubpage);
1208 #endif
1209
1210   if (is_cookies_subpage_enabled) {
1211     // Add allowed sites count.
1212     PageInfoUI::CookiesNewInfo cookies_info;
1213     cookies_info.allowed_sites_count = GetSitesWithAllowedCookiesAccessCount();
1214     cookies_info.blocked_sites_count =
1215         GetThirdPartySitesWithBlockedCookiesAccessCount(site_url_);
1216
1217 #if !BUILDFLAG(IS_ANDROID)
1218     if (base::FeatureList::IsEnabled(
1219             privacy_sandbox::kPrivacySandboxFirstPartySetsUI)) {
1220       auto fps_owner = delegate_->GetFpsOwner(site_url_);
1221       if (fps_owner) {
1222         cookies_info.fps_info = PageInfoUI::CookiesFpsInfo(*fps_owner);
1223         cookies_info.fps_info->is_managed = delegate_->IsFpsManaged();
1224       }
1225     }
1226 #endif
1227
1228     cookies_info.status = status_;
1229     cookies_info.enforcement = enforcement_;
1230     ui_->SetCookieInfo(cookies_info);
1231   } else {
1232     CookieInfoList cookie_info_list;
1233
1234     // Add first party cookie and site data counts.
1235     PageInfoUI::CookieInfo cookie_info;
1236     cookie_info.allowed = GetFirstPartyAllowedCookiesCount(site_url_);
1237     cookie_info.blocked = GetFirstPartyBlockedCookiesCount(site_url_);
1238     cookie_info.is_first_party = true;
1239     cookie_info_list.push_back(cookie_info);
1240
1241     // Add third party cookie counts.
1242     cookie_info.allowed = GetThirdPartyAllowedCookiesCount(site_url_);
1243     cookie_info.blocked = GetThirdPartyBlockedCookiesCount(site_url_);
1244     cookie_info.is_first_party = false;
1245     cookie_info_list.push_back(cookie_info);
1246
1247     ui_->SetCookieInfo(cookie_info_list);
1248   }
1249
1250   std::move(done).Run();
1251 }
1252
1253 void PageInfo::PresentSiteData(base::OnceClosure done) {
1254   auto* settings = GetPageSpecificContentSettings();
1255   if (settings) {
1256     settings->allowed_local_shared_objects().UpdateIgnoredEmptyStorageKeys(
1257         base::BindOnce(&PageInfo::PresentSiteDataInternal,
1258                        weak_factory_.GetWeakPtr(), std::move(done)));
1259   }
1260 }
1261
1262 void PageInfo::PresentSiteIdentity() {
1263   // After initialization the status about the site's connection and its
1264   // identity must be available.
1265   DCHECK_NE(site_identity_status_, SITE_IDENTITY_STATUS_UNKNOWN);
1266   DCHECK_NE(site_connection_status_, SITE_CONNECTION_STATUS_UNKNOWN);
1267   PageInfoUI::IdentityInfo info;
1268   info.site_identity = UTF16ToUTF8(GetSimpleSiteName());
1269
1270   info.connection_status = site_connection_status_;
1271   info.connection_status_description = UTF16ToUTF8(site_connection_details_);
1272   info.identity_status = site_identity_status_;
1273   info.safe_browsing_status = safe_browsing_status_;
1274   info.safe_browsing_details = safe_browsing_details_;
1275   info.safety_tip_info = safety_tip_info_;
1276 #if BUILDFLAG(IS_ANDROID)
1277   info.identity_status_description_android =
1278       UTF16ToUTF8(identity_status_description_android_);
1279 #endif
1280
1281   info.certificate = certificate_;
1282   info.show_ssl_decision_revoke_button = show_ssl_decision_revoke_button_;
1283   info.show_change_password_buttons = show_change_password_buttons_;
1284   ui_->SetIdentityInfo(info);
1285 }
1286
1287 void PageInfo::PresentPageFeatureInfo() {
1288   PageInfoUI::PageFeatureInfo info;
1289   info.is_vr_presentation_in_headset =
1290       delegate_->IsContentDisplayedInVrHeadset();
1291
1292   ui_->SetPageFeatureInfo(info);
1293 }
1294
1295 void PageInfo::PresentAdPersonalizationData() {
1296   PageInfoUI::AdPersonalizationInfo info;
1297   auto* settings = GetPageSpecificContentSettings();
1298   if (!settings)
1299     return;
1300
1301   info.has_joined_user_to_interest_group =
1302       settings->HasJoinedUserToInterestGroup();
1303   info.accessed_topics = settings->GetAccessedTopics();
1304   std::sort(info.accessed_topics.begin(), info.accessed_topics.end(),
1305             [](const privacy_sandbox::CanonicalTopic& a,
1306                const privacy_sandbox::CanonicalTopic& b) {
1307               return a.GetLocalizedRepresentation() <
1308                      b.GetLocalizedRepresentation();
1309             });
1310   ui_->SetAdPersonalizationInfo(info);
1311 }
1312
1313 #if BUILDFLAG(FULL_SAFE_BROWSING)
1314 void PageInfo::RecordPasswordReuseEvent() {
1315   auto* password_protection_service = delegate_->GetPasswordProtectionService();
1316   if (!password_protection_service) {
1317     return;
1318   }
1319   safe_browsing::LogWarningAction(
1320       safe_browsing::WarningUIType::PAGE_INFO,
1321       safe_browsing::WarningAction::SHOWN,
1322       password_protection_service
1323           ->reused_password_account_type_for_last_shown_warning());
1324 }
1325 #endif
1326
1327 HostContentSettingsMap* PageInfo::GetContentSettings() const {
1328   return delegate_->GetContentSettings();
1329 }
1330
1331 std::vector<ContentSettingsType> PageInfo::GetAllPermissionsForTesting() {
1332   std::vector<ContentSettingsType> permission_list;
1333   for (const ContentSettingsType type : kPermissionType)
1334     permission_list.push_back(type);
1335
1336   return permission_list;
1337 }
1338
1339 void PageInfo::SetSiteNameForTesting(const std::u16string& site_name) {
1340   site_name_for_testing_ = site_name;
1341   PresentSiteIdentity();
1342 }
1343
1344 void PageInfo::SetIsolatedWebAppNameForTesting(
1345     const std::u16string& isolated_web_app_name) {
1346   is_isolated_web_app_for_testing_ = true;
1347   isolated_web_app_name_ = isolated_web_app_name;
1348 }
1349
1350 void PageInfo::GetSafeBrowsingStatusByMaliciousContentStatus(
1351     security_state::MaliciousContentStatus malicious_content_status,
1352     PageInfo::SafeBrowsingStatus* status,
1353     std::u16string* details) {
1354   switch (malicious_content_status) {
1355     case security_state::MALICIOUS_CONTENT_STATUS_NONE:
1356       NOTREACHED();
1357       break;
1358     case security_state::MALICIOUS_CONTENT_STATUS_MALWARE:
1359       *status = PageInfo::SAFE_BROWSING_STATUS_MALWARE;
1360       *details = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MALWARE_DETAILS);
1361       break;
1362     case security_state::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING:
1363       *status = PageInfo::SAFE_BROWSING_STATUS_SOCIAL_ENGINEERING;
1364       *details =
1365           l10n_util::GetStringUTF16(IDS_PAGE_INFO_SOCIAL_ENGINEERING_DETAILS);
1366       break;
1367     case security_state::MALICIOUS_CONTENT_STATUS_UNWANTED_SOFTWARE:
1368       *status = PageInfo::SAFE_BROWSING_STATUS_UNWANTED_SOFTWARE;
1369       *details =
1370           l10n_util::GetStringUTF16(IDS_PAGE_INFO_UNWANTED_SOFTWARE_DETAILS);
1371       break;
1372     case security_state::MALICIOUS_CONTENT_STATUS_SAVED_PASSWORD_REUSE:
1373 #if BUILDFLAG(FULL_SAFE_BROWSING)
1374       *status = PageInfo::SAFE_BROWSING_STATUS_SAVED_PASSWORD_REUSE;
1375       *details = delegate_->GetWarningDetailText();
1376 #endif
1377       break;
1378     case security_state::MALICIOUS_CONTENT_STATUS_SIGNED_IN_SYNC_PASSWORD_REUSE:
1379 #if BUILDFLAG(FULL_SAFE_BROWSING)
1380       *status = PageInfo::SAFE_BROWSING_STATUS_SIGNED_IN_SYNC_PASSWORD_REUSE;
1381       *details = delegate_->GetWarningDetailText();
1382 #endif
1383       break;
1384     case security_state::
1385         MALICIOUS_CONTENT_STATUS_SIGNED_IN_NON_SYNC_PASSWORD_REUSE:
1386 #if BUILDFLAG(FULL_SAFE_BROWSING)
1387       *status =
1388           PageInfo::SAFE_BROWSING_STATUS_SIGNED_IN_NON_SYNC_PASSWORD_REUSE;
1389       *details = delegate_->GetWarningDetailText();
1390 #endif
1391       break;
1392     case security_state::MALICIOUS_CONTENT_STATUS_ENTERPRISE_PASSWORD_REUSE:
1393 #if BUILDFLAG(FULL_SAFE_BROWSING)
1394       *status = PageInfo::SAFE_BROWSING_STATUS_ENTERPRISE_PASSWORD_REUSE;
1395       *details = delegate_->GetWarningDetailText();
1396 #endif
1397       break;
1398     case security_state::MALICIOUS_CONTENT_STATUS_BILLING:
1399       *status = PageInfo::SAFE_BROWSING_STATUS_BILLING;
1400       *details = l10n_util::GetStringUTF16(IDS_PAGE_INFO_BILLING_DETAILS);
1401       break;
1402   }
1403 }
1404
1405 content_settings::PageSpecificContentSettings*
1406 PageInfo::GetPageSpecificContentSettings() const {
1407   // TODO(https://crbug.com/1103176, https://crbug.com/1233122): PageInfo should
1408   // be per page. Why is it a WebContentsObserver if it is not observing
1409   // anything?
1410   DCHECK(web_contents_);
1411   return content_settings::PageSpecificContentSettings::GetForFrame(
1412       web_contents_->GetPrimaryMainFrame());
1413 }
1414
1415 bool PageInfo::HasContentSettingChangedViaPageInfo(ContentSettingsType type) {
1416   auto* settings = GetPageSpecificContentSettings();
1417   if (!settings)
1418     return false;
1419
1420   return settings->HasContentSettingChangedViaPageInfo(type);
1421 }
1422
1423 void PageInfo::ContentSettingChangedViaPageInfo(ContentSettingsType type) {
1424   auto* settings = GetPageSpecificContentSettings();
1425   if (!settings)
1426     return;
1427
1428   return settings->ContentSettingChangedViaPageInfo(type);
1429 }
1430
1431 int PageInfo::GetFirstPartyAllowedCookiesCount(const GURL& site_url) {
1432   auto* settings = GetPageSpecificContentSettings();
1433   if (!settings)
1434     return 0;
1435   return settings->allowed_local_shared_objects().GetObjectCountForDomain(
1436       site_url);
1437 }
1438
1439 int PageInfo::GetSitesWithAllowedCookiesAccessCount() {
1440   auto* settings = GetPageSpecificContentSettings();
1441   if (!settings)
1442     return 0;
1443   return settings->allowed_local_shared_objects().GetHostCount();
1444 }
1445
1446 int PageInfo::GetThirdPartySitesWithBlockedCookiesAccessCount(
1447     const GURL& site_url) {
1448   auto* settings = GetPageSpecificContentSettings();
1449   if (!settings)
1450     return 0;
1451   return settings->blocked_local_shared_objects().GetHostCount() -
1452          settings->blocked_local_shared_objects().GetHostCountForDomain(
1453              site_url);
1454 }
1455
1456 int PageInfo::GetFirstPartyBlockedCookiesCount(const GURL& site_url) {
1457   auto* settings = GetPageSpecificContentSettings();
1458   if (!settings)
1459     return 0;
1460
1461   return settings->blocked_local_shared_objects().GetObjectCountForDomain(
1462       site_url);
1463 }
1464
1465 int PageInfo::GetThirdPartyAllowedCookiesCount(const GURL& site_url) {
1466   auto* settings = GetPageSpecificContentSettings();
1467   if (!settings)
1468     return 0;
1469
1470   return settings->allowed_local_shared_objects().GetObjectCount() -
1471          GetFirstPartyAllowedCookiesCount(site_url);
1472 }
1473
1474 int PageInfo::GetThirdPartyBlockedCookiesCount(const GURL& site_url) {
1475   auto* settings = GetPageSpecificContentSettings();
1476   if (!settings)
1477     return 0;
1478
1479   return settings->blocked_local_shared_objects().GetObjectCount() -
1480          GetFirstPartyBlockedCookiesCount(site_url);
1481 }
1482
1483 bool PageInfo::IsIsolatedWebApp() const {
1484   if (is_isolated_web_app_for_testing_)
1485     return true;
1486
1487   return web_contents_ &&
1488          web_contents_->GetPrimaryMainFrame()->GetWebExposedIsolationLevel() >=
1489              content::RenderFrameHost::WebExposedIsolationLevel::
1490                  kMaybeIsolatedApplication;
1491 }