1// Copyright (c) 2011 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_default.h"
6
7#include <set>
8
9#include "base/logging.h"
10#include "base/stl_util-inl.h"
11#include "chrome/browser/password_manager/password_store_change.h"
12#include "chrome/browser/prefs/pref_service.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/webdata/web_data_service.h"
15#include "chrome/common/chrome_constants.h"
16#include "chrome/common/pref_names.h"
17#include "content/browser/browser_thread.h"
18#include "content/common/notification_service.h"
19
20using webkit_glue::PasswordForm;
21
22// MigrateHelper handles migration from WebDB to PasswordStore. It runs
23// entirely on the UI thread and is owned by PasswordStoreDefault.
24class PasswordStoreDefault::MigrateHelper : public WebDataServiceConsumer {
25 public:
26  MigrateHelper(Profile* profile,
27                WebDataService* web_data_service,
28                PasswordStore* password_store)
29      : profile_(profile),
30        web_data_service_(web_data_service),
31        password_store_(password_store) {
32  }
33  ~MigrateHelper();
34
35  void Init();
36
37  // WebDataServiceConsumer:
38  virtual void OnWebDataServiceRequestDone(
39      WebDataService::Handle handle,
40      const WDTypedResult *result) OVERRIDE;
41
42 private:
43  typedef std::set<WebDataService::Handle> Handles;
44
45  Profile* profile_;
46
47  scoped_refptr<WebDataService> web_data_service_;
48
49  // This creates a cycle between us and PasswordStore. The cycle is broken
50  // from PasswordStoreDefault::Shutdown, which deletes us.
51  scoped_refptr<PasswordStore> password_store_;
52
53  // Set of handles from requesting data from the WebDB.
54  Handles handles_;
55
56  DISALLOW_COPY_AND_ASSIGN(MigrateHelper);
57};
58
59PasswordStoreDefault::MigrateHelper::~MigrateHelper() {
60  for (Handles::const_iterator i = handles_.begin(); i != handles_.end(); ++i)
61    web_data_service_->CancelRequest(*i);
62  handles_.clear();
63}
64
65void PasswordStoreDefault::MigrateHelper::Init() {
66  handles_.insert(web_data_service_->GetAutofillableLogins(this));
67  handles_.insert(web_data_service_->GetBlacklistLogins(this));
68}
69
70void PasswordStoreDefault::MigrateHelper::OnWebDataServiceRequestDone(
71    WebDataService::Handle handle,
72    const WDTypedResult* result) {
73  typedef std::vector<const PasswordForm*> PasswordForms;
74
75  DCHECK(handles_.end() != handles_.find(handle));
76  DCHECK(password_store_);
77
78  handles_.erase(handle);
79  if (!result)
80    return;
81
82  if (PASSWORD_RESULT != result->GetType()) {
83    NOTREACHED();
84    return;
85  }
86
87  const PasswordForms& forms =
88      static_cast<const WDResult<PasswordForms>*>(result)->GetValue();
89  for (PasswordForms::const_iterator it = forms.begin();
90       it != forms.end(); ++it) {
91    password_store_->AddLogin(**it);
92    web_data_service_->RemoveLogin(**it);
93    delete *it;
94  }
95  if (handles_.empty()) {
96    profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
97                                              true);
98  }
99}
100
101PasswordStoreDefault::PasswordStoreDefault(LoginDatabase* login_db,
102                                           Profile* profile,
103                                           WebDataService* web_data_service)
104    : web_data_service_(web_data_service),
105      login_db_(login_db), profile_(profile) {
106  DCHECK(login_db);
107  DCHECK(profile);
108  DCHECK(web_data_service);
109  MigrateIfNecessary();
110}
111
112PasswordStoreDefault::~PasswordStoreDefault() {
113  // MigrateHelper should always be NULL as Shutdown should be invoked before
114  // the destructor.
115  DCHECK(!migrate_helper_.get());
116}
117
118void PasswordStoreDefault::Shutdown() {
119  migrate_helper_.reset();
120}
121
122void PasswordStoreDefault::ReportMetricsImpl() {
123  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
124  login_db_->ReportMetrics();
125}
126
127void PasswordStoreDefault::AddLoginImpl(const PasswordForm& form) {
128  if (login_db_->AddLogin(form)) {
129    PasswordStoreChangeList changes;
130    changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
131    NotificationService::current()->Notify(
132        NotificationType::LOGINS_CHANGED,
133        Source<PasswordStore>(this),
134        Details<PasswordStoreChangeList>(&changes));
135  }
136}
137
138void PasswordStoreDefault::UpdateLoginImpl(const PasswordForm& form) {
139  if (login_db_->UpdateLogin(form, NULL)) {
140    PasswordStoreChangeList changes;
141    changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form));
142    NotificationService::current()->Notify(
143        NotificationType::LOGINS_CHANGED,
144        Source<PasswordStore>(this),
145        Details<PasswordStoreChangeList>(&changes));
146  }
147}
148
149void PasswordStoreDefault::RemoveLoginImpl(const PasswordForm& form) {
150  if (login_db_->RemoveLogin(form)) {
151    PasswordStoreChangeList changes;
152    changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
153    NotificationService::current()->Notify(
154        NotificationType::LOGINS_CHANGED,
155        Source<PasswordStore>(this),
156        Details<PasswordStoreChangeList>(&changes));
157  }
158}
159
160void PasswordStoreDefault::RemoveLoginsCreatedBetweenImpl(
161    const base::Time& delete_begin, const base::Time& delete_end) {
162  std::vector<PasswordForm*> forms;
163  if (login_db_->GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) {
164    if (login_db_->RemoveLoginsCreatedBetween(delete_begin, delete_end)) {
165      PasswordStoreChangeList changes;
166      for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
167           it != forms.end(); ++it) {
168        changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
169                                              **it));
170      }
171      NotificationService::current()->Notify(
172          NotificationType::LOGINS_CHANGED,
173          Source<PasswordStore>(this),
174          Details<PasswordStoreChangeList>(&changes));
175    }
176  }
177  STLDeleteElements(&forms);
178}
179
180void PasswordStoreDefault::GetLoginsImpl(
181    GetLoginsRequest* request, const webkit_glue::PasswordForm& form) {
182  login_db_->GetLogins(form, &request->value);
183  ForwardLoginsResult(request);
184}
185
186void PasswordStoreDefault::GetAutofillableLoginsImpl(
187    GetLoginsRequest* request) {
188  FillAutofillableLogins(&request->value);
189  ForwardLoginsResult(request);
190}
191
192void PasswordStoreDefault::GetBlacklistLoginsImpl(
193    GetLoginsRequest* request) {
194  FillBlacklistLogins(&request->value);
195  ForwardLoginsResult(request);
196}
197
198bool PasswordStoreDefault::FillAutofillableLogins(
199         std::vector<PasswordForm*>* forms) {
200  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
201  return login_db_->GetAutofillableLogins(forms);
202}
203
204bool PasswordStoreDefault::FillBlacklistLogins(
205         std::vector<PasswordForm*>* forms) {
206  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
207  return login_db_->GetBlacklistLogins(forms);
208}
209
210void PasswordStoreDefault::MigrateIfNecessary() {
211  PrefService* prefs = profile_->GetPrefs();
212  if (prefs->FindPreference(prefs::kLoginDatabaseMigrated))
213    return;
214  DCHECK(!migrate_helper_.get());
215  migrate_helper_.reset(new MigrateHelper(profile_, web_data_service_, this));
216  migrate_helper_->Init();
217}
218