| // Copyright 2018 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. |
| |
| #include "chrome/browser/ui/webui/reset_password/reset_password_ui.h" |
| |
| #include "base/bind.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/browser_resources.h" |
| #include "components/safe_browsing/common/safe_browsing_prefs.h" |
| #include "components/safe_browsing/password_protection/password_protection_service.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/url_formatter/url_formatter.h" |
| #include "components/user_prefs/user_prefs.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/navigation_entry.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_ui_data_source.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace safe_browsing { |
| using PasswordReuseEvent = |
| safe_browsing::LoginReputationClientRequest::PasswordReuseEvent; |
| } |
| |
| namespace { |
| |
| constexpr char kStringTypeUMAName[] = "PasswordProtection.InterstitialString"; |
| |
| // Used for UMA metric logging. Please don't reorder. |
| // Indicates which type of strings are shown on this page. |
| enum class StringType { |
| GENERIC_NO_ORG_NAME = 0, |
| GENERIC_WITH_ORG_NAME = 1, |
| WARNING_NO_ORG_NAME = 2, |
| WARNING_WITH_ORG_NAME = 3, |
| kMaxValue = WARNING_WITH_ORG_NAME, |
| }; |
| |
| // Implementation of mojom::ResetPasswordHander. |
| class ResetPasswordHandlerImpl : public mojom::ResetPasswordHandler { |
| public: |
| ResetPasswordHandlerImpl( |
| content::WebContents* web_contents, |
| safe_browsing::ReusedPasswordType password_type, |
| mojo::InterfaceRequest<mojom::ResetPasswordHandler> request) |
| : web_contents_(web_contents), |
| password_type_(password_type), |
| binding_(this, std::move(request)) { |
| DCHECK(web_contents); |
| } |
| |
| ~ResetPasswordHandlerImpl() override {} |
| |
| // mojom::ResetPasswordHandler overrides: |
| void HandlePasswordReset() override { |
| Profile* profile = |
| Profile::FromBrowserContext(web_contents_->GetBrowserContext()); |
| safe_browsing::ChromePasswordProtectionService* service = safe_browsing:: |
| ChromePasswordProtectionService::GetPasswordProtectionService(profile); |
| if (service) { |
| service->OnUserAction(web_contents_, password_type_, |
| safe_browsing::WarningUIType::INTERSTITIAL, |
| safe_browsing::WarningAction::CHANGE_PASSWORD); |
| } |
| } |
| |
| private: |
| content::WebContents* web_contents_; |
| safe_browsing::ReusedPasswordType password_type_; |
| mojo::Binding<mojom::ResetPasswordHandler> binding_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ResetPasswordHandlerImpl); |
| }; |
| |
| // Gets the reused password type from post data, or returns |
| // REUSED_PASSWORD_TYPE_UNKNOWN if post data is not available. |
| safe_browsing::ReusedPasswordType GetPasswordType( |
| content::WebContents* web_contents) { |
| content::NavigationEntry* nav_entry = |
| web_contents->GetController().GetPendingEntry(); |
| if (!nav_entry || !nav_entry->GetHasPostData()) |
| return safe_browsing::PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN; |
| auto& post_data = nav_entry->GetPostData()->elements()->at(0); |
| int post_data_int = -1; |
| if (base::StringToInt(std::string(post_data.bytes(), post_data.length()), |
| &post_data_int)) { |
| return static_cast<safe_browsing::ReusedPasswordType>(post_data_int); |
| } |
| |
| return safe_browsing::PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN; |
| } |
| |
| // Properly format host name based on text direction. |
| base::string16 GetFormattedHostName(const std::string host_name) { |
| base::string16 host = url_formatter::IDNToUnicode(host_name); |
| if (base::i18n::IsRTL()) |
| base::i18n::WrapStringWithLTRFormatting(&host); |
| return host; |
| } |
| |
| } // namespace |
| |
| ResetPasswordUI::ResetPasswordUI(content::WebUI* web_ui) |
| : ui::MojoWebUIController(web_ui), |
| password_type_(GetPasswordType(web_ui->GetWebContents())) { |
| std::unique_ptr<content::WebUIDataSource> html_source( |
| content::WebUIDataSource::Create(chrome::kChromeUIResetPasswordHost)); |
| html_source->AddResourcePath("reset_password.js", IDR_RESET_PASSWORD_JS); |
| html_source->AddResourcePath("reset_password.mojom-lite.js", |
| IDR_RESET_PASSWORD_MOJOM_LITE_JS); |
| html_source->SetDefaultResource(IDR_RESET_PASSWORD_HTML); |
| html_source->AddLocalizedStrings(PopulateStrings()); |
| html_source->UseGzip(); |
| |
| content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(), |
| html_source.release()); |
| |
| AddHandlerToRegistry(base::BindRepeating( |
| &ResetPasswordUI::BindResetPasswordHandler, base::Unretained(this))); |
| } |
| |
| ResetPasswordUI::~ResetPasswordUI() {} |
| |
| void ResetPasswordUI::BindResetPasswordHandler( |
| mojom::ResetPasswordHandlerRequest request) { |
| ui_handler_ = std::make_unique<ResetPasswordHandlerImpl>( |
| web_ui()->GetWebContents(), password_type_, std::move(request)); |
| } |
| |
| base::DictionaryValue ResetPasswordUI::PopulateStrings() const { |
| std::string org_name = |
| safe_browsing::ChromePasswordProtectionService:: |
| GetPasswordProtectionService(Profile::FromWebUI(web_ui())) |
| ->GetOrganizationName(password_type_); |
| bool known_password_type = |
| password_type_ != |
| safe_browsing::PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN; |
| |
| int heading_string_id = known_password_type |
| ? IDS_RESET_PASSWORD_WARNING_HEADING |
| : IDS_RESET_PASSWORD_HEADING; |
| base::string16 explanation_paragraph_string; |
| if (org_name.empty()) { |
| explanation_paragraph_string = l10n_util::GetStringUTF16( |
| known_password_type ? IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH |
| : IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH); |
| UMA_HISTOGRAM_ENUMERATION(kStringTypeUMAName, |
| known_password_type |
| ? StringType::WARNING_NO_ORG_NAME |
| : StringType::GENERIC_NO_ORG_NAME); |
| } else { |
| base::string16 formatted_org_name = GetFormattedHostName(org_name); |
| explanation_paragraph_string = l10n_util::GetStringFUTF16( |
| known_password_type |
| ? IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH_WITH_ORG_NAME |
| : IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH_WITH_ORG_NAME, |
| formatted_org_name); |
| UMA_HISTOGRAM_ENUMERATION(kStringTypeUMAName, |
| known_password_type |
| ? StringType::WARNING_WITH_ORG_NAME |
| : StringType::GENERIC_WITH_ORG_NAME); |
| } |
| |
| base::DictionaryValue load_time_data; |
| load_time_data.SetString("title", |
| l10n_util::GetStringUTF16(IDS_RESET_PASSWORD_TITLE)); |
| load_time_data.SetString("heading", |
| l10n_util::GetStringUTF16(heading_string_id)); |
| load_time_data.SetString("primaryParagraph", explanation_paragraph_string); |
| load_time_data.SetString("primaryButtonText", l10n_util::GetStringUTF16( |
| IDS_RESET_PASSWORD_BUTTON)); |
| return load_time_data; |
| } |