blob: 2241d7c62fb8172a2a67a3431e43c11b9d6c3602 [file] [log] [blame]
// Copyright 2015 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/password_manager/password_store_proxy_mac.h"
#include <string>
#include <utility>
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/password_manager/password_store_mac.h"
#include "chrome/browser/password_manager/simple_password_store_mac.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/apple_keychain.h"
using password_manager::MigrationStatus;
using password_manager::PasswordStoreChangeList;
PasswordStoreProxyMac::PasswordStoreProxyMac(
scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
scoped_ptr<crypto::AppleKeychain> keychain,
scoped_ptr<password_manager::LoginDatabase> login_db,
PrefService* prefs)
: PasswordStore(main_thread_runner, nullptr),
login_metadata_db_(std::move(login_db)) {
DCHECK(login_metadata_db_);
migration_status_.Init(password_manager::prefs::kKeychainMigrationStatus,
prefs);
if (migration_status_.GetValue() ==
static_cast<int>(MigrationStatus::MIGRATED)) {
// The login database will be set later after initialization.
password_store_simple_ =
new SimplePasswordStoreMac(main_thread_runner, nullptr, nullptr);
} else {
password_store_mac_ =
new PasswordStoreMac(main_thread_runner, nullptr, std::move(keychain));
}
}
PasswordStoreProxyMac::~PasswordStoreProxyMac() {
}
bool PasswordStoreProxyMac::Init(
const syncer::SyncableService::StartSyncFlare& flare) {
// Set up a background thread.
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
thread_.reset(new base::Thread("Chrome_PasswordStore_Thread"));
if (!thread_->Start()) {
thread_.reset();
return false;
}
if (!password_manager::PasswordStore::Init(flare))
return false;
return ScheduleTask(
base::Bind(&PasswordStoreProxyMac::InitOnBackgroundThread, this,
static_cast<MigrationStatus>(migration_status_.GetValue())));
}
void PasswordStoreProxyMac::ShutdownOnUIThread() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PasswordStore::ShutdownOnUIThread();
thread_->Stop();
// Execute the task which are still pending.
FlushPendingTasks();
// Unsubscribe the observer, otherwise it's too late in the destructor.
migration_status_.Destroy();
// After the thread has stopped it's impossible to switch from one backend to
// another. GetBackend() returns the correct result.
// The backend doesn't need the background thread as PasswordStore::Init() and
// other public methods were never called on it.
GetBackend()->ShutdownOnUIThread();
}
scoped_refptr<base::SingleThreadTaskRunner>
PasswordStoreProxyMac::GetBackgroundTaskRunner() {
return thread_ ? thread_->task_runner() : nullptr;
}
password_manager::PasswordStore* PasswordStoreProxyMac::GetBackend() const {
if (password_store_mac_)
return password_store_mac_.get();
return password_store_simple_.get();
}
void PasswordStoreProxyMac::InitOnBackgroundThread(MigrationStatus status) {
DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
if (!login_metadata_db_->Init()) {
login_metadata_db_.reset();
LOG(ERROR) << "Could not create/open login database.";
}
if (status == MigrationStatus::MIGRATED) {
password_store_simple_->InitWithTaskRunner(GetBackgroundTaskRunner(),
std::move(login_metadata_db_));
} else {
password_store_mac_->set_login_metadata_db(login_metadata_db_.get());
password_store_mac_->InitWithTaskRunner(GetBackgroundTaskRunner());
if (login_metadata_db_ && (status == MigrationStatus::NOT_STARTED ||
status == MigrationStatus::FAILED_ONCE)) {
// Let's try to migrate the passwords.
if (password_store_mac_->ImportFromKeychain() ==
PasswordStoreMac::MIGRATION_OK) {
status = MigrationStatus::MIGRATED;
// Switch from |password_store_mac_| to |password_store_simple_|.
password_store_mac_->set_login_metadata_db(nullptr);
pending_ui_tasks_.push_back(base::Bind(
&PasswordStoreMac::ShutdownOnUIThread, password_store_mac_));
password_store_mac_ = nullptr;
DCHECK(!password_store_simple_);
password_store_simple_ = new SimplePasswordStoreMac(
main_thread_runner_, GetBackgroundTaskRunner(),
std::move(login_metadata_db_));
} else {
status = (status == MigrationStatus::FAILED_ONCE
? MigrationStatus::FAILED_TWICE
: MigrationStatus::FAILED_ONCE);
}
pending_ui_tasks_.push_back(
base::Bind(&PasswordStoreProxyMac::UpdateStatusPref, this, status));
}
}
if (!pending_ui_tasks_.empty()) {
main_thread_runner_->PostTask(
FROM_HERE, base::Bind(&PasswordStoreProxyMac::FlushPendingTasks, this));
}
UMA_HISTOGRAM_ENUMERATION(
"PasswordManager.KeychainMigration.Status", static_cast<int>(status),
static_cast<int>(MigrationStatus::MIGRATION_STATUS_COUNT));
DCHECK(GetBackend());
}
void PasswordStoreProxyMac::UpdateStatusPref(MigrationStatus status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
migration_status_.SetValue(static_cast<int>(status));
}
void PasswordStoreProxyMac::FlushPendingTasks() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
for (auto& task : pending_ui_tasks_)
task.Run();
pending_ui_tasks_.clear();
}
void PasswordStoreProxyMac::ReportMetricsImpl(
const std::string& sync_username,
bool custom_passphrase_sync_enabled) {
GetBackend()->ReportMetricsImpl(sync_username,
custom_passphrase_sync_enabled);
}
PasswordStoreChangeList PasswordStoreProxyMac::AddLoginImpl(
const autofill::PasswordForm& form) {
return GetBackend()->AddLoginImpl(form);
}
PasswordStoreChangeList PasswordStoreProxyMac::UpdateLoginImpl(
const autofill::PasswordForm& form) {
return GetBackend()->UpdateLoginImpl(form);
}
PasswordStoreChangeList PasswordStoreProxyMac::RemoveLoginImpl(
const autofill::PasswordForm& form) {
return GetBackend()->RemoveLoginImpl(form);
}
PasswordStoreChangeList PasswordStoreProxyMac::RemoveLoginsByOriginAndTimeImpl(
const url::Origin& origin,
base::Time delete_begin,
base::Time delete_end) {
return GetBackend()->RemoveLoginsByOriginAndTimeImpl(origin, delete_begin,
delete_end);
}
PasswordStoreChangeList PasswordStoreProxyMac::RemoveLoginsCreatedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) {
return GetBackend()->RemoveLoginsCreatedBetweenImpl(delete_begin, delete_end);
}
PasswordStoreChangeList PasswordStoreProxyMac::RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) {
return GetBackend()->RemoveLoginsSyncedBetweenImpl(delete_begin, delete_end);
}
bool PasswordStoreProxyMac::RemoveStatisticsCreatedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) {
return GetBackend()->RemoveStatisticsCreatedBetweenImpl(delete_begin,
delete_end);
}
ScopedVector<autofill::PasswordForm> PasswordStoreProxyMac::FillMatchingLogins(
const autofill::PasswordForm& form) {
return GetBackend()->FillMatchingLogins(form);
}
bool PasswordStoreProxyMac::FillAutofillableLogins(
ScopedVector<autofill::PasswordForm>* forms) {
return GetBackend()->FillAutofillableLogins(forms);
}
bool PasswordStoreProxyMac::FillBlacklistLogins(
ScopedVector<autofill::PasswordForm>* forms) {
return GetBackend()->FillBlacklistLogins(forms);
}
void PasswordStoreProxyMac::AddSiteStatsImpl(
const password_manager::InteractionsStats& stats) {
GetBackend()->AddSiteStatsImpl(stats);
}
void PasswordStoreProxyMac::RemoveSiteStatsImpl(const GURL& origin_domain) {
GetBackend()->RemoveSiteStatsImpl(origin_domain);
}
std::vector<scoped_ptr<password_manager::InteractionsStats>>
PasswordStoreProxyMac::GetSiteStatsImpl(const GURL& origin_domain) {
return GetBackend()->GetSiteStatsImpl(origin_domain);
}