From e163956d3ca3a44bab7aa1f2077df368af4cef41 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Tue, 20 Jun 2017 09:35:09 -0700 Subject: [PATCH] Import password from Chrome fixes https://github.com/brave/browser-laptop/issues/9434 Auditors: @bridiver, @bbondy, @diracdeltas, @bsclifton Mac: master password will store in Chrome/Chromium Safe Storage so we will ask users to access it Windows: Using `CryptProtectData` and `CryptUnprotectData` `Usually, the only user who can decrypt the data is a user with the same logon credentials as the user who encrypted the data` Linux: Using NativeBackEnd. gnome-keyring which will be removed soon is deprecated by libsecret KDE has a bug traking it https://github.com/brave/muon/issues/238 --- BUILD.gn | 7 + atom/common/importer/chrome_importer_utils.cc | 4 + brave/utility/brave_profile_import_handler.cc | 9 ++ brave/utility/importer/chrome_importer.cc | 122 ++++++++++++++++++ brave/utility/importer/chrome_importer.h | 4 + patches/master_patch.patch | 27 ++++ 6 files changed, 173 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index dc0f63684..ff9cc270a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -244,6 +244,8 @@ source_set("utility") { "//content/public/common", ] + defines = [ ] + deps = [ "chromium_src:importer", "//chrome/common", @@ -251,6 +253,11 @@ source_set("utility") { "//third_party/protobuf:protobuf_lite", ] + if (use_glib) { + defines += [ "USE_LIBSECRET" ] + deps += [ "//third_party/libsecret" ] + } + sources = [ "atom/utility/atom_content_utility_client.cc", "atom/utility/atom_content_utility_client.h", diff --git a/atom/common/importer/chrome_importer_utils.cc b/atom/common/importer/chrome_importer_utils.cc index a402627c8..5f9917858 100644 --- a/atom/common/importer/chrome_importer_utils.cc +++ b/atom/common/importer/chrome_importer_utils.cc @@ -65,6 +65,8 @@ bool ChromeImporterCanImport(const base::FilePath& profile, profile.Append(base::FilePath::StringType(FILE_PATH_LITERAL("History"))); base::FilePath cookies = profile.Append(base::FilePath::StringType(FILE_PATH_LITERAL("Cookies"))); + base::FilePath passwords = + profile.Append(base::FilePath::StringType(FILE_PATH_LITERAL("Login Data"))); if (base::PathExists(bookmarks)) *services_supported |= importer::FAVORITES; @@ -72,6 +74,8 @@ bool ChromeImporterCanImport(const base::FilePath& profile, *services_supported |= importer::HISTORY; if (base::PathExists(cookies)) *services_supported |= importer::COOKIES; + if (base::PathExists(passwords)) + *services_supported |= importer::PASSWORDS; return *services_supported != importer::NONE; } diff --git a/brave/utility/brave_profile_import_handler.cc b/brave/utility/brave_profile_import_handler.cc index e7add513d..3b15db414 100644 --- a/brave/utility/brave_profile_import_handler.cc +++ b/brave/utility/brave_profile_import_handler.cc @@ -8,10 +8,13 @@ #include "brave/utility/brave_profile_import_handler.h" #include "base/bind.h" +#include "base/command_line.h" #include "base/location.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" @@ -51,6 +54,12 @@ void BraveProfileImportHandler::StartImport( items_to_import_ = items; + if (base::StartsWith(base::UTF16ToUTF8(source_profile.importer_name), + "Chrome", base::CompareCase::SENSITIVE)) { + auto command_line = base::CommandLine::ForCurrentProcess(); + command_line->AppendSwitch("import-chrome"); + } + // Create worker thread in which importer runs. import_thread_.reset(new base::Thread("import_thread")); #if defined(OS_WIN) diff --git a/brave/utility/importer/chrome_importer.cc b/brave/utility/importer/chrome_importer.cc index 34726e729..7500f704e 100644 --- a/brave/utility/importer/chrome_importer.cc +++ b/brave/utility/importer/chrome_importer.cc @@ -11,7 +11,10 @@ #include "base/files/file_util.h" #include "base/json/json_reader.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/strings/utf_string_conversions.h" +#include "base/task_scheduler/post_task.h" +#include "base/task_scheduler/task_traits.h" #include "base/values.h" #include "brave/common/importer/imported_cookie_entry.h" #include "build/build_config.h" @@ -19,10 +22,30 @@ #include "chrome/common/importer/importer_bridge.h" #include "chrome/common/importer/importer_url_row.h" #include "chrome/utility/importer/favicon_reencode.h" +#include "components/autofill/core/common/password_form.h" +#include "components/os_crypt/os_crypt.h" +#include "components/password_manager/core/browser/login_database.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/prefs/json_pref_store.h" +#include "components/prefs/pref_filter.h" #include "sql/connection.h" #include "sql/statement.h" #include "url/gurl.h" +#if defined(USE_X11) +#if defined(USE_LIBSECRET) +#include "chrome/browser/password_manager/native_backend_libsecret.h" +#endif +#include "chrome/browser/password_manager/native_backend_kwallet_x.h" +#include "chrome/browser/password_manager/password_store_x.h" +#include "components/os_crypt/key_storage_util_linux.h" + +base::nix::DesktopEnvironment ChromeImporter::GetDesktopEnvironment() { + std::unique_ptr env(base::Environment::Create()); + return base::nix::GetDesktopEnvironment(env.get()); +} +#endif + ChromeImporter::ChromeImporter() { } @@ -55,6 +78,13 @@ void ChromeImporter::StartImport(const importer::SourceProfile& source_profile, ImportCookies(); bridge_->NotifyItemEnded(importer::COOKIES); } + + if ((items & importer::PASSWORDS) && !cancelled()) { + bridge_->NotifyItemStarted(importer::PASSWORDS); + ImportPasswords(); + bridge_->NotifyItemEnded(importer::PASSWORDS); + } + bridge_->NotifyEnded(); } @@ -250,6 +280,98 @@ void ChromeImporter::ImportCookies() { SetCookies(cookies); } +void ChromeImporter::ImportPasswords() { +#if !defined(USE_X11) + base::FilePath passwords_path = + source_path_.Append( + base::FilePath::StringType(FILE_PATH_LITERAL("Login Data"))); + + password_manager::LoginDatabase database(passwords_path); + if (!database.Init()) { + LOG(ERROR) << "LoginDatabase Init() failed"; + return; + } + + std::vector> forms; + bool success = database.GetAutofillableLogins(&forms); + if (success) { + for (int i = 0; i < forms.size(); ++i) { + bridge_->SetPasswordForm(*forms[i].get()); + } + } + std::vector> blacklist; + success = database.GetBlacklistLogins(&blacklist); + if (success) { + for (int i = 0; i < blacklist.size(); ++i) { + bridge_->SetPasswordForm(*blacklist[i].get()); + } + } +#else + base::FilePath prefs_path = + source_path_.Append( + base::FilePath::StringType(FILE_PATH_LITERAL("Preferences"))); + const base::Value *value; + scoped_refptr file_task_runner = + base::CreateSequencedTaskRunnerWithTraits(base::TaskTraits().MayBlock()); + scoped_refptr prefs = new JsonPrefStore( + prefs_path, file_task_runner, std::unique_ptr()); + int local_profile_id; + if (prefs->ReadPrefs() != PersistentPrefStore::PREF_READ_ERROR_NONE) { + return; + } + if (!prefs->GetValue(password_manager::prefs::kLocalProfileId, &value)) { + return; + } + if (!value->GetAsInteger(&local_profile_id)) { + return; + } + + std::unique_ptr backend; + base::nix::DesktopEnvironment desktop_env = GetDesktopEnvironment(); + + os_crypt::SelectedLinuxBackend selected_backend = + os_crypt::SelectBackend(std::string(), desktop_env); + if (!backend && + (selected_backend == os_crypt::SelectedLinuxBackend::KWALLET || + selected_backend == os_crypt::SelectedLinuxBackend::KWALLET5)) { + base::nix::DesktopEnvironment used_desktop_env = + selected_backend == os_crypt::SelectedLinuxBackend::KWALLET + ? base::nix::DESKTOP_ENVIRONMENT_KDE4 + : base::nix::DESKTOP_ENVIRONMENT_KDE5; + backend.reset(new NativeBackendKWallet(local_profile_id, + used_desktop_env)); + } else if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY || + selected_backend == + os_crypt::SelectedLinuxBackend::GNOME_KEYRING || + selected_backend == + os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) { +#if defined(USE_LIBSECRET) + if (!backend && + (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY || + selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET)) { + backend.reset(new NativeBackendLibsecret(local_profile_id)); + } +#endif + } + if (backend && backend->Init()) { + std::vector> forms; + bool success = backend->GetAutofillableLogins(&forms); + if (success) { + for (int i = 0; i < forms.size(); ++i) { + bridge_->SetPasswordForm(*forms[i].get()); + } + } + std::vector> blacklist; + success = backend->GetBlacklistLogins(&blacklist); + if (success) { + for (int i = 0; i < blacklist.size(); ++i) { + bridge_->SetPasswordForm(*blacklist[i].get()); + } + } + } +#endif +} + void ChromeImporter::RecursiveReadBookmarksFolder( const base::DictionaryValue* folder, const std::vector& parent_path, diff --git a/brave/utility/importer/chrome_importer.h b/brave/utility/importer/chrome_importer.h index 6b52df89d..0b4bb7cc1 100644 --- a/brave/utility/importer/chrome_importer.h +++ b/brave/utility/importer/chrome_importer.h @@ -14,6 +14,7 @@ #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/macros.h" +#include "base/nix/xdg_util.h" #include "build/build_config.h" #include "chrome/utility/importer/importer.h" #include "components/favicon_base/favicon_usage_data.h" @@ -40,9 +41,12 @@ class ChromeImporter : public Importer { private: ~ChromeImporter() override; + static base::nix::DesktopEnvironment GetDesktopEnvironment(); + void ImportBookmarks(); void ImportHistory(); void ImportCookies(); + void ImportPasswords(); // Multiple URLs can share the same favicon; this is a map // of URLs -> IconIDs that we load as a temporary step before diff --git a/patches/master_patch.patch b/patches/master_patch.patch index 28d3e0aed..4c46b32e6 100644 --- a/patches/master_patch.patch +++ b/patches/master_patch.patch @@ -1003,6 +1003,33 @@ index bc36a92f4ad97e84d65c5213acbb68fc89aae8d9..9567f7f130181a40917751fff899b439 } // static +diff --git a/components/os_crypt/keychain_password_mac.mm b/components/os_crypt/keychain_password_mac.mm +index 2b38db266f9aa1f4141c8649c021042ede4e5589..ea0387b11f4b00f87596d738c152aa4cc43b2beb 100644 +--- a/components/os_crypt/keychain_password_mac.mm ++++ b/components/os_crypt/keychain_password_mac.mm +@@ -7,6 +7,7 @@ + #import + + #include "base/base64.h" ++#include "base/command_line.h" + #include "base/mac/mac_logging.h" + #include "base/rand_util.h" + #include "crypto/apple_keychain.h" +@@ -61,6 +62,14 @@ const char KeychainPassword::account_name[] = "Chromium"; + std::string KeychainPassword::GetPassword() const { + UInt32 password_length = 0; + void* password_data = NULL; ++ const char *service_name, *account_name; ++ if (base::CommandLine::ForCurrentProcess()->HasSwitch("import-chrome")) { ++ service_name = "Chrome Safe Storage"; ++ account_name = "Chrome"; ++ } else { ++ service_name = ::KeychainPassword::service_name; ++ account_name = ::KeychainPassword::account_name; ++ } + OSStatus error = keychain_.FindGenericPassword( + nullptr, strlen(service_name), service_name, strlen(account_name), + account_name, &password_length, &password_data, NULL); diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h index 32b0451b60dd100d57ec67a31a94673f2ebd5359..ba98bd0c470bb155177bdd4fd0e268535f0c24d2 100644 --- a/components/printing/common/print_messages.h