1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/password_manager/password_store_proxy_mac.h"
7 #include "base/metrics/histogram_macros.h"
8 #include "chrome/browser/password_manager/password_store_mac.h"
9 #include "chrome/browser/password_manager/simple_password_store_mac.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "crypto/apple_keychain.h"
13 using password_manager::MigrationStatus
;
14 using password_manager::PasswordStoreChangeList
;
16 PasswordStoreProxyMac::PasswordStoreProxyMac(
17 scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_runner
,
18 scoped_ptr
<crypto::AppleKeychain
> keychain
,
19 scoped_ptr
<password_manager::LoginDatabase
> login_db
,
21 : PasswordStore(main_thread_runner
, nullptr),
22 login_metadata_db_(login_db
.Pass()) {
23 DCHECK(login_metadata_db_
);
24 migration_status_
.Init(password_manager::prefs::kKeychainMigrationStatus
,
26 if (migration_status_
.GetValue() ==
27 static_cast<int>(MigrationStatus::MIGRATED
)) {
28 // The login database will be set later after initialization.
29 password_store_simple_
=
30 new SimplePasswordStoreMac(main_thread_runner
, nullptr, nullptr);
33 new PasswordStoreMac(main_thread_runner
, nullptr, keychain
.Pass());
37 PasswordStoreProxyMac::~PasswordStoreProxyMac() {
40 bool PasswordStoreProxyMac::Init(
41 const syncer::SyncableService::StartSyncFlare
& flare
) {
42 // Set up a background thread.
43 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
44 thread_
.reset(new base::Thread("Chrome_PasswordStore_Thread"));
46 if (!thread_
->Start()) {
51 if (!password_manager::PasswordStore::Init(flare
))
55 base::Bind(&PasswordStoreProxyMac::InitOnBackgroundThread
, this,
56 static_cast<MigrationStatus
>(migration_status_
.GetValue())));
59 void PasswordStoreProxyMac::Shutdown() {
60 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
61 PasswordStore::Shutdown();
64 // Execute the task which are still pending.
67 // Unsubscribe the observer, otherwise it's too late in the destructor.
68 migration_status_
.Destroy();
70 // After the thread has stopped it's impossible to switch from one backend to
71 // another. GetBackend() returns the correct result.
72 // The backend doesn't need the background thread as PasswordStore::Init() and
73 // other public methods were never called on it.
74 GetBackend()->Shutdown();
77 scoped_refptr
<base::SingleThreadTaskRunner
>
78 PasswordStoreProxyMac::GetBackgroundTaskRunner() {
79 return thread_
? thread_
->task_runner() : nullptr;
82 password_manager::PasswordStore
* PasswordStoreProxyMac::GetBackend() const {
83 if (password_store_mac_
)
84 return password_store_mac_
.get();
85 return password_store_simple_
.get();
88 void PasswordStoreProxyMac::InitOnBackgroundThread(MigrationStatus status
) {
89 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
90 if (!login_metadata_db_
->Init()) {
91 login_metadata_db_
.reset();
92 LOG(ERROR
) << "Could not create/open login database.";
95 if (status
== MigrationStatus::MIGRATED
) {
96 password_store_simple_
->InitWithTaskRunner(GetBackgroundTaskRunner(),
97 login_metadata_db_
.Pass());
99 password_store_mac_
->set_login_metadata_db(login_metadata_db_
.get());
100 password_store_mac_
->InitWithTaskRunner(GetBackgroundTaskRunner());
101 if (login_metadata_db_
&& (status
== MigrationStatus::NOT_STARTED
||
102 status
== MigrationStatus::FAILED_ONCE
)) {
103 // Let's try to migrate the passwords.
104 if (password_store_mac_
->ImportFromKeychain() ==
105 PasswordStoreMac::MIGRATION_OK
) {
106 status
= MigrationStatus::MIGRATED
;
107 // Switch from |password_store_mac_| to |password_store_simple_|.
108 password_store_mac_
->set_login_metadata_db(nullptr);
109 pending_ui_tasks_
.push_back(
110 base::Bind(&PasswordStoreMac::Shutdown
, password_store_mac_
));
111 password_store_mac_
= nullptr;
112 DCHECK(!password_store_simple_
);
113 password_store_simple_
= new SimplePasswordStoreMac(
114 main_thread_runner_
, GetBackgroundTaskRunner(),
115 login_metadata_db_
.Pass());
117 status
= (status
== MigrationStatus::FAILED_ONCE
118 ? MigrationStatus::FAILED_TWICE
119 : MigrationStatus::FAILED_ONCE
);
121 pending_ui_tasks_
.push_back(
122 base::Bind(&PasswordStoreProxyMac::UpdateStatusPref
, this, status
));
125 if (!pending_ui_tasks_
.empty()) {
126 main_thread_runner_
->PostTask(
127 FROM_HERE
, base::Bind(&PasswordStoreProxyMac::FlushPendingTasks
, this));
129 UMA_HISTOGRAM_ENUMERATION(
130 "PasswordManager.KeychainMigration.Status", static_cast<int>(status
),
131 static_cast<int>(MigrationStatus::MIGRATION_STATUS_COUNT
));
132 DCHECK(GetBackend());
135 void PasswordStoreProxyMac::UpdateStatusPref(MigrationStatus status
) {
136 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
137 migration_status_
.SetValue(static_cast<int>(status
));
140 void PasswordStoreProxyMac::FlushPendingTasks() {
141 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
142 for (auto& task
: pending_ui_tasks_
)
144 pending_ui_tasks_
.clear();
147 void PasswordStoreProxyMac::ReportMetricsImpl(
148 const std::string
& sync_username
,
149 bool custom_passphrase_sync_enabled
) {
150 GetBackend()->ReportMetricsImpl(sync_username
,
151 custom_passphrase_sync_enabled
);
154 PasswordStoreChangeList
PasswordStoreProxyMac::AddLoginImpl(
155 const autofill::PasswordForm
& form
) {
156 return GetBackend()->AddLoginImpl(form
);
159 PasswordStoreChangeList
PasswordStoreProxyMac::UpdateLoginImpl(
160 const autofill::PasswordForm
& form
) {
161 return GetBackend()->UpdateLoginImpl(form
);
164 PasswordStoreChangeList
PasswordStoreProxyMac::RemoveLoginImpl(
165 const autofill::PasswordForm
& form
) {
166 return GetBackend()->RemoveLoginImpl(form
);
169 PasswordStoreChangeList
PasswordStoreProxyMac::RemoveLoginsCreatedBetweenImpl(
170 base::Time delete_begin
,
171 base::Time delete_end
) {
172 return GetBackend()->RemoveLoginsCreatedBetweenImpl(delete_begin
, delete_end
);
175 PasswordStoreChangeList
PasswordStoreProxyMac::RemoveLoginsSyncedBetweenImpl(
176 base::Time delete_begin
,
177 base::Time delete_end
) {
178 return GetBackend()->RemoveLoginsSyncedBetweenImpl(delete_begin
, delete_end
);
181 ScopedVector
<autofill::PasswordForm
> PasswordStoreProxyMac::FillMatchingLogins(
182 const autofill::PasswordForm
& form
,
183 AuthorizationPromptPolicy prompt_policy
) {
184 return GetBackend()->FillMatchingLogins(form
, prompt_policy
);
187 bool PasswordStoreProxyMac::FillAutofillableLogins(
188 ScopedVector
<autofill::PasswordForm
>* forms
) {
189 return GetBackend()->FillAutofillableLogins(forms
);
192 bool PasswordStoreProxyMac::FillBlacklistLogins(
193 ScopedVector
<autofill::PasswordForm
>* forms
) {
194 return GetBackend()->FillBlacklistLogins(forms
);
197 void PasswordStoreProxyMac::AddSiteStatsImpl(
198 const password_manager::InteractionsStats
& stats
) {
199 GetBackend()->AddSiteStatsImpl(stats
);
202 void PasswordStoreProxyMac::RemoveSiteStatsImpl(const GURL
& origin_domain
) {
203 GetBackend()->RemoveSiteStatsImpl(origin_domain
);
206 scoped_ptr
<password_manager::InteractionsStats
>
207 PasswordStoreProxyMac::GetSiteStatsImpl(const GURL
& origin_domain
) {
208 return GetBackend()->GetSiteStatsImpl(origin_domain
);