- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / password_store_x.cc
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_x.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/stl_util.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/password_manager/password_store_change.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/user_prefs/pref_registry_syncable.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/notification_service.h"
21
22 using autofill::PasswordForm;
23 using content::BrowserThread;
24 using std::vector;
25
26 PasswordStoreX::PasswordStoreX(LoginDatabase* login_db,
27                                Profile* profile,
28                                NativeBackend* backend)
29     : PasswordStoreDefault(login_db, profile),
30       backend_(backend), migration_checked_(!backend), allow_fallback_(false) {
31 }
32
33 PasswordStoreX::~PasswordStoreX() {}
34
35 void PasswordStoreX::AddLoginImpl(const PasswordForm& form) {
36   CheckMigration();
37   if (use_native_backend() && backend_->AddLogin(form)) {
38     PasswordStoreChangeList changes;
39     changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
40     content::NotificationService::current()->Notify(
41         chrome::NOTIFICATION_LOGINS_CHANGED,
42         content::Source<PasswordStore>(this),
43         content::Details<PasswordStoreChangeList>(&changes));
44     allow_fallback_ = false;
45   } else if (allow_default_store()) {
46     PasswordStoreDefault::AddLoginImpl(form);
47   }
48 }
49
50 void PasswordStoreX::UpdateLoginImpl(const PasswordForm& form) {
51   CheckMigration();
52   if (use_native_backend() && backend_->UpdateLogin(form)) {
53     PasswordStoreChangeList changes;
54     changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form));
55     content::NotificationService::current()->Notify(
56         chrome::NOTIFICATION_LOGINS_CHANGED,
57         content::Source<PasswordStore>(this),
58         content::Details<PasswordStoreChangeList>(&changes));
59     allow_fallback_ = false;
60   } else if (allow_default_store()) {
61     PasswordStoreDefault::UpdateLoginImpl(form);
62   }
63 }
64
65 void PasswordStoreX::RemoveLoginImpl(const PasswordForm& form) {
66   CheckMigration();
67   if (use_native_backend() && backend_->RemoveLogin(form)) {
68     PasswordStoreChangeList changes;
69     changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
70     content::NotificationService::current()->Notify(
71         chrome::NOTIFICATION_LOGINS_CHANGED,
72         content::Source<PasswordStore>(this),
73         content::Details<PasswordStoreChangeList>(&changes));
74     allow_fallback_ = false;
75   } else if (allow_default_store()) {
76     PasswordStoreDefault::RemoveLoginImpl(form);
77   }
78 }
79
80 void PasswordStoreX::RemoveLoginsCreatedBetweenImpl(
81     const base::Time& delete_begin,
82     const base::Time& delete_end) {
83   CheckMigration();
84   vector<PasswordForm*> forms;
85   if (use_native_backend() &&
86       backend_->GetLoginsCreatedBetween(delete_begin, delete_end, &forms) &&
87       backend_->RemoveLoginsCreatedBetween(delete_begin, delete_end)) {
88     PasswordStoreChangeList changes;
89     for (vector<PasswordForm*>::const_iterator it = forms.begin();
90          it != forms.end(); ++it) {
91       changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
92                                             **it));
93     }
94     LogStatsForBulkDeletion(changes.size());
95     content::NotificationService::current()->Notify(
96         chrome::NOTIFICATION_LOGINS_CHANGED,
97         content::Source<PasswordStore>(this),
98         content::Details<PasswordStoreChangeList>(&changes));
99     allow_fallback_ = false;
100   } else if (allow_default_store()) {
101     PasswordStoreDefault::RemoveLoginsCreatedBetweenImpl(delete_begin,
102                                                          delete_end);
103   }
104   STLDeleteElements(&forms);
105 }
106
107 namespace {
108 struct LoginLessThan {
109   bool operator()(const PasswordForm* a, const PasswordForm* b) {
110     return a->origin < b->origin;
111   }
112 };
113 }  // anonymous namespace
114
115 void PasswordStoreX::SortLoginsByOrigin(NativeBackend::PasswordFormList* list) {
116   // In login_database.cc, the query has ORDER BY origin_url. Simulate that.
117   std::sort(list->begin(), list->end(), LoginLessThan());
118 }
119
120 void PasswordStoreX::GetLoginsImpl(
121     const autofill::PasswordForm& form,
122     const ConsumerCallbackRunner& callback_runner) {
123   CheckMigration();
124   std::vector<autofill::PasswordForm*> matched_forms;
125   if (use_native_backend() && backend_->GetLogins(form, &matched_forms)) {
126     SortLoginsByOrigin(&matched_forms);
127     callback_runner.Run(matched_forms);
128     // The native backend may succeed and return no data even while locked, if
129     // the query did not match anything stored. So we continue to allow fallback
130     // until we perform a write operation, or until a read returns actual data.
131     if (matched_forms.size() > 0)
132       allow_fallback_ = false;
133   } else if (allow_default_store()) {
134     DCHECK(matched_forms.empty());
135     PasswordStoreDefault::GetLoginsImpl(form, callback_runner);
136   } else {
137     // The consumer will be left hanging unless we reply.
138     callback_runner.Run(matched_forms);
139   }
140 }
141
142 void PasswordStoreX::GetAutofillableLoginsImpl(GetLoginsRequest* request) {
143   CheckMigration();
144   if (use_native_backend() &&
145       backend_->GetAutofillableLogins(&request->value)) {
146     SortLoginsByOrigin(&request->value);
147     ForwardLoginsResult(request);
148     // See GetLoginsImpl() for why we disallow fallback conditionally here.
149     if (request->value.size() > 0)
150       allow_fallback_ = false;
151   } else if (allow_default_store()) {
152     PasswordStoreDefault::GetAutofillableLoginsImpl(request);
153   } else {
154     // The consumer will be left hanging unless we reply.
155     ForwardLoginsResult(request);
156   }
157 }
158
159 void PasswordStoreX::GetBlacklistLoginsImpl(GetLoginsRequest* request) {
160   CheckMigration();
161   if (use_native_backend() &&
162       backend_->GetBlacklistLogins(&request->value)) {
163     SortLoginsByOrigin(&request->value);
164     ForwardLoginsResult(request);
165     // See GetLoginsImpl() for why we disallow fallback conditionally here.
166     if (request->value.size() > 0)
167       allow_fallback_ = false;
168   } else if (allow_default_store()) {
169     PasswordStoreDefault::GetBlacklistLoginsImpl(request);
170   } else {
171     // The consumer will be left hanging unless we reply.
172     ForwardLoginsResult(request);
173   }
174 }
175
176 bool PasswordStoreX::FillAutofillableLogins(vector<PasswordForm*>* forms) {
177   CheckMigration();
178   if (use_native_backend() && backend_->GetAutofillableLogins(forms)) {
179     // See GetLoginsImpl() for why we disallow fallback conditionally here.
180     if (forms->size() > 0)
181       allow_fallback_ = false;
182     return true;
183   }
184   if (allow_default_store())
185     return PasswordStoreDefault::FillAutofillableLogins(forms);
186   return false;
187 }
188
189 bool PasswordStoreX::FillBlacklistLogins(vector<PasswordForm*>* forms) {
190   CheckMigration();
191   if (use_native_backend() && backend_->GetBlacklistLogins(forms)) {
192     // See GetLoginsImpl() for why we disallow fallback conditionally here.
193     if (forms->size() > 0)
194       allow_fallback_ = false;
195     return true;
196   }
197   if (allow_default_store())
198     return PasswordStoreDefault::FillBlacklistLogins(forms);
199   return false;
200 }
201
202 void PasswordStoreX::CheckMigration() {
203   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
204   if (migration_checked_ || !backend_.get())
205     return;
206   migration_checked_ = true;
207   ssize_t migrated = MigrateLogins();
208   if (migrated > 0) {
209     VLOG(1) << "Migrated " << migrated << " passwords to native store.";
210   } else if (migrated == 0) {
211     // As long as we are able to migrate some passwords, we know the native
212     // store is working. But if there is nothing to migrate, the "migration"
213     // can succeed even when the native store would fail. In this case we
214     // allow a later fallback to the default store. Once any later operation
215     // succeeds on the native store, we will no longer allow fallback.
216     allow_fallback_ = true;
217   } else {
218     LOG(WARNING) << "Native password store migration failed! " <<
219                  "Falling back on default (unencrypted) store.";
220     backend_.reset(NULL);
221   }
222 }
223
224 bool PasswordStoreX::allow_default_store() {
225   if (allow_fallback_) {
226     LOG(WARNING) << "Native password store failed! " <<
227                  "Falling back on default (unencrypted) store.";
228     backend_.reset(NULL);
229     // Don't warn again. We'll use the default store because backend_ is NULL.
230     allow_fallback_ = false;
231   }
232   return !backend_.get();
233 }
234
235 ssize_t PasswordStoreX::MigrateLogins() {
236   DCHECK(backend_.get());
237   vector<PasswordForm*> forms;
238   bool ok = PasswordStoreDefault::FillAutofillableLogins(&forms) &&
239       PasswordStoreDefault::FillBlacklistLogins(&forms);
240   if (ok) {
241     // We add all the passwords (and blacklist entries) to the native backend
242     // before attempting to remove any from the login database, to make sure we
243     // don't somehow end up with some of the passwords in one store and some in
244     // another. We'll always have at least one intact store this way.
245     for (size_t i = 0; i < forms.size(); ++i) {
246       if (!backend_->AddLogin(*forms[i])) {
247         ok = false;
248         break;
249       }
250     }
251     if (ok) {
252       for (size_t i = 0; i < forms.size(); ++i) {
253         // If even one of these calls to RemoveLoginImpl() succeeds, then we
254         // should prefer the native backend to the now-incomplete login
255         // database. Thus we want to return a success status even in the case
256         // where some fail. The only real problem with this is that we might
257         // leave passwords in the login database and never come back to clean
258         // them out if any of these calls do fail.
259         PasswordStoreDefault::RemoveLoginImpl(*forms[i]);
260       }
261       // Finally, delete the database file itself. We remove the passwords from
262       // it before deleting the file just in case there is some problem deleting
263       // the file (e.g. directory is not writable, but file is), which would
264       // otherwise cause passwords to re-migrate next (or maybe every) time.
265       DeleteAndRecreateDatabaseFile();
266     }
267   }
268   ssize_t result = ok ? forms.size() : -1;
269   STLDeleteElements(&forms);
270   return result;
271 }
272
273 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && defined(OS_POSIX)
274 // static
275 void PasswordStoreX::RegisterProfilePrefs(
276     user_prefs::PrefRegistrySyncable* registry) {
277   // Normally we should be on the UI thread here, but in tests we might not.
278   registry->RegisterBooleanPref(
279       prefs::kPasswordsUseLocalProfileId,
280       // default: passwords don't use local ids
281       false,
282       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
283 }
284
285 // static
286 bool PasswordStoreX::PasswordsUseLocalProfileId(PrefService* prefs) {
287   // Normally we should be on the UI thread here, but in tests we might not.
288   return prefs->GetBoolean(prefs::kPasswordsUseLocalProfileId);
289 }
290
291 namespace {
292 // This function is a hack to do something not entirely thread safe: the pref
293 // service comes from the UI thread, but it's not ref counted. We keep a pointer
294 // to it on the DB thread, and need to invoke a method on the UI thread. This
295 // function does that for us without requiring ref counting the pref service.
296 // TODO(mdm): Fix this if it becomes a problem. Given that this function will
297 // be called once ever per profile, it probably will not cause a problem...
298 void UISetPasswordsUseLocalProfileId(PrefService* prefs) {
299   prefs->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
300 }
301 }  // anonymous namespace
302
303 // static
304 void PasswordStoreX::SetPasswordsUseLocalProfileId(PrefService* prefs) {
305   // This method should work on any thread, but we expect the DB thread.
306   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
307   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
308                           base::Bind(&UISetPasswordsUseLocalProfileId, prefs));
309 }
310 #endif  // !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && defined(OS_POSIX)