1 // Copyright 2014 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 "components/password_manager/core/browser/password_store.h"
8 #include "base/debug/dump_without_crashing.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/metrics/histogram.h"
13 #include "base/stl_util.h"
14 #include "components/autofill/core/common/password_form.h"
15 #include "components/password_manager/core/browser/password_store_consumer.h"
16 #include "components/password_manager/core/browser/password_syncable_service.h"
18 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
19 #include "components/password_manager/core/browser/password_syncable_service.h"
22 using autofill::PasswordForm;
24 namespace password_manager {
28 // Calls |consumer| back with the request result, if |consumer| is still alive.
29 // Takes ownership of the elements in |result|, passing ownership to |consumer|
30 // if it is still alive.
31 void MaybeCallConsumerCallback(base::WeakPtr<PasswordStoreConsumer> consumer,
32 scoped_ptr<std::vector<PasswordForm*> > result) {
34 consumer->OnGetPasswordStoreResults(*result);
36 STLDeleteElements(result.get());
39 // http://crbug.com/404012. Let's see where the empty fields come from.
40 void CheckForEmptyUsernameAndPassword(const PasswordForm& form) {
41 if (form.username_value.empty() &&
42 form.password_value.empty() &&
43 !form.blacklisted_by_user)
44 base::debug::DumpWithoutCrashing();
49 PasswordStore::GetLoginsRequest::GetLoginsRequest(
50 PasswordStoreConsumer* consumer)
51 : consumer_weak_(consumer->GetWeakPtr()),
52 result_(new std::vector<PasswordForm*>()) {
53 DCHECK(thread_checker_.CalledOnValidThread());
54 origin_loop_ = base::MessageLoopProxy::current();
57 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
60 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() {
61 if (!ignore_logins_cutoff_.is_null()) {
62 // Count down rather than up since we may be deleting elements.
63 // Note that in principle it could be more efficient to copy the whole array
64 // since that's worst-case linear time, but we expect that elements will be
65 // deleted rarely and lists will be small, so this avoids the copies.
66 for (size_t i = result_->size(); i > 0; --i) {
67 if ((*result_)[i - 1]->date_created < ignore_logins_cutoff_) {
68 delete (*result_)[i - 1];
69 result_->erase(result_->begin() + (i - 1));
75 void PasswordStore::GetLoginsRequest::ForwardResult() {
76 origin_loop_->PostTask(FROM_HERE,
77 base::Bind(&MaybeCallConsumerCallback,
79 base::Passed(result_.Pass())));
82 PasswordStore::PasswordStore(
83 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
84 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner)
85 : main_thread_runner_(main_thread_runner),
86 db_thread_runner_(db_thread_runner),
87 observers_(new ObserverListThreadSafe<Observer>()),
88 shutdown_called_(false) {}
90 bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare) {
91 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
92 ScheduleTask(base::Bind(&PasswordStore::InitSyncableService, this, flare));
97 void PasswordStore::AddLogin(const PasswordForm& form) {
98 CheckForEmptyUsernameAndPassword(form);
100 base::Bind(&PasswordStore::WrapModificationTask, this,
101 base::Bind(&PasswordStore::AddLoginImpl, this, form)));
104 void PasswordStore::UpdateLogin(const PasswordForm& form) {
105 CheckForEmptyUsernameAndPassword(form);
107 base::Bind(&PasswordStore::WrapModificationTask, this,
108 base::Bind(&PasswordStore::UpdateLoginImpl, this, form)));
111 void PasswordStore::RemoveLogin(const PasswordForm& form) {
113 base::Bind(&PasswordStore::WrapModificationTask, this,
114 base::Bind(&PasswordStore::RemoveLoginImpl, this, form)));
117 void PasswordStore::RemoveLoginsCreatedBetween(base::Time delete_begin,
118 base::Time delete_end) {
120 base::Bind(&PasswordStore::WrapModificationTask, this,
121 base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl,
122 this, delete_begin, delete_end)));
125 void PasswordStore::RemoveLoginsSyncedBetween(base::Time delete_begin,
126 base::Time delete_end) {
128 base::Bind(&PasswordStore::WrapModificationTask,
130 base::Bind(&PasswordStore::RemoveLoginsSyncedBetweenImpl,
136 void PasswordStore::GetLogins(
137 const PasswordForm& form,
138 AuthorizationPromptPolicy prompt_policy,
139 PasswordStoreConsumer* consumer) {
140 // Per http://crbug.com/121738, we deliberately ignore saved logins for
141 // http*://www.google.com/ that were stored prior to 2012. (Google now uses
142 // https://accounts.google.com/ for all login forms, so these should be
143 // unused.) We don't delete them just yet, and they'll still be visible in the
144 // password manager, but we won't use them to autofill any forms. This is a
145 // security feature to help minimize damage that can be done by XSS attacks.
146 // TODO(mdm): actually delete them at some point, say M24 or so.
147 base::Time ignore_logins_cutoff; // the null time
148 if (form.scheme == PasswordForm::SCHEME_HTML &&
149 (form.signon_realm == "http://www.google.com" ||
150 form.signon_realm == "http://www.google.com/" ||
151 form.signon_realm == "https://www.google.com" ||
152 form.signon_realm == "https://www.google.com/")) {
153 static const base::Time::Exploded exploded_cutoff =
154 { 2012, 1, 0, 1, 0, 0, 0, 0 }; // 00:00 Jan 1 2012
155 ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
157 GetLoginsRequest* request = new GetLoginsRequest(consumer);
158 request->set_ignore_logins_cutoff(ignore_logins_cutoff);
160 ConsumerCallbackRunner callback_runner =
161 base::Bind(&PasswordStore::CopyAndForwardLoginsResult,
162 this, base::Owned(request));
163 ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl,
164 this, form, prompt_policy, callback_runner));
167 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
168 Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
171 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
172 Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
175 void PasswordStore::ReportMetrics(const std::string& sync_username,
176 bool custom_passphrase_sync_enabled) {
177 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl,
180 custom_passphrase_sync_enabled));
183 void PasswordStore::AddObserver(Observer* observer) {
184 observers_->AddObserver(observer);
187 void PasswordStore::RemoveObserver(Observer* observer) {
188 observers_->RemoveObserver(observer);
191 bool PasswordStore::ScheduleTask(const base::Closure& task) {
192 scoped_refptr<base::SingleThreadTaskRunner> task_runner(
193 GetBackgroundTaskRunner());
194 if (task_runner.get())
195 return task_runner->PostTask(FROM_HERE, task);
199 void PasswordStore::Shutdown() {
200 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
201 ScheduleTask(base::Bind(&PasswordStore::DestroySyncableService, this));
203 shutdown_called_ = true;
206 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
207 base::WeakPtr<syncer::SyncableService>
208 PasswordStore::GetPasswordSyncableService() {
209 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
210 DCHECK(syncable_service_);
211 return syncable_service_->AsWeakPtr();
215 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); }
217 scoped_refptr<base::SingleThreadTaskRunner>
218 PasswordStore::GetBackgroundTaskRunner() {
219 return db_thread_runner_;
222 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
223 request->ApplyIgnoreLoginsCutoff();
224 request->ForwardResult();
227 void PasswordStore::CopyAndForwardLoginsResult(
228 PasswordStore::GetLoginsRequest* request,
229 const std::vector<PasswordForm*>& matched_forms) {
230 // Copy the contents of |matched_forms| into the request. The request takes
231 // ownership of the PasswordForm elements.
232 *(request->result()) = matched_forms;
233 ForwardLoginsResult(request);
236 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
237 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
241 void PasswordStore::NotifyLoginsChanged(
242 const PasswordStoreChangeList& changes) {
243 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
244 if (!changes.empty()) {
245 observers_->Notify(&Observer::OnLoginsChanged, changes);
246 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
247 if (syncable_service_)
248 syncable_service_->ActOnPasswordStoreChanges(changes);
253 template<typename BackendFunc>
254 void PasswordStore::Schedule(
256 PasswordStoreConsumer* consumer) {
257 GetLoginsRequest* request = new GetLoginsRequest(consumer);
258 consumer->cancelable_task_tracker()->PostTask(
259 GetBackgroundTaskRunner().get(),
261 base::Bind(func, this, base::Owned(request)));
264 void PasswordStore::WrapModificationTask(ModificationTask task) {
265 PasswordStoreChangeList changes = task.Run();
266 NotifyLoginsChanged(changes);
269 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
270 void PasswordStore::InitSyncableService(
271 const syncer::SyncableService::StartSyncFlare& flare) {
272 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
273 DCHECK(!syncable_service_);
274 syncable_service_.reset(new PasswordSyncableService(this));
275 syncable_service_->InjectStartSyncFlare(flare);
278 void PasswordStore::DestroySyncableService() {
279 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
280 syncable_service_.reset();
284 } // namespace password_manager