1 // Copyright (c) 2012 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.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 "chrome/browser/password_manager/password_store_consumer.h"
14 #include "components/autofill/core/common/password_form.h"
16 using autofill::PasswordForm
;
21 // Calls |consumer| back with the request result, if |consumer| is still alive.
22 // Takes ownership of the elements in |result|, passing ownership to |consumer|
23 // if it is still alive.
24 void MaybeCallConsumerCallback(base::WeakPtr
<PasswordStoreConsumer
> consumer
,
25 scoped_ptr
<vector
<PasswordForm
*> > result
) {
27 consumer
->OnGetPasswordStoreResults(*result
);
29 STLDeleteElements(result
.get());
34 PasswordStore::GetLoginsRequest::GetLoginsRequest(
35 PasswordStoreConsumer
* consumer
)
36 : consumer_weak_(consumer
->GetWeakPtr()),
37 result_(new vector
<PasswordForm
*>()) {
38 DCHECK(thread_checker_
.CalledOnValidThread());
39 origin_loop_
= base::MessageLoopProxy::current();
42 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
45 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() {
46 if (!ignore_logins_cutoff_
.is_null()) {
47 // Count down rather than up since we may be deleting elements.
48 // Note that in principle it could be more efficient to copy the whole array
49 // since that's worst-case linear time, but we expect that elements will be
50 // deleted rarely and lists will be small, so this avoids the copies.
51 for (size_t i
= result_
->size(); i
> 0; --i
) {
52 if ((*result_
)[i
- 1]->date_created
< ignore_logins_cutoff_
) {
53 delete (*result_
)[i
- 1];
54 result_
->erase(result_
->begin() + (i
- 1));
60 void PasswordStore::GetLoginsRequest::ForwardResult() {
61 origin_loop_
->PostTask(FROM_HERE
,
62 base::Bind(&MaybeCallConsumerCallback
,
64 base::Passed(result_
.Pass())));
67 PasswordStore::PasswordStore(
68 scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_runner
,
69 scoped_refptr
<base::SingleThreadTaskRunner
> db_thread_runner
)
70 : main_thread_runner_(main_thread_runner
),
71 db_thread_runner_(db_thread_runner
),
72 observers_(new ObserverListThreadSafe
<Observer
>()),
73 shutdown_called_(false) {}
75 bool PasswordStore::Init() {
80 void PasswordStore::AddLogin(const PasswordForm
& form
) {
82 base::Bind(&PasswordStore::WrapModificationTask
, this,
83 base::Bind(&PasswordStore::AddLoginImpl
, this, form
)));
86 void PasswordStore::UpdateLogin(const PasswordForm
& form
) {
88 base::Bind(&PasswordStore::WrapModificationTask
, this,
89 base::Bind(&PasswordStore::UpdateLoginImpl
, this, form
)));
92 void PasswordStore::RemoveLogin(const PasswordForm
& form
) {
94 base::Bind(&PasswordStore::WrapModificationTask
, this,
95 base::Bind(&PasswordStore::RemoveLoginImpl
, this, form
)));
98 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time
& delete_begin
,
99 const base::Time
& delete_end
) {
101 base::Bind(&PasswordStore::WrapModificationTask
, this,
102 base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl
,
103 this, delete_begin
, delete_end
)));
106 void PasswordStore::GetLogins(
107 const PasswordForm
& form
,
108 AuthorizationPromptPolicy prompt_policy
,
109 PasswordStoreConsumer
* consumer
) {
110 // Per http://crbug.com/121738, we deliberately ignore saved logins for
111 // http*://www.google.com/ that were stored prior to 2012. (Google now uses
112 // https://accounts.google.com/ for all login forms, so these should be
113 // unused.) We don't delete them just yet, and they'll still be visible in the
114 // password manager, but we won't use them to autofill any forms. This is a
115 // security feature to help minimize damage that can be done by XSS attacks.
116 // TODO(mdm): actually delete them at some point, say M24 or so.
117 base::Time ignore_logins_cutoff
; // the null time
118 if (form
.scheme
== PasswordForm::SCHEME_HTML
&&
119 (form
.signon_realm
== "http://www.google.com" ||
120 form
.signon_realm
== "http://www.google.com/" ||
121 form
.signon_realm
== "https://www.google.com" ||
122 form
.signon_realm
== "https://www.google.com/")) {
123 static const base::Time::Exploded exploded_cutoff
=
124 { 2012, 1, 0, 1, 0, 0, 0, 0 }; // 00:00 Jan 1 2012
125 ignore_logins_cutoff
= base::Time::FromUTCExploded(exploded_cutoff
);
127 GetLoginsRequest
* request
= new GetLoginsRequest(consumer
);
128 request
->set_ignore_logins_cutoff(ignore_logins_cutoff
);
130 ConsumerCallbackRunner callback_runner
=
131 base::Bind(&PasswordStore::CopyAndForwardLoginsResult
,
132 this, base::Owned(request
));
133 ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl
,
134 this, form
, prompt_policy
, callback_runner
));
137 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer
* consumer
) {
138 Schedule(&PasswordStore::GetAutofillableLoginsImpl
, consumer
);
141 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer
* consumer
) {
142 Schedule(&PasswordStore::GetBlacklistLoginsImpl
, consumer
);
145 void PasswordStore::ReportMetrics() {
146 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl
, this));
149 void PasswordStore::AddObserver(Observer
* observer
) {
150 observers_
->AddObserver(observer
);
153 void PasswordStore::RemoveObserver(Observer
* observer
) {
154 observers_
->RemoveObserver(observer
);
157 void PasswordStore::Shutdown() { shutdown_called_
= true; }
159 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_
); }
161 bool PasswordStore::ScheduleTask(const base::Closure
& task
) {
162 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner(
163 GetBackgroundTaskRunner());
164 if (task_runner
.get())
165 return task_runner
->PostTask(FROM_HERE
, task
);
169 scoped_refptr
<base::SingleThreadTaskRunner
>
170 PasswordStore::GetBackgroundTaskRunner() {
171 return db_thread_runner_
;
174 void PasswordStore::ForwardLoginsResult(GetLoginsRequest
* request
) {
175 request
->ApplyIgnoreLoginsCutoff();
176 request
->ForwardResult();
179 void PasswordStore::CopyAndForwardLoginsResult(
180 PasswordStore::GetLoginsRequest
* request
,
181 const vector
<PasswordForm
*>& matched_forms
) {
182 // Copy the contents of |matched_forms| into the request. The request takes
183 // ownership of the PasswordForm elements.
184 *(request
->result()) = matched_forms
;
185 ForwardLoginsResult(request
);
188 void PasswordStore::LogStatsForBulkDeletion(int num_deletions
) {
189 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
193 template<typename BackendFunc
>
194 void PasswordStore::Schedule(
196 PasswordStoreConsumer
* consumer
) {
197 GetLoginsRequest
* request
= new GetLoginsRequest(consumer
);
198 consumer
->cancelable_task_tracker()->PostTask(
199 GetBackgroundTaskRunner(),
201 base::Bind(func
, this, base::Owned(request
)));
204 void PasswordStore::WrapModificationTask(ModificationTask task
) {
205 PasswordStoreChangeList changes
= task
.Run();
206 NotifyLoginsChanged(changes
);
209 void PasswordStore::NotifyLoginsChanged(
210 const PasswordStoreChangeList
& changes
) {
211 if (!changes
.empty())
212 observers_
->Notify(&Observer::OnLoginsChanged
, changes
);