Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / components / password_manager / core / browser / password_store.cc
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.
4
5 #include "components/password_manager/core/browser/password_store.h"
6
7 #include "base/bind.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
16 using autofill::PasswordForm;
17 using std::vector;
18
19 namespace {
20
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) {
26   if (consumer.get())
27     consumer->OnGetPasswordStoreResults(*result);
28   else
29     STLDeleteElements(result.get());
30 }
31
32 }  // namespace
33
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();
40 }
41
42 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
43 }
44
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));
55       }
56     }
57   }
58 }
59
60 void PasswordStore::GetLoginsRequest::ForwardResult() {
61   origin_loop_->PostTask(FROM_HERE,
62                          base::Bind(&MaybeCallConsumerCallback,
63                                     consumer_weak_,
64                                     base::Passed(result_.Pass())));
65 }
66
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) {}
74
75 bool PasswordStore::Init() {
76   ReportMetrics();
77   return true;
78 }
79
80 void PasswordStore::AddLogin(const PasswordForm& form) {
81   ScheduleTask(
82       base::Bind(&PasswordStore::WrapModificationTask, this,
83                  base::Bind(&PasswordStore::AddLoginImpl, this, form)));
84 }
85
86 void PasswordStore::UpdateLogin(const PasswordForm& form) {
87   ScheduleTask(
88       base::Bind(&PasswordStore::WrapModificationTask, this,
89                  base::Bind(&PasswordStore::UpdateLoginImpl, this, form)));
90 }
91
92 void PasswordStore::RemoveLogin(const PasswordForm& form) {
93   ScheduleTask(
94       base::Bind(&PasswordStore::WrapModificationTask, this,
95                  base::Bind(&PasswordStore::RemoveLoginImpl, this, form)));
96 }
97
98 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time& delete_begin,
99                                                const base::Time& delete_end) {
100   ScheduleTask(
101       base::Bind(&PasswordStore::WrapModificationTask, this,
102                  base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl,
103                             this, delete_begin, delete_end)));
104 }
105
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);
126   }
127   GetLoginsRequest* request = new GetLoginsRequest(consumer);
128   request->set_ignore_logins_cutoff(ignore_logins_cutoff);
129
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));
135 }
136
137 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
138   Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
139 }
140
141 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
142   Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
143 }
144
145 void PasswordStore::ReportMetrics() {
146   ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this));
147 }
148
149 void PasswordStore::AddObserver(Observer* observer) {
150   observers_->AddObserver(observer);
151 }
152
153 void PasswordStore::RemoveObserver(Observer* observer) {
154   observers_->RemoveObserver(observer);
155 }
156
157 void PasswordStore::Shutdown() { shutdown_called_ = true; }
158
159 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); }
160
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);
166   return false;
167 }
168
169 scoped_refptr<base::SingleThreadTaskRunner>
170 PasswordStore::GetBackgroundTaskRunner() {
171   return db_thread_runner_;
172 }
173
174 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
175   request->ApplyIgnoreLoginsCutoff();
176   request->ForwardResult();
177 }
178
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);
186 }
187
188 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
189   UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
190                        num_deletions);
191 }
192
193 template<typename BackendFunc>
194 void PasswordStore::Schedule(
195     BackendFunc func,
196     PasswordStoreConsumer* consumer) {
197   GetLoginsRequest* request = new GetLoginsRequest(consumer);
198   consumer->cancelable_task_tracker()->PostTask(
199       GetBackgroundTaskRunner(),
200       FROM_HERE,
201       base::Bind(func, this, base::Owned(request)));
202 }
203
204 void PasswordStore::WrapModificationTask(ModificationTask task) {
205   PasswordStoreChangeList changes = task.Run();
206   NotifyLoginsChanged(changes);
207 }
208
209 void PasswordStore::NotifyLoginsChanged(
210     const PasswordStoreChangeList& changes) {
211   if (!changes.empty())
212     observers_->Notify(&Observer::OnLoginsChanged, changes);
213 }