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/stl_util.h" 12 #include "chrome/browser/password_manager/password_store_consumer.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/common/password_form.h" 15 16 using content::BrowserThread; 17 using std::vector; 18 using content::PasswordForm; 19 20 namespace { 21 22 // PasswordStoreConsumer callback requires vector const reference. 23 void RunConsumerCallbackIfNotCanceled( 24 const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb, 25 PasswordStoreConsumer* consumer, 26 const vector<PasswordForm*>* matched_forms) { 27 if (is_canceled_cb.Run()) { 28 STLDeleteContainerPointers(matched_forms->begin(), matched_forms->end()); 29 return; 30 } 31 32 // OnGetPasswordStoreResults owns PasswordForms in the vector. 33 consumer->OnGetPasswordStoreResults(*matched_forms); 34 } 35 36 void PostConsumerCallback( 37 base::TaskRunner* task_runner, 38 const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb, 39 PasswordStoreConsumer* consumer, 40 const base::Time& ignore_logins_cutoff, 41 const vector<PasswordForm*>& matched_forms) { 42 vector<PasswordForm*>* matched_forms_copy = new vector<PasswordForm*>(); 43 if (ignore_logins_cutoff.is_null()) { 44 *matched_forms_copy = matched_forms; 45 } else { 46 // Apply |ignore_logins_cutoff| and delete old ones. 47 for (size_t i = 0; i < matched_forms.size(); i++) { 48 if (matched_forms[i]->date_created < ignore_logins_cutoff) 49 delete matched_forms[i]; 50 else 51 matched_forms_copy->push_back(matched_forms[i]); 52 } 53 } 54 55 task_runner->PostTask( 56 FROM_HERE, 57 base::Bind(&RunConsumerCallbackIfNotCanceled, 58 is_canceled_cb, consumer, base::Owned(matched_forms_copy))); 59 } 60 61 } // namespace 62 63 PasswordStore::GetLoginsRequest::GetLoginsRequest( 64 const GetLoginsCallback& callback) 65 : CancelableRequest1<GetLoginsCallback, vector<PasswordForm*> >(callback) { 66 } 67 68 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() { 69 if (!ignore_logins_cutoff_.is_null()) { 70 // Count down rather than up since we may be deleting elements. 71 // Note that in principle it could be more efficient to copy the whole array 72 // since that's worst-case linear time, but we expect that elements will be 73 // deleted rarely and lists will be small, so this avoids the copies. 74 for (size_t i = value.size(); i > 0; --i) { 75 if (value[i - 1]->date_created < ignore_logins_cutoff_) { 76 delete value[i - 1]; 77 value.erase(value.begin() + (i - 1)); 78 } 79 } 80 } 81 } 82 83 PasswordStore::GetLoginsRequest::~GetLoginsRequest() { 84 if (canceled()) { 85 STLDeleteElements(&value); 86 } 87 } 88 89 PasswordStore::PasswordStore() { 90 } 91 92 bool PasswordStore::Init() { 93 ReportMetrics(); 94 return true; 95 } 96 97 void PasswordStore::AddLogin(const PasswordForm& form) { 98 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 99 base::Closure(base::Bind(&PasswordStore::AddLoginImpl, this, form)))); 100 } 101 102 void PasswordStore::UpdateLogin(const PasswordForm& form) { 103 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 104 base::Closure(base::Bind(&PasswordStore::UpdateLoginImpl, this, form)))); 105 } 106 107 void PasswordStore::RemoveLogin(const PasswordForm& form) { 108 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 109 base::Closure(base::Bind(&PasswordStore::RemoveLoginImpl, this, form)))); 110 } 111 112 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time& delete_begin, 113 const base::Time& delete_end) { 114 ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this, 115 base::Closure( 116 base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl, this, 117 delete_begin, delete_end)))); 118 } 119 120 CancelableTaskTracker::TaskId PasswordStore::GetLogins( 121 const PasswordForm& form, 122 PasswordStoreConsumer* consumer) { 123 // Per http://crbug.com/121738, we deliberately ignore saved logins for 124 // http*://www.google.com/ that were stored prior to 2012. (Google now uses 125 // https://accounts.google.com/ for all login forms, so these should be 126 // unused.) We don't delete them just yet, and they'll still be visible in the 127 // password manager, but we won't use them to autofill any forms. This is a 128 // security feature to help minimize damage that can be done by XSS attacks. 129 // TODO(mdm): actually delete them at some point, say M24 or so. 130 base::Time ignore_logins_cutoff; // the null time 131 if (form.scheme == PasswordForm::SCHEME_HTML && 132 (form.signon_realm == "http://www.google.com" || 133 form.signon_realm == "http://www.google.com/" || 134 form.signon_realm == "https://www.google.com" || 135 form.signon_realm == "https://www.google.com/")) { 136 static const base::Time::Exploded exploded_cutoff = 137 { 2012, 1, 0, 1, 0, 0, 0, 0 }; // 00:00 Jan 1 2012 138 ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff); 139 } 140 141 CancelableTaskTracker::IsCanceledCallback is_canceled_cb; 142 CancelableTaskTracker::TaskId id = 143 consumer->cancelable_task_tracker()->NewTrackedTaskId(&is_canceled_cb); 144 145 ConsumerCallbackRunner callback_runner = 146 base::Bind(&PostConsumerCallback, 147 base::MessageLoopProxy::current(), 148 is_canceled_cb, 149 consumer, 150 ignore_logins_cutoff); 151 ScheduleTask( 152 base::Bind(&PasswordStore::GetLoginsImpl, this, form, callback_runner)); 153 return id; 154 } 155 156 CancelableRequestProvider::Handle PasswordStore::GetAutofillableLogins( 157 PasswordStoreConsumer* consumer) { 158 return Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer); 159 } 160 161 CancelableRequestProvider::Handle PasswordStore::GetBlacklistLogins( 162 PasswordStoreConsumer* consumer) { 163 return Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer); 164 } 165 166 void PasswordStore::ReportMetrics() { 167 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this)); 168 } 169 170 void PasswordStore::AddObserver(Observer* observer) { 171 observers_.AddObserver(observer); 172 } 173 174 void PasswordStore::RemoveObserver(Observer* observer) { 175 observers_.RemoveObserver(observer); 176 } 177 178 PasswordStore::~PasswordStore() {} 179 180 PasswordStore::GetLoginsRequest* PasswordStore::NewGetLoginsRequest( 181 const GetLoginsCallback& callback) { 182 return new GetLoginsRequest(callback); 183 } 184 185 bool PasswordStore::ScheduleTask(const base::Closure& task) { 186 return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, task); 187 } 188 189 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) { 190 request->ApplyIgnoreLoginsCutoff(); 191 request->ForwardResult(request->handle(), request->value); 192 } 193 194 template<typename BackendFunc> 195 CancelableRequestProvider::Handle PasswordStore::Schedule( 196 BackendFunc func, 197 PasswordStoreConsumer* consumer) { 198 scoped_refptr<GetLoginsRequest> request( 199 NewGetLoginsRequest( 200 base::Bind(&PasswordStoreConsumer::OnPasswordStoreRequestDone, 201 base::Unretained(consumer)))); 202 AddRequest(request.get(), consumer->cancelable_consumer()); 203 ScheduleTask(base::Bind(func, this, request)); 204 return request->handle(); 205 } 206 207 template<typename BackendFunc> 208 CancelableRequestProvider::Handle PasswordStore::Schedule( 209 BackendFunc func, 210 PasswordStoreConsumer* consumer, 211 const PasswordForm& form, 212 const base::Time& ignore_logins_cutoff) { 213 scoped_refptr<GetLoginsRequest> request( 214 NewGetLoginsRequest( 215 base::Bind(&PasswordStoreConsumer::OnPasswordStoreRequestDone, 216 base::Unretained(consumer)))); 217 request->set_ignore_logins_cutoff(ignore_logins_cutoff); 218 AddRequest(request.get(), consumer->cancelable_consumer()); 219 ScheduleTask(base::Bind(func, this, request, form)); 220 return request->handle(); 221 } 222 223 void PasswordStore::WrapModificationTask(base::Closure task) { 224 #if !defined(OS_MACOSX) 225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 226 #endif // !defined(OS_MACOSX) 227 task.Run(); 228 PostNotifyLoginsChanged(); 229 } 230 231 void PasswordStore::PostNotifyLoginsChanged() { 232 #if !defined(OS_MACOSX) 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 234 #endif // !defined(OS_MACOSX) 235 BrowserThread::PostTask( 236 BrowserThread::UI, FROM_HERE, 237 base::Bind(&PasswordStore::NotifyLoginsChanged, this)); 238 } 239 240 void PasswordStore::NotifyLoginsChanged() { 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 242 FOR_EACH_OBSERVER(Observer, observers_, OnLoginsChanged()); 243 } 244