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/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "components/autofill/core/common/password_form.h"
14 #include "components/password_manager/core/browser/password_store_consumer.h"
15 #include "components/password_manager/core/browser/password_syncable_service.h"
17 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
18 #include "components/password_manager/core/browser/password_syncable_service.h"
21 using autofill::PasswordForm;
23 namespace password_manager {
27 // Calls |consumer| back with the request result, if |consumer| is still alive.
28 // Takes ownership of the elements in |result|, passing ownership to |consumer|
29 // if it is still alive.
30 void MaybeCallConsumerCallback(base::WeakPtr<PasswordStoreConsumer> consumer,
31 scoped_ptr<std::vector<PasswordForm*> > result) {
33 consumer->OnGetPasswordStoreResults(*result);
35 STLDeleteElements(result.get());
40 PasswordStore::GetLoginsRequest::GetLoginsRequest(
41 PasswordStoreConsumer* consumer)
42 : consumer_weak_(consumer->GetWeakPtr()),
43 result_(new std::vector<PasswordForm*>()) {
44 DCHECK(thread_checker_.CalledOnValidThread());
45 origin_loop_ = base::MessageLoopProxy::current();
48 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
51 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() {
52 if (!ignore_logins_cutoff_.is_null()) {
53 // Count down rather than up since we may be deleting elements.
54 // Note that in principle it could be more efficient to copy the whole array
55 // since that's worst-case linear time, but we expect that elements will be
56 // deleted rarely and lists will be small, so this avoids the copies.
57 for (size_t i = result_->size(); i > 0; --i) {
58 if ((*result_)[i - 1]->date_created < ignore_logins_cutoff_) {
59 delete (*result_)[i - 1];
60 result_->erase(result_->begin() + (i - 1));
66 void PasswordStore::GetLoginsRequest::ForwardResult() {
67 origin_loop_->PostTask(FROM_HERE,
68 base::Bind(&MaybeCallConsumerCallback,
70 base::Passed(result_.Pass())));
73 PasswordStore::PasswordStore(
74 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
75 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner)
76 : main_thread_runner_(main_thread_runner),
77 db_thread_runner_(db_thread_runner),
78 observers_(new ObserverListThreadSafe<Observer>()),
79 shutdown_called_(false) {}
81 bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare) {
83 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
84 ScheduleTask(base::Bind(&PasswordStore::InitSyncableService, this, flare));
89 void PasswordStore::AddLogin(const PasswordForm& form) {
91 base::Bind(&PasswordStore::WrapModificationTask, this,
92 base::Bind(&PasswordStore::AddLoginImpl, this, form)));
95 void PasswordStore::UpdateLogin(const PasswordForm& form) {
97 base::Bind(&PasswordStore::WrapModificationTask, this,
98 base::Bind(&PasswordStore::UpdateLoginImpl, this, form)));
101 void PasswordStore::RemoveLogin(const PasswordForm& form) {
103 base::Bind(&PasswordStore::WrapModificationTask, this,
104 base::Bind(&PasswordStore::RemoveLoginImpl, this, form)));
107 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time& delete_begin,
108 const base::Time& delete_end) {
110 base::Bind(&PasswordStore::WrapModificationTask, this,
111 base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl,
112 this, delete_begin, delete_end)));
115 void PasswordStore::GetLogins(
116 const PasswordForm& form,
117 AuthorizationPromptPolicy prompt_policy,
118 PasswordStoreConsumer* consumer) {
119 // Per http://crbug.com/121738, we deliberately ignore saved logins for
120 // http*://www.google.com/ that were stored prior to 2012. (Google now uses
121 // https://accounts.google.com/ for all login forms, so these should be
122 // unused.) We don't delete them just yet, and they'll still be visible in the
123 // password manager, but we won't use them to autofill any forms. This is a
124 // security feature to help minimize damage that can be done by XSS attacks.
125 // TODO(mdm): actually delete them at some point, say M24 or so.
126 base::Time ignore_logins_cutoff; // the null time
127 if (form.scheme == PasswordForm::SCHEME_HTML &&
128 (form.signon_realm == "http://www.google.com" ||
129 form.signon_realm == "http://www.google.com/" ||
130 form.signon_realm == "https://www.google.com" ||
131 form.signon_realm == "https://www.google.com/")) {
132 static const base::Time::Exploded exploded_cutoff =
133 { 2012, 1, 0, 1, 0, 0, 0, 0 }; // 00:00 Jan 1 2012
134 ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
136 GetLoginsRequest* request = new GetLoginsRequest(consumer);
137 request->set_ignore_logins_cutoff(ignore_logins_cutoff);
139 ConsumerCallbackRunner callback_runner =
140 base::Bind(&PasswordStore::CopyAndForwardLoginsResult,
141 this, base::Owned(request));
142 ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl,
143 this, form, prompt_policy, callback_runner));
146 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
147 Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
150 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
151 Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
154 void PasswordStore::ReportMetrics() {
155 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this));
158 void PasswordStore::AddObserver(Observer* observer) {
159 observers_->AddObserver(observer);
162 void PasswordStore::RemoveObserver(Observer* observer) {
163 observers_->RemoveObserver(observer);
166 bool PasswordStore::ScheduleTask(const base::Closure& task) {
167 scoped_refptr<base::SingleThreadTaskRunner> task_runner(
168 GetBackgroundTaskRunner());
169 if (task_runner.get())
170 return task_runner->PostTask(FROM_HERE, task);
174 void PasswordStore::Shutdown() {
175 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
176 ScheduleTask(base::Bind(&PasswordStore::DestroySyncableService, this));
178 shutdown_called_ = true;
181 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
182 base::WeakPtr<syncer::SyncableService>
183 PasswordStore::GetPasswordSyncableService() {
184 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
185 DCHECK(syncable_service_);
186 return syncable_service_->AsWeakPtr();
190 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); }
192 scoped_refptr<base::SingleThreadTaskRunner>
193 PasswordStore::GetBackgroundTaskRunner() {
194 return db_thread_runner_;
197 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
198 request->ApplyIgnoreLoginsCutoff();
199 request->ForwardResult();
202 void PasswordStore::CopyAndForwardLoginsResult(
203 PasswordStore::GetLoginsRequest* request,
204 const std::vector<PasswordForm*>& matched_forms) {
205 // Copy the contents of |matched_forms| into the request. The request takes
206 // ownership of the PasswordForm elements.
207 *(request->result()) = matched_forms;
208 ForwardLoginsResult(request);
211 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
212 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
216 template<typename BackendFunc>
217 void PasswordStore::Schedule(
219 PasswordStoreConsumer* consumer) {
220 GetLoginsRequest* request = new GetLoginsRequest(consumer);
221 consumer->cancelable_task_tracker()->PostTask(
222 GetBackgroundTaskRunner(),
224 base::Bind(func, this, base::Owned(request)));
227 void PasswordStore::WrapModificationTask(ModificationTask task) {
228 PasswordStoreChangeList changes = task.Run();
229 NotifyLoginsChanged(changes);
232 void PasswordStore::NotifyLoginsChanged(
233 const PasswordStoreChangeList& changes) {
234 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
235 if (!changes.empty()) {
236 observers_->Notify(&Observer::OnLoginsChanged, changes);
237 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
238 if (syncable_service_)
239 syncable_service_->ActOnPasswordStoreChanges(changes);
244 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
245 void PasswordStore::InitSyncableService(
246 const syncer::SyncableService::StartSyncFlare& flare) {
247 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
248 DCHECK(!syncable_service_);
249 syncable_service_.reset(new PasswordSyncableService(this));
250 syncable_service_->InjectStartSyncFlare(flare);
253 void PasswordStore::DestroySyncableService() {
254 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
255 syncable_service_.reset();
259 } // namespace password_manager