Home | History | Annotate | Download | only in browser
      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