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 shutdown_called_(false) {}
74 bool PasswordStore::Init() {
79 void PasswordStore::AddLogin(const PasswordForm
& form
) {
80 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
81 base::Closure(base::Bind(&PasswordStore::AddLoginImpl
, this, form
))));
84 void PasswordStore::UpdateLogin(const PasswordForm
& form
) {
85 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
86 base::Closure(base::Bind(&PasswordStore::UpdateLoginImpl
, this, form
))));
89 void PasswordStore::RemoveLogin(const PasswordForm
& form
) {
90 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
91 base::Closure(base::Bind(&PasswordStore::RemoveLoginImpl
, this, form
))));
94 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time
& delete_begin
,
95 const base::Time
& delete_end
) {
96 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask
, this,
98 base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl
, this,
99 delete_begin
, delete_end
))));
102 void PasswordStore::GetLogins(
103 const PasswordForm
& form
,
104 AuthorizationPromptPolicy prompt_policy
,
105 PasswordStoreConsumer
* consumer
) {
106 // Per http://crbug.com/121738, we deliberately ignore saved logins for
107 // http*://www.google.com/ that were stored prior to 2012. (Google now uses
108 // https://accounts.google.com/ for all login forms, so these should be
109 // unused.) We don't delete them just yet, and they'll still be visible in the
110 // password manager, but we won't use them to autofill any forms. This is a
111 // security feature to help minimize damage that can be done by XSS attacks.
112 // TODO(mdm): actually delete them at some point, say M24 or so.
113 base::Time ignore_logins_cutoff
; // the null time
114 if (form
.scheme
== PasswordForm::SCHEME_HTML
&&
115 (form
.signon_realm
== "http://www.google.com" ||
116 form
.signon_realm
== "http://www.google.com/" ||
117 form
.signon_realm
== "https://www.google.com" ||
118 form
.signon_realm
== "https://www.google.com/")) {
119 static const base::Time::Exploded exploded_cutoff
=
120 { 2012, 1, 0, 1, 0, 0, 0, 0 }; // 00:00 Jan 1 2012
121 ignore_logins_cutoff
= base::Time::FromUTCExploded(exploded_cutoff
);
123 GetLoginsRequest
* request
= new GetLoginsRequest(consumer
);
124 request
->set_ignore_logins_cutoff(ignore_logins_cutoff
);
126 ConsumerCallbackRunner callback_runner
=
127 base::Bind(&PasswordStore::CopyAndForwardLoginsResult
,
128 this, base::Owned(request
));
129 ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl
,
130 this, form
, prompt_policy
, callback_runner
));
133 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer
* consumer
) {
134 Schedule(&PasswordStore::GetAutofillableLoginsImpl
, consumer
);
137 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer
* consumer
) {
138 Schedule(&PasswordStore::GetBlacklistLoginsImpl
, consumer
);
141 void PasswordStore::ReportMetrics() {
142 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl
, this));
145 void PasswordStore::AddObserver(Observer
* observer
) {
146 observers_
.AddObserver(observer
);
149 void PasswordStore::RemoveObserver(Observer
* observer
) {
150 observers_
.RemoveObserver(observer
);
153 void PasswordStore::Shutdown() { shutdown_called_
= true; }
155 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_
); }
157 bool PasswordStore::ScheduleTask(const base::Closure
& task
) {
158 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner(
159 GetBackgroundTaskRunner());
160 if (task_runner
.get())
161 return task_runner
->PostTask(FROM_HERE
, task
);
165 scoped_refptr
<base::SingleThreadTaskRunner
>
166 PasswordStore::GetBackgroundTaskRunner() {
167 return db_thread_runner_
;
170 void PasswordStore::ForwardLoginsResult(GetLoginsRequest
* request
) {
171 request
->ApplyIgnoreLoginsCutoff();
172 request
->ForwardResult();
175 void PasswordStore::CopyAndForwardLoginsResult(
176 PasswordStore::GetLoginsRequest
* request
,
177 const vector
<PasswordForm
*>& matched_forms
) {
178 // Copy the contents of |matched_forms| into the request. The request takes
179 // ownership of the PasswordForm elements.
180 *(request
->result()) = matched_forms
;
181 ForwardLoginsResult(request
);
184 void PasswordStore::LogStatsForBulkDeletion(int num_deletions
) {
185 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
189 template<typename BackendFunc
>
190 void PasswordStore::Schedule(
192 PasswordStoreConsumer
* consumer
) {
193 GetLoginsRequest
* request
= new GetLoginsRequest(consumer
);
194 consumer
->cancelable_task_tracker()->PostTask(
195 GetBackgroundTaskRunner(),
197 base::Bind(func
, this, base::Owned(request
)));
200 void PasswordStore::WrapModificationTask(base::Closure task
) {
202 PostNotifyLoginsChanged();
205 void PasswordStore::PostNotifyLoginsChanged() {
206 main_thread_runner_
->PostTask(
208 base::Bind(&PasswordStore::NotifyLoginsChanged
, this));
211 void PasswordStore::NotifyLoginsChanged() {
212 DCHECK(main_thread_runner_
->BelongsToCurrentThread());
213 FOR_EACH_OBSERVER(Observer
, observers_
, OnLoginsChanged());