| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/ui/page_info/page_info_mediator.h" |
| |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "components/security_state/core/security_state.h" |
| #include "components/ssl_errors/error_info.h" |
| #include "components/strings/grit/components_chromium_strings.h" |
| #include "components/strings/grit/components_google_chrome_strings.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "ios/chrome/browser/chrome_url_constants.h" |
| #import "ios/chrome/browser/ui/page_info/page_info_config.h" |
| #include "ios/chrome/grit/ios_chromium_strings.h" |
| #include "ios/chrome/grit/ios_strings.h" |
| #include "ios/web/public/security/ssl_status.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "url/gurl.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| namespace { |
| |
| // Build the certificate details based on the |SSLStatus| and the |URL|. |
| NSString* BuildCertificateDetailString(web::SSLStatus& SSLStatus, |
| const GURL& URL) { |
| NSMutableString* certificateDetails = [NSMutableString |
| stringWithString:l10n_util::GetNSString( |
| IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY)]; |
| NSString* bullet = @"\n • "; |
| std::vector<ssl_errors::ErrorInfo> errors; |
| ssl_errors::ErrorInfo::GetErrorsForCertStatus( |
| SSLStatus.certificate, SSLStatus.cert_status, URL, &errors); |
| for (size_t i = 0; i < errors.size(); ++i) { |
| [certificateDetails appendString:bullet]; |
| [certificateDetails |
| appendString:base::SysUTF16ToNSString(errors[i].short_description())]; |
| } |
| |
| return certificateDetails; |
| } |
| |
| // Returns a messages, based on the |messagesComponents|, joined by a spacing. |
| NSString* BuildMessage(NSArray<NSString*>* messageComponents) { |
| DCHECK(messageComponents.count > 0); |
| NSMutableString* message = |
| [NSMutableString stringWithString:messageComponents[0]]; |
| for (NSUInteger index = 1; index < messageComponents.count; index++) { |
| NSString* component = messageComponents[index]; |
| if (component.length == 0) |
| continue; |
| [message appendString:@"\n\n"]; |
| [message appendString:component]; |
| } |
| return message; |
| } |
| |
| } // namespace |
| |
| @implementation PageInfoMediator |
| |
| + (PageInfoConfig*)configurationForURL:(const GURL&)URL |
| SSLStatus:(web::SSLStatus&)status |
| offlinePage:(BOOL)offlinePage { |
| PageInfoConfig* dataHolder = [[PageInfoConfig alloc] init]; |
| if (offlinePage) { |
| dataHolder.title = l10n_util::GetNSString(IDS_IOS_PAGE_INFO_OFFLINE_TITLE); |
| dataHolder.message = l10n_util::GetNSString(IDS_IOS_PAGE_INFO_OFFLINE_PAGE); |
| dataHolder.image = [UIImage imageNamed:@"page_info_offline"]; |
| dataHolder.buttonAction = PageInfoButtonActionReload; |
| return dataHolder; |
| } |
| |
| if (URL.SchemeIs(kChromeUIScheme)) { |
| dataHolder.title = base::SysUTF8ToNSString(URL.spec()); |
| dataHolder.message = l10n_util::GetNSString(IDS_PAGE_INFO_INTERNAL_PAGE); |
| dataHolder.image = nil; |
| dataHolder.buttonAction = PageInfoButtonActionNone; |
| return dataHolder; |
| } |
| |
| // At this point, this is a web page. |
| dataHolder.title = base::SysUTF8ToNSString(URL.host()); |
| dataHolder.buttonAction = PageInfoButtonActionShowHelp; |
| |
| // Summary and details. |
| if (!status.certificate) { |
| // Not HTTPS. This maps to the WARNING security level. Show the grey |
| // triangle icon in page info based on the same logic used to determine |
| // the iconography in the omnibox. |
| if (security_state::ShouldShowDangerTriangleForWarningLevel()) { |
| dataHolder.image = [UIImage imageNamed:@"page_info_bad"]; |
| } else { |
| dataHolder.image = [UIImage imageNamed:@"page_info_info"]; |
| } |
| dataHolder.message = BuildMessage(@[ |
| l10n_util::GetNSString(IDS_PAGE_INFO_NOT_SECURE_SUMMARY), |
| l10n_util::GetNSString(IDS_PAGE_INFO_NOT_SECURE_DETAILS) |
| ]); |
| return dataHolder; |
| } |
| |
| // It is possible to have |SECURITY_STYLE_AUTHENTICATION_BROKEN| and non-error |
| // |cert_status| for WKWebView because |security_style| and |cert_status| |
| // are |
| // calculated using different API, which may lead to different cert |
| // verification results. |
| if (net::IsCertStatusError(status.cert_status) || |
| status.security_style == web::SECURITY_STYLE_AUTHENTICATION_BROKEN) { |
| // HTTPS with major errors |
| dataHolder.image = [UIImage imageNamed:@"page_info_bad"]; |
| |
| NSString* certificateDetails = BuildCertificateDetailString(status, URL); |
| |
| dataHolder.message = BuildMessage(@[ |
| l10n_util::GetNSString(IDS_PAGE_INFO_NOT_SECURE_SUMMARY), |
| l10n_util::GetNSString(IDS_PAGE_INFO_NOT_SECURE_DETAILS), |
| certificateDetails |
| ]); |
| |
| return dataHolder; |
| } |
| |
| // The remaining states are valid HTTPS, or HTTPS with minor errors. |
| |
| base::string16 issuerName( |
| base::UTF8ToUTF16(status.certificate->issuer().GetDisplayName())); |
| // Have certificateDetails be an empty string to help building the message. |
| NSString* certificateDetails = @""; |
| if (!issuerName.empty()) { |
| // Show the issuer name if it's available. |
| // TODO(crbug.com/502470): Implement a certificate viewer instead. |
| certificateDetails = l10n_util::GetNSStringF( |
| IDS_IOS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuerName); |
| } |
| |
| if (status.content_status == web::SSLStatus::DISPLAYED_INSECURE_CONTENT) { |
| // HTTPS with mixed content. This maps to the WARNING security level in M80, |
| // so assume the WARNING state when determining whether to swap the icon for |
| // a grey triangle. This will result in an inconsistency between the omnibox |
| // and page info if the mixed content WARNING feature is disabled. |
| if (security_state::ShouldShowDangerTriangleForWarningLevel()) { |
| dataHolder.image = [UIImage imageNamed:@"page_info_bad"]; |
| } else { |
| dataHolder.image = [UIImage imageNamed:@"page_info_info"]; |
| } |
| dataHolder.message = BuildMessage(@[ |
| l10n_util::GetNSString(IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY), |
| l10n_util::GetNSString(IDS_PAGE_INFO_MIXED_CONTENT_DETAILS), |
| certificateDetails |
| ]); |
| |
| return dataHolder; |
| } |
| |
| // Valid HTTPS |
| dataHolder.image = [UIImage imageNamed:@"page_info_good"]; |
| dataHolder.message = BuildMessage(@[ |
| l10n_util::GetNSString(IDS_PAGE_INFO_SECURE_SUMMARY), |
| l10n_util::GetNSString(IDS_PAGE_INFO_SECURE_DETAILS), certificateDetails |
| ]); |
| |
| DCHECK(!(status.cert_status & net::CERT_STATUS_IS_EV)) |
| << "Extended Validation should be disabled"; |
| |
| return dataHolder; |
| } |
| |
| @end |