| Index: chrome/browser/ui/webui/options/password_manager_handler.cc
|
| diff --git a/chrome/browser/ui/webui/options/password_manager_handler.cc b/chrome/browser/ui/webui/options/password_manager_handler.cc
|
| index 2b10eb8ec8d69bb7dd8c9f2719c909f1d20e517e..2e5421c5f5ec98cb2a1117420c967c1d571f2a64 100644
|
| --- a/chrome/browser/ui/webui/options/password_manager_handler.cc
|
| +++ b/chrome/browser/ui/webui/options/password_manager_handler.cc
|
| @@ -6,25 +6,31 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/command_line.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/metrics/histogram.h"
|
| #include "base/prefs/pref_service.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_split.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/values.h"
|
| #include "chrome/browser/chrome_notification_types.h"
|
| +#include "chrome/browser/password_manager/sync_metrics.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/sync/profile_sync_service.h"
|
| #include "chrome/browser/sync/profile_sync_service_factory.h"
|
| #if defined(OS_WIN) && defined(USE_ASH)
|
| #include "chrome/browser/ui/ash/ash_util.h"
|
| #endif
|
| +#include "chrome/browser/ui/chrome_select_file_policy.h"
|
| #include "chrome/common/pref_names.h"
|
| #include "chrome/common/url_constants.h"
|
| #include "chrome/grit/generated_resources.h"
|
| #include "components/autofill/core/common/password_form.h"
|
| #include "components/password_manager/core/browser/affiliation_utils.h"
|
| +#include "components/password_manager/core/browser/export/password_exporter.h"
|
| #include "components/password_manager/core/browser/password_bubble_experiment.h"
|
| #include "components/password_manager/core/common/experiments.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| #include "content/public/browser/notification_details.h"
|
| #include "content/public/browser/notification_source.h"
|
| #include "content/public/browser/user_metrics.h"
|
| @@ -36,8 +42,25 @@
|
|
|
| namespace options {
|
|
|
| -PasswordManagerHandler::PasswordManagerHandler()
|
| - : password_manager_presenter_(this) {}
|
| +namespace {
|
| +
|
| +// Enumeration of different callers of SelectFile. Starting count at 1 so
|
| +// accidental call of SelectFile with params=NULL will error out.
|
| +enum {
|
| + IMPORT_FILE_SELECTED = 1,
|
| + EXPORT_FILE_SELECTED,
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +PasswordManagerHandler::PasswordManagerHandler() {
|
| + password_manager_presenter_.reset(new PasswordManagerPresenter(this));
|
| +}
|
| +
|
| +PasswordManagerHandler::PasswordManagerHandler(
|
| + PasswordManagerPresenter* presenter) {
|
| + password_manager_presenter_.reset(presenter);
|
| +}
|
|
|
| PasswordManagerHandler::~PasswordManagerHandler() {}
|
|
|
| @@ -56,24 +79,23 @@ void PasswordManagerHandler::GetLocalizedValues(
|
| DCHECK(localized_strings);
|
|
|
| static const OptionsStringResource resources[] = {
|
| - { "autoSigninTitle",
|
| - IDS_PASSWORDS_AUTO_SIGNIN_TITLE },
|
| - { "autoSigninDescription",
|
| - IDS_PASSWORDS_AUTO_SIGNIN_DESCRIPTION },
|
| - { "savedPasswordsTitle",
|
| - IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE },
|
| - { "passwordExceptionsTitle",
|
| - IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE },
|
| - { "passwordSearchPlaceholder",
|
| - IDS_PASSWORDS_PAGE_SEARCH_PASSWORDS },
|
| - { "passwordShowButton",
|
| - IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON },
|
| - { "passwordHideButton",
|
| - IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON },
|
| - { "passwordsNoPasswordsDescription",
|
| - IDS_PASSWORDS_PAGE_VIEW_NO_PASSWORDS_DESCRIPTION },
|
| - { "passwordsNoExceptionsDescription",
|
| - IDS_PASSWORDS_PAGE_VIEW_NO_EXCEPTIONS_DESCRIPTION },
|
| + {"autoSigninTitle", IDS_PASSWORDS_AUTO_SIGNIN_TITLE},
|
| + {"autoSigninDescription", IDS_PASSWORDS_AUTO_SIGNIN_DESCRIPTION},
|
| + {"savedPasswordsTitle", IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE},
|
| + {"passwordExceptionsTitle", IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE},
|
| + {"passwordSearchPlaceholder", IDS_PASSWORDS_PAGE_SEARCH_PASSWORDS},
|
| + {"passwordShowButton", IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON},
|
| + {"passwordHideButton", IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON},
|
| + {"passwordsNoPasswordsDescription",
|
| + IDS_PASSWORDS_PAGE_VIEW_NO_PASSWORDS_DESCRIPTION},
|
| + {"passwordsNoExceptionsDescription",
|
| + IDS_PASSWORDS_PAGE_VIEW_NO_EXCEPTIONS_DESCRIPTION},
|
| + {"passwordManagerImportPasswordButtonText",
|
| + IDS_PASSWORD_MANAGER_IMPORT_BUTTON},
|
| + {"passwordManagerExportPasswordButtonText",
|
| + IDS_PASSWORD_MANAGER_EXPORT_BUTTON},
|
| + {"importPasswordCompletedMessage",
|
| + IDS_PASSWORD_MANAGER_IMPORT_COMPLETED_MESSAGE},
|
| };
|
|
|
| RegisterStrings(localized_strings, resources, arraysize(resources));
|
| @@ -141,10 +163,18 @@ void PasswordManagerHandler::RegisterMessages() {
|
| "requestShowPassword",
|
| base::Bind(&PasswordManagerHandler::HandleRequestShowPassword,
|
| base::Unretained(this)));
|
| + web_ui()->RegisterMessageCallback(
|
| + "importPassword",
|
| + base::Bind(&PasswordManagerHandler::HandlePasswordImport,
|
| + base::Unretained(this)));
|
| + web_ui()->RegisterMessageCallback(
|
| + "exportPassword",
|
| + base::Bind(&PasswordManagerHandler::HandlePasswordExport,
|
| + base::Unretained(this)));
|
| }
|
|
|
| void PasswordManagerHandler::InitializeHandler() {
|
| - password_manager_presenter_.Initialize();
|
| + password_manager_presenter_->Initialize();
|
| }
|
|
|
| void PasswordManagerHandler::InitializePage() {
|
| @@ -152,6 +182,9 @@ void PasswordManagerHandler::InitializePage() {
|
| password_manager::ManageAccountLinkExperimentEnabled());
|
| web_ui()->CallJavascriptFunction(
|
| "PasswordManager.setManageAccountLinkVisibility", visible);
|
| + if (password_manager::ImportExportExperimentEnabled()) {
|
| + web_ui()->CallJavascriptFunction("PasswordManager.showImportExportButton");
|
| + }
|
| }
|
|
|
| void PasswordManagerHandler::HandleRemoveSavedPassword(
|
| @@ -159,7 +192,8 @@ void PasswordManagerHandler::HandleRemoveSavedPassword(
|
| std::string string_value = base::UTF16ToUTF8(ExtractStringValue(args));
|
| int index;
|
| if (base::StringToInt(string_value, &index) && index >= 0) {
|
| - password_manager_presenter_.RemoveSavedPassword(static_cast<size_t>(index));
|
| + password_manager_presenter_->RemoveSavedPassword(
|
| + static_cast<size_t>(index));
|
| }
|
| }
|
|
|
| @@ -168,7 +202,7 @@ void PasswordManagerHandler::HandleRemovePasswordException(
|
| std::string string_value = base::UTF16ToUTF8(ExtractStringValue(args));
|
| int index;
|
| if (base::StringToInt(string_value, &index) && index >= 0) {
|
| - password_manager_presenter_.RemovePasswordException(
|
| + password_manager_presenter_->RemovePasswordException(
|
| static_cast<size_t>(index));
|
| }
|
| }
|
| @@ -179,7 +213,7 @@ void PasswordManagerHandler::HandleRequestShowPassword(
|
| if (!ExtractIntegerValue(args, &index))
|
| NOTREACHED();
|
|
|
| - password_manager_presenter_.RequestShowPassword(static_cast<size_t>(index));
|
| + password_manager_presenter_->RequestShowPassword(static_cast<size_t>(index));
|
| }
|
|
|
| void PasswordManagerHandler::ShowPassword(
|
| @@ -196,7 +230,7 @@ void PasswordManagerHandler::ShowPassword(
|
|
|
| void PasswordManagerHandler::HandleUpdatePasswordLists(
|
| const base::ListValue* args) {
|
| - password_manager_presenter_.UpdatePasswordLists();
|
| + password_manager_presenter_->UpdatePasswordLists();
|
| }
|
|
|
| void PasswordManagerHandler::SetPasswordList(
|
| @@ -242,4 +276,111 @@ void PasswordManagerHandler::SetPasswordExceptionList(
|
| entries);
|
| }
|
|
|
| +void PasswordManagerHandler::FileSelected(const base::FilePath& path,
|
| + int index,
|
| + void* params) {
|
| + switch (reinterpret_cast<intptr_t>(params)) {
|
| + case IMPORT_FILE_SELECTED:
|
| + ImportPasswordFileSelected(path);
|
| + break;
|
| + case EXPORT_FILE_SELECTED:
|
| + ExportPasswordFileSelected(path);
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| +}
|
| +
|
| +void PasswordManagerHandler::HandlePasswordImport(const base::ListValue* args) {
|
| +#if !defined(OS_ANDROID) // This is never called on Android.
|
| + ui::SelectFileDialog::FileTypeInfo file_type_info;
|
| + file_type_info.extensions =
|
| + password_manager::PasswordImporter::GetSupportedFileExtensions();
|
| + DCHECK(!file_type_info.extensions.empty() &&
|
| + !file_type_info.extensions[0].empty());
|
| + file_type_info.include_all_files = true;
|
| + selected_file_dialog_ = ui::SelectFileDialog::Create(
|
| + this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
|
| + selected_file_dialog_->SelectFile(
|
| + ui::SelectFileDialog::SELECT_OPEN_FILE,
|
| + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_IMPORT_DIALOG_TITLE),
|
| + base::FilePath(), &file_type_info, 1, file_type_info.extensions[0][0],
|
| + web_ui()->GetWebContents()->GetTopLevelNativeWindow(),
|
| + reinterpret_cast<void*>(IMPORT_FILE_SELECTED));
|
| +#endif
|
| +}
|
| +
|
| +void PasswordManagerHandler::ImportPasswordFileSelected(
|
| + const base::FilePath& path) {
|
| + password_manager::PasswordImporter::Import(
|
| + path, content::BrowserThread::GetMessageLoopProxyForThread(
|
| + content::BrowserThread::FILE).get(),
|
| + base::Bind(&PasswordManagerHandler::ImportPasswordFileRead,
|
| + base::Unretained(this)));
|
| +}
|
| +
|
| +void PasswordManagerHandler::ImportPasswordFileRead(
|
| + password_manager::PasswordImporter::Result result,
|
| + const std::vector<autofill::PasswordForm>& forms) {
|
| + UMA_HISTOGRAM_ENUMERATION("PasswordManager.ImportPasswordFromCSVResult",
|
| + result,
|
| + password_manager::PasswordImporter::SEMANTIC_ERROR);
|
| + if (result != password_manager::PasswordImporter::SUCCESS) {
|
| + return;
|
| + }
|
| +
|
| + UMA_HISTOGRAM_COUNTS("PasswordManager.ImportedPasswordsPerUserInCSV",
|
| + forms.size());
|
| +
|
| + if (password_manager_presenter_->AddPasswordsToStore(forms)) {
|
| + // Display Feedback UI
|
| + base::FundamentalValue visible(true);
|
| + web_ui()->CallJavascriptFunction(
|
| + "PasswordManager.setImportCompleteUIVisibility", visible);
|
| + } else {
|
| + UMA_HISTOGRAM_COUNTS("PasswordManager.FailToStorePasswordImportedFromCSV",
|
| + 1);
|
| + }
|
| +}
|
| +
|
| +void PasswordManagerHandler::HandlePasswordExport(const base::ListValue* args) {
|
| +#if !defined(OS_ANDROID) // This is never called on Android.
|
| + if (password_manager_presenter_->RequestToExportPassword()) {
|
| + ui::SelectFileDialog::FileTypeInfo file_type_info;
|
| + file_type_info.extensions =
|
| + password_manager::PasswordExporter::GetSupportedFileExtensions();
|
| + DCHECK(!file_type_info.extensions.empty() &&
|
| + !file_type_info.extensions[0].empty());
|
| + file_type_info.include_all_files = true;
|
| + selected_file_dialog_ = ui::SelectFileDialog::Create(
|
| + this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
|
| + selected_file_dialog_->SelectFile(
|
| + ui::SelectFileDialog::SELECT_SAVEAS_FILE,
|
| + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_EXPORT_DIALOG_TITLE),
|
| + base::FilePath(), &file_type_info, 1, file_type_info.extensions[0][0],
|
| + GetNativeWindow(), reinterpret_cast<void*>(EXPORT_FILE_SELECTED));
|
| + }
|
| +#endif
|
| +}
|
| +
|
| +void PasswordManagerHandler::ExportPasswordFileSelected(
|
| + const base::FilePath& path) {
|
| + ScopedVector<autofill::PasswordForm> password_list =
|
| + password_manager_presenter_->GetAllPasswords().Pass();
|
| + UMA_HISTOGRAM_COUNTS("PasswordManager.ExportedPasswordsPerUserInCSV",
|
| + password_list.size());
|
| + password_manager::PasswordExporter::Export(
|
| + path, password_list.Pass(),
|
| + content::BrowserThread::GetMessageLoopProxyForThread(
|
| + content::BrowserThread::FILE).get(),
|
| + base::Bind(&PasswordManagerHandler::ExportPasswordFileWritten,
|
| + base::Unretained(this)));
|
| +}
|
| +
|
| +void PasswordManagerHandler::ExportPasswordFileWritten() {
|
| + // We do not plan to give any UI feedback for export
|
| + // at this moment as it will almost always succeed. If the plan changes, this
|
| + // is the place to put the feedback logic.
|
| +}
|
| +
|
| } // namespace options
|
|
|