password_store.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 16using autofill::PasswordForm; 17using std::vector; 18 19namespace { 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. 24void 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 34PasswordStore::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 42PasswordStore::GetLoginsRequest::~GetLoginsRequest() { 43} 44 45void 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 60void PasswordStore::GetLoginsRequest::ForwardResult() { 61 origin_loop_->PostTask(FROM_HERE, 62 base::Bind(&MaybeCallConsumerCallback, 63 consumer_weak_, 64 base::Passed(result_.Pass()))); 65} 66 67PasswordStore::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 75bool PasswordStore::Init() { 76 ReportMetrics(); 77 return true; 78} 79 80void PasswordStore::AddLogin(const PasswordForm& form) { 81 ScheduleTask( 82 base::Bind(&PasswordStore::WrapModificationTask, this, 83 base::Bind(&PasswordStore::AddLoginImpl, this, form))); 84} 85 86void PasswordStore::UpdateLogin(const PasswordForm& form) { 87 ScheduleTask( 88 base::Bind(&PasswordStore::WrapModificationTask, this, 89 base::Bind(&PasswordStore::UpdateLoginImpl, this, form))); 90} 91 92void PasswordStore::RemoveLogin(const PasswordForm& form) { 93 ScheduleTask( 94 base::Bind(&PasswordStore::WrapModificationTask, this, 95 base::Bind(&PasswordStore::RemoveLoginImpl, this, form))); 96} 97 98void 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 106void 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 137void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) { 138 Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer); 139} 140 141void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) { 142 Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer); 143} 144 145void PasswordStore::ReportMetrics() { 146 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this)); 147} 148 149void PasswordStore::AddObserver(Observer* observer) { 150 observers_->AddObserver(observer); 151} 152 153void PasswordStore::RemoveObserver(Observer* observer) { 154 observers_->RemoveObserver(observer); 155} 156 157void PasswordStore::Shutdown() { shutdown_called_ = true; } 158 159PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); } 160 161bool 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 169scoped_refptr<base::SingleThreadTaskRunner> 170PasswordStore::GetBackgroundTaskRunner() { 171 return db_thread_runner_; 172} 173 174void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) { 175 request->ApplyIgnoreLoginsCutoff(); 176 request->ForwardResult(); 177} 178 179void 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 188void PasswordStore::LogStatsForBulkDeletion(int num_deletions) { 189 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete", 190 num_deletions); 191} 192 193template<typename BackendFunc> 194void 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 204void PasswordStore::WrapModificationTask(ModificationTask task) { 205 PasswordStoreChangeList changes = task.Run(); 206 NotifyLoginsChanged(changes); 207} 208 209void PasswordStore::NotifyLoginsChanged( 210 const PasswordStoreChangeList& changes) { 211 if (!changes.empty()) 212 observers_->Notify(&Observer::OnLoginsChanged, changes); 213} 214