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"
15 #include "content/public/browser/browser_thread.h"
17 using autofill::PasswordForm
;
18 using content::BrowserThread
;
23 // PasswordStoreConsumer callback requires vector const reference.
24 void RunConsumerCallbackIfNotCanceled(
25 const CancelableTaskTracker::IsCanceledCallback
& is_canceled_cb
,
26 PasswordStoreConsumer
* consumer
,
27 const vector
<PasswordForm
*>* matched_forms
) {
28 if (is_canceled_cb
.Run()) {
29 STLDeleteContainerPointers(matched_forms
->begin(), matched_forms
->end());
33 // OnGetPasswordStoreResults owns PasswordForms in the vector.
34 consumer
->OnGetPasswordStoreResults(*matched_forms
);
37 void PostConsumerCallback(
38 base::TaskRunner
* task_runner
,
39 const CancelableTaskTracker::IsCanceledCallback
& is_canceled_cb
,
40 PasswordStoreConsumer
* consumer
,
41 const base::Time
& ignore_logins_cutoff
,
42 const vector
<PasswordForm
*>& matched_forms
) {
43 vector
<PasswordForm
*>* matched_forms_copy
= new vector
<PasswordForm
*>();
44 if (ignore_logins_cutoff
.is_null()) {
45 *matched_forms_copy
= matched_forms
;
47 // Apply |ignore_logins_cutoff| and delete old ones.
48 for (size_t i
= 0; i
< matched_forms
.size(); i
++) {
49 if (matched_forms
[i
]->date_created
< ignore_logins_cutoff
)
50 delete matched_forms
[i
];
52 matched_forms_copy
->push_back(matched_forms
[i
]);
56 task_runner
->PostTask(
58 base::Bind(&RunConsumerCallbackIfNotCanceled
,
59 is_canceled_cb
, consumer
, base::Owned(matched_forms_copy
)));
64 PasswordStore::GetLoginsRequest::GetLoginsRequest(
65 const GetLoginsCallback
& callback
)
66 : CancelableRequest1
<GetLoginsCallback
, vector
<PasswordForm
*> >(callback
) {
69 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() {
70 if (!ignore_logins_cutoff_
.is_null()) {
71 // Count down rather than up since we may be deleting elements.
72 // Note that in principle it could be more efficient to copy the whole array
73 // since that's worst-case linear time, but we expect that elements will be
74 // deleted rarely and lists will be small, so this avoids the copies.
75 for (size_t i
= value
.size(); i
> 0; --i
) {
76 if (value
[i
- 1]->date_created
< ignore_logins_cutoff_
) {
78 value
.erase(value
.begin() + (i
- 1));
84 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
86 STLDeleteElements(&value
);
90 PasswordStore::PasswordStore() {
93 bool PasswordStore::Init() {
98 void PasswordStore::AddLogin(const PasswordForm
& form
) {
99 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
100 base::Closure(base::Bind(&PasswordStore::AddLoginImpl
, this, form
))));
103 void PasswordStore::UpdateLogin(const PasswordForm
& form
) {
104 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
105 base::Closure(base::Bind(&PasswordStore::UpdateLoginImpl
, this, form
))));
108 void PasswordStore::RemoveLogin(const PasswordForm
& form
) {
109 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
110 base::Closure(base::Bind(&PasswordStore::RemoveLoginImpl
, this, form
))));
113 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time
& delete_begin
,
114 const base::Time
& delete_end
) {
115 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
117 base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl
, this,
118 delete_begin
, delete_end
))));
121 CancelableTaskTracker::TaskId
PasswordStore::GetLogins(
122 const PasswordForm
& form
,
123 AuthorizationPromptPolicy prompt_policy
,
124 PasswordStoreConsumer
* consumer
) {
125 // Per http://crbug.com/121738, we deliberately ignore saved logins for
126 // http*://www.google.com/ that were stored prior to 2012. (Google now uses
127 // https://accounts.google.com/ for all login forms, so these should be
128 // unused.) We don't delete them just yet, and they'll still be visible in the
129 // password manager, but we won't use them to autofill any forms. This is a
130 // security feature to help minimize damage that can be done by XSS attacks.
131 // TODO(mdm): actually delete them at some point, say M24 or so.
132 base::Time ignore_logins_cutoff
; // the null time
133 if (form
.scheme
== PasswordForm::SCHEME_HTML
&&
134 (form
.signon_realm
== "http://www.google.com" ||
135 form
.signon_realm
== "http://www.google.com/" ||
136 form
.signon_realm
== "https://www.google.com" ||
137 form
.signon_realm
== "https://www.google.com/")) {
138 static const base::Time::Exploded exploded_cutoff
=
139 { 2012, 1, 0, 1, 0, 0, 0, 0 }; // 00:00 Jan 1 2012
140 ignore_logins_cutoff
= base::Time::FromUTCExploded(exploded_cutoff
);
143 CancelableTaskTracker::IsCanceledCallback is_canceled_cb
;
144 CancelableTaskTracker::TaskId id
=
145 consumer
->cancelable_task_tracker()->NewTrackedTaskId(&is_canceled_cb
);
147 ConsumerCallbackRunner callback_runner
=
148 base::Bind(&PostConsumerCallback
,
149 base::MessageLoopProxy::current(),
152 ignore_logins_cutoff
);
153 ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl
,
154 this, form
, prompt_policy
, callback_runner
));
158 CancelableRequestProvider::Handle
PasswordStore::GetAutofillableLogins(
159 PasswordStoreConsumer
* consumer
) {
160 return Schedule(&PasswordStore::GetAutofillableLoginsImpl
, consumer
);
163 CancelableRequestProvider::Handle
PasswordStore::GetBlacklistLogins(
164 PasswordStoreConsumer
* consumer
) {
165 return Schedule(&PasswordStore::GetBlacklistLoginsImpl
, consumer
);
168 void PasswordStore::ReportMetrics() {
169 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl
, this));
172 void PasswordStore::AddObserver(Observer
* observer
) {
173 observers_
.AddObserver(observer
);
176 void PasswordStore::RemoveObserver(Observer
* observer
) {
177 observers_
.RemoveObserver(observer
);
180 PasswordStore::~PasswordStore() {}
182 PasswordStore::GetLoginsRequest
* PasswordStore::NewGetLoginsRequest(
183 const GetLoginsCallback
& callback
) {
184 return new GetLoginsRequest(callback
);
187 bool PasswordStore::ScheduleTask(const base::Closure
& task
) {
188 return BrowserThread::PostTask(BrowserThread::DB
, FROM_HERE
, task
);
191 void PasswordStore::ForwardLoginsResult(GetLoginsRequest
* request
) {
192 request
->ApplyIgnoreLoginsCutoff();
193 request
->ForwardResult(request
->handle(), request
->value
);
196 void PasswordStore::LogStatsForBulkDeletion(int num_deletions
) {
197 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
201 template<typename BackendFunc
>
202 CancelableRequestProvider::Handle
PasswordStore::Schedule(
204 PasswordStoreConsumer
* consumer
) {
205 scoped_refptr
<GetLoginsRequest
> request(
207 base::Bind(&PasswordStoreConsumer::OnPasswordStoreRequestDone
,
208 base::Unretained(consumer
))));
209 AddRequest(request
.get(), consumer
->cancelable_consumer());
210 ScheduleTask(base::Bind(func
, this, request
));
211 return request
->handle();
214 template<typename BackendFunc
>
215 CancelableRequestProvider::Handle
PasswordStore::Schedule(
217 PasswordStoreConsumer
* consumer
,
218 const PasswordForm
& form
,
219 const base::Time
& ignore_logins_cutoff
) {
220 scoped_refptr
<GetLoginsRequest
> request(
222 base::Bind(&PasswordStoreConsumer::OnPasswordStoreRequestDone
,
223 base::Unretained(consumer
))));
224 request
->set_ignore_logins_cutoff(ignore_logins_cutoff
);
225 AddRequest(request
.get(), consumer
->cancelable_consumer());
226 ScheduleTask(base::Bind(func
, this, request
, form
));
227 return request
->handle();
230 void PasswordStore::WrapModificationTask(base::Closure task
) {
231 #if !defined(OS_MACOSX)
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
233 #endif // !defined(OS_MACOSX)
235 PostNotifyLoginsChanged();
238 void PasswordStore::PostNotifyLoginsChanged() {
239 #if !defined(OS_MACOSX)
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
241 #endif // !defined(OS_MACOSX)
242 BrowserThread::PostTask(
243 BrowserThread::UI
, FROM_HERE
,
244 base::Bind(&PasswordStore::NotifyLoginsChanged
, this));
247 void PasswordStore::NotifyLoginsChanged() {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
249 FOR_EACH_OBSERVER(Observer
, observers_
, OnLoginsChanged());