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. 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 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 48 PasswordStore::GetLoginsRequest::~GetLoginsRequest() { 49 } 50 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 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 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 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 89 void PasswordStore::AddLogin(const PasswordForm& form) { 90 ScheduleTask( 91 base::Bind(&PasswordStore::WrapModificationTask, this, 92 base::Bind(&PasswordStore::AddLoginImpl, this, form))); 93 } 94 95 void PasswordStore::UpdateLogin(const PasswordForm& form) { 96 ScheduleTask( 97 base::Bind(&PasswordStore::WrapModificationTask, this, 98 base::Bind(&PasswordStore::UpdateLoginImpl, this, form))); 99 } 100 101 void PasswordStore::RemoveLogin(const PasswordForm& form) { 102 ScheduleTask( 103 base::Bind(&PasswordStore::WrapModificationTask, this, 104 base::Bind(&PasswordStore::RemoveLoginImpl, this, form))); 105 } 106 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 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 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 157 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) { 158 Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer); 159 } 160 161 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) { 162 Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer); 163 } 164 165 void PasswordStore::ReportMetrics() { 166 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this)); 167 } 168 169 void PasswordStore::AddObserver(Observer* observer) { 170 observers_->AddObserver(observer); 171 } 172 173 void PasswordStore::RemoveObserver(Observer* observer) { 174 observers_->RemoveObserver(observer); 175 } 176 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 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> 194 PasswordStore::GetPasswordSyncableService() { 195 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); 196 DCHECK(syncable_service_); 197 return syncable_service_->AsWeakPtr(); 198 } 199 #endif 200 201 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); } 202 203 scoped_refptr<base::SingleThreadTaskRunner> 204 PasswordStore::GetBackgroundTaskRunner() { 205 return db_thread_runner_; 206 } 207 208 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) { 209 request->ApplyIgnoreLoginsCutoff(); 210 request->ForwardResult(); 211 } 212 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 222 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) { 223 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete", 224 num_deletions); 225 } 226 227 template<typename BackendFunc> 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 238 void PasswordStore::WrapModificationTask(ModificationTask task) { 239 PasswordStoreChangeList changes = task.Run(); 240 NotifyLoginsChanged(changes); 241 } 242 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) 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 264 void PasswordStore::DestroySyncableService() { 265 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); 266 syncable_service_.reset(); 267 } 268 #endif 269 270 } // namespace password_manager 271