• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "components/password_manager/core/browser/password_syncable_service.h"
16 
17 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
18 #include "components/password_manager/core/browser/password_syncable_service.h"
19 #endif
20 
21 using autofill::PasswordForm;
22 
23 namespace password_manager {
24 
25 namespace {
26 
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.
MaybeCallConsumerCallback(base::WeakPtr<PasswordStoreConsumer> consumer,scoped_ptr<std::vector<PasswordForm * >> result)30 void MaybeCallConsumerCallback(base::WeakPtr<PasswordStoreConsumer> consumer,
31                                scoped_ptr<std::vector<PasswordForm*> > result) {
32   if (consumer.get())
33     consumer->OnGetPasswordStoreResults(*result);
34   else
35     STLDeleteElements(result.get());
36 }
37 
38 }  // namespace
39 
GetLoginsRequest(PasswordStoreConsumer * consumer)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();
46 }
47 
~GetLoginsRequest()48 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
49 }
50 
ApplyIgnoreLoginsCutoff()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));
61       }
62     }
63   }
64 }
65 
ForwardResult()66 void PasswordStore::GetLoginsRequest::ForwardResult() {
67   origin_loop_->PostTask(FROM_HERE,
68                          base::Bind(&MaybeCallConsumerCallback,
69                                     consumer_weak_,
70                                     base::Passed(result_.Pass())));
71 }
72 
PasswordStore(scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner)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) {}
80 
Init(const syncer::SyncableService::StartSyncFlare & flare)81 bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare) {
82   ReportMetrics();
83 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
84   ScheduleTask(base::Bind(&PasswordStore::InitSyncableService, this, flare));
85 #endif
86   return true;
87 }
88 
AddLogin(const PasswordForm & form)89 void PasswordStore::AddLogin(const PasswordForm& form) {
90   ScheduleTask(
91       base::Bind(&PasswordStore::WrapModificationTask, this,
92                  base::Bind(&PasswordStore::AddLoginImpl, this, form)));
93 }
94 
UpdateLogin(const PasswordForm & form)95 void PasswordStore::UpdateLogin(const PasswordForm& form) {
96   ScheduleTask(
97       base::Bind(&PasswordStore::WrapModificationTask, this,
98                  base::Bind(&PasswordStore::UpdateLoginImpl, this, form)));
99 }
100 
RemoveLogin(const PasswordForm & form)101 void PasswordStore::RemoveLogin(const PasswordForm& form) {
102   ScheduleTask(
103       base::Bind(&PasswordStore::WrapModificationTask, this,
104                  base::Bind(&PasswordStore::RemoveLoginImpl, this, form)));
105 }
106 
RemoveLoginsCreatedBetween(base::Time delete_begin,base::Time delete_end)107 void PasswordStore::RemoveLoginsCreatedBetween(base::Time delete_begin,
108                                                base::Time delete_end) {
109   ScheduleTask(
110       base::Bind(&PasswordStore::WrapModificationTask, this,
111                  base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl,
112                             this, delete_begin, delete_end)));
113 }
114 
RemoveLoginsSyncedBetween(base::Time delete_begin,base::Time delete_end)115 void PasswordStore::RemoveLoginsSyncedBetween(base::Time delete_begin,
116                                               base::Time delete_end) {
117   ScheduleTask(
118       base::Bind(&PasswordStore::WrapModificationTask,
119                  this,
120                  base::Bind(&PasswordStore::RemoveLoginsSyncedBetweenImpl,
121                             this,
122                             delete_begin,
123                             delete_end)));
124 }
125 
GetLogins(const PasswordForm & form,AuthorizationPromptPolicy prompt_policy,PasswordStoreConsumer * consumer)126 void PasswordStore::GetLogins(
127     const PasswordForm& form,
128     AuthorizationPromptPolicy prompt_policy,
129     PasswordStoreConsumer* consumer) {
130   // Per http://crbug.com/121738, we deliberately ignore saved logins for
131   // http*://www.google.com/ that were stored prior to 2012. (Google now uses
132   // https://accounts.google.com/ for all login forms, so these should be
133   // unused.) We don't delete them just yet, and they'll still be visible in the
134   // password manager, but we won't use them to autofill any forms. This is a
135   // security feature to help minimize damage that can be done by XSS attacks.
136   // TODO(mdm): actually delete them at some point, say M24 or so.
137   base::Time ignore_logins_cutoff;  // the null time
138   if (form.scheme == PasswordForm::SCHEME_HTML &&
139       (form.signon_realm == "http://www.google.com" ||
140        form.signon_realm == "http://www.google.com/" ||
141        form.signon_realm == "https://www.google.com" ||
142        form.signon_realm == "https://www.google.com/")) {
143     static const base::Time::Exploded exploded_cutoff =
144         { 2012, 1, 0, 1, 0, 0, 0, 0 };  // 00:00 Jan 1 2012
145     ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
146   }
147   GetLoginsRequest* request = new GetLoginsRequest(consumer);
148   request->set_ignore_logins_cutoff(ignore_logins_cutoff);
149 
150   ConsumerCallbackRunner callback_runner =
151       base::Bind(&PasswordStore::CopyAndForwardLoginsResult,
152                  this, base::Owned(request));
153   ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl,
154                           this, form, prompt_policy, callback_runner));
155 }
156 
GetAutofillableLogins(PasswordStoreConsumer * consumer)157 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
158   Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
159 }
160 
GetBlacklistLogins(PasswordStoreConsumer * consumer)161 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
162   Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
163 }
164 
ReportMetrics()165 void PasswordStore::ReportMetrics() {
166   ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this));
167 }
168 
AddObserver(Observer * observer)169 void PasswordStore::AddObserver(Observer* observer) {
170   observers_->AddObserver(observer);
171 }
172 
RemoveObserver(Observer * observer)173 void PasswordStore::RemoveObserver(Observer* observer) {
174   observers_->RemoveObserver(observer);
175 }
176 
ScheduleTask(const base::Closure & task)177 bool PasswordStore::ScheduleTask(const base::Closure& task) {
178   scoped_refptr<base::SingleThreadTaskRunner> task_runner(
179       GetBackgroundTaskRunner());
180   if (task_runner.get())
181     return task_runner->PostTask(FROM_HERE, task);
182   return false;
183 }
184 
Shutdown()185 void PasswordStore::Shutdown() {
186 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
187   ScheduleTask(base::Bind(&PasswordStore::DestroySyncableService, this));
188 #endif
189   shutdown_called_ = true;
190 }
191 
192 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
193 base::WeakPtr<syncer::SyncableService>
GetPasswordSyncableService()194     PasswordStore::GetPasswordSyncableService() {
195   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
196   DCHECK(syncable_service_);
197   return syncable_service_->AsWeakPtr();
198 }
199 #endif
200 
~PasswordStore()201 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); }
202 
203 scoped_refptr<base::SingleThreadTaskRunner>
GetBackgroundTaskRunner()204 PasswordStore::GetBackgroundTaskRunner() {
205   return db_thread_runner_;
206 }
207 
ForwardLoginsResult(GetLoginsRequest * request)208 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
209   request->ApplyIgnoreLoginsCutoff();
210   request->ForwardResult();
211 }
212 
CopyAndForwardLoginsResult(PasswordStore::GetLoginsRequest * request,const std::vector<PasswordForm * > & matched_forms)213 void PasswordStore::CopyAndForwardLoginsResult(
214     PasswordStore::GetLoginsRequest* request,
215     const std::vector<PasswordForm*>& matched_forms) {
216   // Copy the contents of |matched_forms| into the request. The request takes
217   // ownership of the PasswordForm elements.
218   *(request->result()) = matched_forms;
219   ForwardLoginsResult(request);
220 }
221 
LogStatsForBulkDeletion(int num_deletions)222 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
223   UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
224                        num_deletions);
225 }
226 
227 template<typename BackendFunc>
Schedule(BackendFunc func,PasswordStoreConsumer * consumer)228 void PasswordStore::Schedule(
229     BackendFunc func,
230     PasswordStoreConsumer* consumer) {
231   GetLoginsRequest* request = new GetLoginsRequest(consumer);
232   consumer->cancelable_task_tracker()->PostTask(
233       GetBackgroundTaskRunner(),
234       FROM_HERE,
235       base::Bind(func, this, base::Owned(request)));
236 }
237 
WrapModificationTask(ModificationTask task)238 void PasswordStore::WrapModificationTask(ModificationTask task) {
239   PasswordStoreChangeList changes = task.Run();
240   NotifyLoginsChanged(changes);
241 }
242 
NotifyLoginsChanged(const PasswordStoreChangeList & changes)243 void PasswordStore::NotifyLoginsChanged(
244     const PasswordStoreChangeList& changes) {
245   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
246   if (!changes.empty()) {
247     observers_->Notify(&Observer::OnLoginsChanged, changes);
248 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
249     if (syncable_service_)
250       syncable_service_->ActOnPasswordStoreChanges(changes);
251 #endif
252   }
253 }
254 
255 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
InitSyncableService(const syncer::SyncableService::StartSyncFlare & flare)256 void PasswordStore::InitSyncableService(
257     const syncer::SyncableService::StartSyncFlare& flare) {
258   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
259   DCHECK(!syncable_service_);
260   syncable_service_.reset(new PasswordSyncableService(this));
261   syncable_service_->InjectStartSyncFlare(flare);
262 }
263 
DestroySyncableService()264 void PasswordStore::DestroySyncableService() {
265   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
266   syncable_service_.reset();
267 }
268 #endif
269 
270 }  // namespace password_manager
271