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. 4 5 #include "chrome/browser/password_manager/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 "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" 16 17 using autofill::PasswordForm; 18 using content::BrowserThread; 19 using std::vector; 20 21 namespace { 22 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()); 30 return; 31 } 32 33 // OnGetPasswordStoreResults owns PasswordForms in the vector. 34 consumer->OnGetPasswordStoreResults(*matched_forms); 35 } 36 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; 46 } else { 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]; 51 else 52 matched_forms_copy->push_back(matched_forms[i]); 53 } 54 } 55 56 task_runner->PostTask( 57 FROM_HERE, 58 base::Bind(&RunConsumerCallbackIfNotCanceled, 59 is_canceled_cb, consumer, base::Owned(matched_forms_copy))); 60 } 61 62 } // namespace 63 64 PasswordStore::GetLoginsRequest::GetLoginsRequest( 65 const GetLoginsCallback& callback) 66 : CancelableRequest1<GetLoginsCallback, vector<PasswordForm*> >(callback) { 67 } 68 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_) { 77 delete value[i - 1]; 78 value.erase(value.begin() + (i - 1)); 79 } 80 } 81 } 82 } 83 84 PasswordStore::GetLoginsRequest::~GetLoginsRequest() { 85 if (canceled()) { 86 STLDeleteElements(&value); 87 } 88 } 89 90 PasswordStore::PasswordStore() { 91 } 92 93 bool PasswordStore::Init() { 94 ReportMetrics(); 95 return true; 96 } 97 98 void PasswordStore::AddLogin(const PasswordForm& form) { 99 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 100 base::Closure(base::Bind(&PasswordStore::AddLoginImpl, this, form)))); 101 } 102 103 void PasswordStore::UpdateLogin(const PasswordForm& form) { 104 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 105 base::Closure(base::Bind(&PasswordStore::UpdateLoginImpl, this, form)))); 106 } 107 108 void PasswordStore::RemoveLogin(const PasswordForm& form) { 109 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 110 base::Closure(base::Bind(&PasswordStore::RemoveLoginImpl, this, form)))); 111 } 112 113 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time& delete_begin, 114 const base::Time& delete_end) { 115 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 116 base::Closure( 117 base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl, this, 118 delete_begin, delete_end)))); 119 } 120 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); 141 } 142 143 CancelableTaskTracker::IsCanceledCallback is_canceled_cb; 144 CancelableTaskTracker::TaskId id = 145 consumer->cancelable_task_tracker()->NewTrackedTaskId(&is_canceled_cb); 146 147 ConsumerCallbackRunner callback_runner = 148 base::Bind(&PostConsumerCallback, 149 base::MessageLoopProxy::current(), 150 is_canceled_cb, 151 consumer, 152 ignore_logins_cutoff); 153 ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl, 154 this, form, prompt_policy, callback_runner)); 155 return id; 156 } 157 158 CancelableRequestProvider::Handle PasswordStore::GetAutofillableLogins( 159 PasswordStoreConsumer* consumer) { 160 return Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer); 161 } 162 163 CancelableRequestProvider::Handle PasswordStore::GetBlacklistLogins( 164 PasswordStoreConsumer* consumer) { 165 return Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer); 166 } 167 168 void PasswordStore::ReportMetrics() { 169 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this)); 170 } 171 172 void PasswordStore::AddObserver(Observer* observer) { 173 observers_.AddObserver(observer); 174 } 175 176 void PasswordStore::RemoveObserver(Observer* observer) { 177 observers_.RemoveObserver(observer); 178 } 179 180 PasswordStore::~PasswordStore() {} 181 182 PasswordStore::GetLoginsRequest* PasswordStore::NewGetLoginsRequest( 183 const GetLoginsCallback& callback) { 184 return new GetLoginsRequest(callback); 185 } 186 187 bool PasswordStore::ScheduleTask(const base::Closure& task) { 188 return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, task); 189 } 190 191 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) { 192 request->ApplyIgnoreLoginsCutoff(); 193 request->ForwardResult(request->handle(), request->value); 194 } 195 196 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) { 197 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete", 198 num_deletions); 199 } 200 201 template<typename BackendFunc> 202 CancelableRequestProvider::Handle PasswordStore::Schedule( 203 BackendFunc func, 204 PasswordStoreConsumer* consumer) { 205 scoped_refptr<GetLoginsRequest> request( 206 NewGetLoginsRequest( 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(); 212 } 213 214 template<typename BackendFunc> 215 CancelableRequestProvider::Handle PasswordStore::Schedule( 216 BackendFunc func, 217 PasswordStoreConsumer* consumer, 218 const PasswordForm& form, 219 const base::Time& ignore_logins_cutoff) { 220 scoped_refptr<GetLoginsRequest> request( 221 NewGetLoginsRequest( 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(); 228 } 229 230 void PasswordStore::WrapModificationTask(base::Closure task) { 231 #if !defined(OS_MACOSX) 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 233 #endif // !defined(OS_MACOSX) 234 task.Run(); 235 PostNotifyLoginsChanged(); 236 } 237 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)); 245 } 246 247 void PasswordStore::NotifyLoginsChanged() { 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 FOR_EACH_OBSERVER(Observer, observers_, OnLoginsChanged()); 250 } 251