Fix infinite recursion on hiding panel when created during fullscreen mode.
[chromium-blink-merge.git] / components / password_manager / core / browser / login_database.cc
blobcf825c618901e3ee990a7f4bb1da4398aea81234
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.
5 #include "components/password_manager/core/browser/login_database.h"
7 #include <algorithm>
8 #include <limits>
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/pickle.h"
14 #include "base/strings/string_util.h"
15 #include "base/time/time.h"
16 #include "components/autofill/core/common/password_form.h"
17 #include "sql/connection.h"
18 #include "sql/statement.h"
19 #include "sql/transaction.h"
21 using autofill::PasswordForm;
23 static const int kCurrentVersionNumber = 5;
24 static const int kCompatibleVersionNumber = 1;
26 namespace {
28 // Convenience enum for interacting with SQL queries that use all the columns.
29 enum LoginTableColumns {
30 COLUMN_ORIGIN_URL = 0,
31 COLUMN_ACTION_URL,
32 COLUMN_USERNAME_ELEMENT,
33 COLUMN_USERNAME_VALUE,
34 COLUMN_PASSWORD_ELEMENT,
35 COLUMN_PASSWORD_VALUE,
36 COLUMN_SUBMIT_ELEMENT,
37 COLUMN_SIGNON_REALM,
38 COLUMN_SSL_VALID,
39 COLUMN_PREFERRED,
40 COLUMN_DATE_CREATED,
41 COLUMN_BLACKLISTED_BY_USER,
42 COLUMN_SCHEME,
43 COLUMN_PASSWORD_TYPE,
44 COLUMN_POSSIBLE_USERNAMES,
45 COLUMN_TIMES_USED,
46 COLUMN_FORM_DATA,
47 COLUMN_USE_ADDITIONAL_AUTH
50 } // namespace
52 LoginDatabase::LoginDatabase() {
55 LoginDatabase::~LoginDatabase() {
58 bool LoginDatabase::Init(const base::FilePath& db_path) {
59 // Set pragmas for a small, private database (based on WebDatabase).
60 db_.set_page_size(2048);
61 db_.set_cache_size(32);
62 db_.set_exclusive_locking();
63 db_.set_restrict_to_user();
65 if (!db_.Open(db_path)) {
66 LOG(WARNING) << "Unable to open the password store database.";
67 return false;
70 sql::Transaction transaction(&db_);
71 transaction.Begin();
73 // Check the database version.
74 if (!meta_table_.Init(&db_, kCurrentVersionNumber,
75 kCompatibleVersionNumber)) {
76 db_.Close();
77 return false;
79 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
80 LOG(WARNING) << "Password store database is too new.";
81 db_.Close();
82 return false;
85 // Initialize the tables.
86 if (!InitLoginsTable()) {
87 LOG(WARNING) << "Unable to initialize the password store database.";
88 db_.Close();
89 return false;
92 // Save the path for DeleteDatabaseFile().
93 db_path_ = db_path;
95 // If the file on disk is an older database version, bring it up to date.
96 if (!MigrateOldVersionsAsNeeded()) {
97 LOG(WARNING) << "Unable to migrate database";
98 db_.Close();
99 return false;
102 if (!transaction.Commit()) {
103 db_.Close();
104 return false;
107 return true;
110 bool LoginDatabase::MigrateOldVersionsAsNeeded() {
111 switch (meta_table_.GetVersionNumber()) {
112 case 1:
113 if (!db_.Execute("ALTER TABLE logins "
114 "ADD COLUMN password_type INTEGER") ||
115 !db_.Execute("ALTER TABLE logins "
116 "ADD COLUMN possible_usernames BLOB")) {
117 return false;
119 meta_table_.SetVersionNumber(2);
120 // Fall through.
121 case 2:
122 if (!db_.Execute("ALTER TABLE logins ADD COLUMN times_used INTEGER")) {
123 return false;
125 meta_table_.SetVersionNumber(3);
126 // Fall through.
127 case 3:
128 // We need to check if the column exists because of
129 // https://crbug.com/295851
130 if (!db_.DoesColumnExist("logins", "form_data") &&
131 !db_.Execute("ALTER TABLE logins ADD COLUMN form_data BLOB")) {
132 return false;
134 meta_table_.SetVersionNumber(4);
135 // Fall through.
136 case 4:
137 if (!db_.Execute(
138 "ALTER TABLE logins ADD COLUMN use_additional_auth INTEGER")) {
139 return false;
141 meta_table_.SetVersionNumber(5);
142 // Fall through.
143 case kCurrentVersionNumber:
144 // Already up to date
145 return true;
146 default:
147 NOTREACHED();
148 return false;
152 bool LoginDatabase::InitLoginsTable() {
153 if (!db_.DoesTableExist("logins")) {
154 if (!db_.Execute("CREATE TABLE logins ("
155 "origin_url VARCHAR NOT NULL, "
156 "action_url VARCHAR, "
157 "username_element VARCHAR, "
158 "username_value VARCHAR, "
159 "password_element VARCHAR, "
160 "password_value BLOB, "
161 "submit_element VARCHAR, "
162 "signon_realm VARCHAR NOT NULL,"
163 "ssl_valid INTEGER NOT NULL,"
164 "preferred INTEGER NOT NULL,"
165 "date_created INTEGER NOT NULL,"
166 "blacklisted_by_user INTEGER NOT NULL,"
167 "scheme INTEGER NOT NULL,"
168 "password_type INTEGER,"
169 "possible_usernames BLOB,"
170 "times_used INTEGER,"
171 "form_data BLOB,"
172 "use_additional_auth INTEGER,"
173 "UNIQUE "
174 "(origin_url, username_element, "
175 "username_value, password_element, "
176 "submit_element, signon_realm))")) {
177 NOTREACHED();
178 return false;
180 if (!db_.Execute("CREATE INDEX logins_signon ON "
181 "logins (signon_realm)")) {
182 NOTREACHED();
183 return false;
186 return true;
189 void LoginDatabase::ReportMetrics() {
190 sql::Statement s(db_.GetCachedStatement(
191 SQL_FROM_HERE,
192 "SELECT signon_realm, blacklisted_by_user, COUNT(username_value) "
193 "FROM logins GROUP BY signon_realm, blacklisted_by_user"));
195 if (!s.is_valid())
196 return;
198 int total_accounts = 0;
199 int blacklisted_sites = 0;
200 while (s.Step()) {
201 int blacklisted = s.ColumnInt(1);
202 int accounts_per_site = s.ColumnInt(2);
203 if (blacklisted) {
204 ++blacklisted_sites;
205 } else {
206 total_accounts += accounts_per_site;
207 UMA_HISTOGRAM_CUSTOM_COUNTS("PasswordManager.AccountsPerSite",
208 accounts_per_site, 0, 32, 6);
211 UMA_HISTOGRAM_CUSTOM_COUNTS("PasswordManager.TotalAccounts",
212 total_accounts, 0, 32, 6);
213 UMA_HISTOGRAM_CUSTOM_COUNTS("PasswordManager.BlacklistedSites",
214 blacklisted_sites, 0, 32, 6);
216 sql::Statement usage_statement(db_.GetCachedStatement(
217 SQL_FROM_HERE,
218 "SELECT password_type, times_used FROM logins"));
220 if (!usage_statement.is_valid())
221 return;
223 while (usage_statement.Step()) {
224 PasswordForm::Type type = static_cast<PasswordForm::Type>(
225 usage_statement.ColumnInt(0));
227 if (type == PasswordForm::TYPE_GENERATED) {
228 UMA_HISTOGRAM_CUSTOM_COUNTS(
229 "PasswordManager.TimesGeneratedPasswordUsed",
230 usage_statement.ColumnInt(1), 0, 100, 10);
231 } else {
232 UMA_HISTOGRAM_CUSTOM_COUNTS(
233 "PasswordManager.TimesPasswordUsed",
234 usage_statement.ColumnInt(1), 0, 100, 10);
239 bool LoginDatabase::AddLogin(const PasswordForm& form) {
240 std::string encrypted_password;
241 if (EncryptedString(form.password_value, &encrypted_password) !=
242 ENCRYPTION_RESULT_SUCCESS)
243 return false;
245 // You *must* change LoginTableColumns if this query changes.
246 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
247 "INSERT OR REPLACE INTO logins "
248 "(origin_url, action_url, username_element, username_value, "
249 " password_element, password_value, submit_element, "
250 " signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
251 " scheme, password_type, possible_usernames, times_used, form_data, "
252 " use_additional_auth) VALUES "
253 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
254 s.BindString(COLUMN_ORIGIN_URL, form.origin.spec());
255 s.BindString(COLUMN_ACTION_URL, form.action.spec());
256 s.BindString16(COLUMN_USERNAME_ELEMENT, form.username_element);
257 s.BindString16(COLUMN_USERNAME_VALUE, form.username_value);
258 s.BindString16(COLUMN_PASSWORD_ELEMENT, form.password_element);
259 s.BindBlob(COLUMN_PASSWORD_VALUE, encrypted_password.data(),
260 static_cast<int>(encrypted_password.length()));
261 s.BindString16(COLUMN_SUBMIT_ELEMENT, form.submit_element);
262 s.BindString(COLUMN_SIGNON_REALM, form.signon_realm);
263 s.BindInt(COLUMN_SSL_VALID, form.ssl_valid);
264 s.BindInt(COLUMN_PREFERRED, form.preferred);
265 s.BindInt64(COLUMN_DATE_CREATED, form.date_created.ToTimeT());
266 s.BindInt(COLUMN_BLACKLISTED_BY_USER, form.blacklisted_by_user);
267 s.BindInt(COLUMN_SCHEME, form.scheme);
268 s.BindInt(COLUMN_PASSWORD_TYPE, form.type);
269 Pickle usernames_pickle = SerializeVector(form.other_possible_usernames);
270 s.BindBlob(COLUMN_POSSIBLE_USERNAMES,
271 usernames_pickle.data(),
272 usernames_pickle.size());
273 s.BindInt(COLUMN_TIMES_USED, form.times_used);
274 Pickle form_data_pickle;
275 autofill::SerializeFormData(form.form_data, &form_data_pickle);
276 s.BindBlob(COLUMN_FORM_DATA,
277 form_data_pickle.data(),
278 form_data_pickle.size());
279 s.BindInt(COLUMN_USE_ADDITIONAL_AUTH, form.use_additional_authentication);
281 return s.Run();
284 bool LoginDatabase::UpdateLogin(const PasswordForm& form, int* items_changed) {
285 std::string encrypted_password;
286 if (EncryptedString(form.password_value, &encrypted_password) !=
287 ENCRYPTION_RESULT_SUCCESS)
288 return false;
290 // Replacement is necessary to deal with updating imported credentials. See
291 // crbug.com/349138 for details.
292 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
293 "UPDATE OR REPLACE logins SET "
294 "action_url = ?, "
295 "password_value = ?, "
296 "ssl_valid = ?, "
297 "preferred = ?, "
298 "possible_usernames = ?, "
299 "times_used = ?, "
300 "username_element = ?, "
301 "password_element = ?, "
302 "submit_element = ? "
303 "WHERE origin_url = ? AND "
304 "(username_element = ? OR username_element = '') AND "
305 "username_value = ? AND "
306 "(password_element = ? OR password_element = '') AND "
307 "(submit_element = ? OR submit_element = '') AND "
308 "signon_realm = ?"));
309 s.BindString(0, form.action.spec());
310 s.BindBlob(1, encrypted_password.data(),
311 static_cast<int>(encrypted_password.length()));
312 s.BindInt(2, form.ssl_valid);
313 s.BindInt(3, form.preferred);
314 Pickle pickle = SerializeVector(form.other_possible_usernames);
315 s.BindBlob(4, pickle.data(), pickle.size());
316 s.BindInt(5, form.times_used);
317 s.BindString16(6, form.username_element);
318 s.BindString16(7, form.password_element);
319 s.BindString16(8, form.submit_element);
321 s.BindString(9, form.origin.spec());
322 s.BindString16(10, form.username_element);
323 s.BindString16(11, form.username_value);
324 s.BindString16(12, form.password_element);
325 s.BindString16(13, form.submit_element);
326 s.BindString(14, form.signon_realm);
328 if (!s.Run())
329 return false;
331 if (items_changed)
332 *items_changed = db_.GetLastChangeCount();
334 return true;
337 bool LoginDatabase::RemoveLogin(const PasswordForm& form) {
338 // Remove a login by UNIQUE-constrained fields.
339 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
340 "DELETE FROM logins WHERE "
341 "origin_url = ? AND "
342 "username_element = ? AND "
343 "username_value = ? AND "
344 "password_element = ? AND "
345 "submit_element = ? AND "
346 "signon_realm = ? "));
347 s.BindString(0, form.origin.spec());
348 s.BindString16(1, form.username_element);
349 s.BindString16(2, form.username_value);
350 s.BindString16(3, form.password_element);
351 s.BindString16(4, form.submit_element);
352 s.BindString(5, form.signon_realm);
354 return s.Run();
357 bool LoginDatabase::RemoveLoginsCreatedBetween(const base::Time delete_begin,
358 const base::Time delete_end) {
359 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
360 "DELETE FROM logins WHERE "
361 "date_created >= ? AND date_created < ?"));
362 s.BindInt64(0, delete_begin.ToTimeT());
363 s.BindInt64(1, delete_end.is_null() ? std::numeric_limits<int64>::max()
364 : delete_end.ToTimeT());
366 return s.Run();
369 LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
370 PasswordForm* form,
371 sql::Statement& s) const {
372 std::string encrypted_password;
373 s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password);
374 base::string16 decrypted_password;
375 EncryptionResult encryption_result =
376 DecryptedString(encrypted_password, &decrypted_password);
377 if (encryption_result != ENCRYPTION_RESULT_SUCCESS)
378 return encryption_result;
380 std::string tmp = s.ColumnString(COLUMN_ORIGIN_URL);
381 form->origin = GURL(tmp);
382 tmp = s.ColumnString(COLUMN_ACTION_URL);
383 form->action = GURL(tmp);
384 form->username_element = s.ColumnString16(COLUMN_USERNAME_ELEMENT);
385 form->username_value = s.ColumnString16(COLUMN_USERNAME_VALUE);
386 form->password_element = s.ColumnString16(COLUMN_PASSWORD_ELEMENT);
387 form->password_value = decrypted_password;
388 form->submit_element = s.ColumnString16(COLUMN_SUBMIT_ELEMENT);
389 tmp = s.ColumnString(COLUMN_SIGNON_REALM);
390 form->signon_realm = tmp;
391 form->ssl_valid = (s.ColumnInt(COLUMN_SSL_VALID) > 0);
392 form->preferred = (s.ColumnInt(COLUMN_PREFERRED) > 0);
393 form->date_created = base::Time::FromTimeT(
394 s.ColumnInt64(COLUMN_DATE_CREATED));
395 form->blacklisted_by_user = (s.ColumnInt(COLUMN_BLACKLISTED_BY_USER) > 0);
396 int scheme_int = s.ColumnInt(COLUMN_SCHEME);
397 DCHECK((scheme_int >= 0) && (scheme_int <= PasswordForm::SCHEME_OTHER));
398 form->scheme = static_cast<PasswordForm::Scheme>(scheme_int);
399 int type_int = s.ColumnInt(COLUMN_PASSWORD_TYPE);
400 DCHECK(type_int >= 0 && type_int <= PasswordForm::TYPE_GENERATED);
401 form->type = static_cast<PasswordForm::Type>(type_int);
402 if (s.ColumnByteLength(COLUMN_POSSIBLE_USERNAMES)) {
403 Pickle pickle(
404 static_cast<const char*>(s.ColumnBlob(COLUMN_POSSIBLE_USERNAMES)),
405 s.ColumnByteLength(COLUMN_POSSIBLE_USERNAMES));
406 form->other_possible_usernames = DeserializeVector(pickle);
408 form->times_used = s.ColumnInt(COLUMN_TIMES_USED);
409 if (s.ColumnByteLength(COLUMN_FORM_DATA)) {
410 Pickle form_data_pickle(
411 static_cast<const char*>(s.ColumnBlob(COLUMN_FORM_DATA)),
412 s.ColumnByteLength(COLUMN_FORM_DATA));
413 PickleIterator form_data_iter(form_data_pickle);
414 autofill::DeserializeFormData(&form_data_iter, &form->form_data);
416 form->use_additional_authentication =
417 (s.ColumnInt(COLUMN_USE_ADDITIONAL_AUTH) > 0);
418 return ENCRYPTION_RESULT_SUCCESS;
421 bool LoginDatabase::GetLogins(const PasswordForm& form,
422 std::vector<PasswordForm*>* forms) const {
423 DCHECK(forms);
424 // You *must* change LoginTableColumns if this query changes.
425 const std::string sql_query = "SELECT origin_url, action_url, "
426 "username_element, username_value, "
427 "password_element, password_value, submit_element, "
428 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
429 "scheme, password_type, possible_usernames, times_used, form_data, "
430 "use_additional_auth FROM logins WHERE signon_realm == ? ";
431 sql::Statement s;
432 const GURL signon_realm(form.signon_realm);
433 std::string registered_domain =
434 PSLMatchingHelper::GetRegistryControlledDomain(signon_realm);
435 PSLMatchingHelper::PSLDomainMatchMetric psl_domain_match_metric =
436 PSLMatchingHelper::PSL_DOMAIN_MATCH_NONE;
437 if (psl_helper_.ShouldPSLDomainMatchingApply(registered_domain)) {
438 // We are extending the original SQL query with one that includes more
439 // possible matches based on public suffix domain matching. Using a regexp
440 // here is just an optimization to not have to parse all the stored entries
441 // in the |logins| table. The result (scheme, domain and port) is verified
442 // further down using GURL. See the functions SchemeMatches,
443 // RegistryControlledDomainMatches and PortMatches.
444 const std::string extended_sql_query =
445 sql_query + "OR signon_realm REGEXP ? ";
446 // TODO(nyquist) Re-enable usage of GetCachedStatement when
447 // http://crbug.com/248608 is fixed.
448 s.Assign(db_.GetUniqueStatement(extended_sql_query.c_str()));
449 // We need to escape . in the domain. Since the domain has already been
450 // sanitized using GURL, we do not need to escape any other characters.
451 base::ReplaceChars(registered_domain, ".", "\\.", &registered_domain);
452 std::string scheme = signon_realm.scheme();
453 // We need to escape . in the scheme. Since the scheme has already been
454 // sanitized using GURL, we do not need to escape any other characters.
455 // The scheme soap.beep is an example with '.'.
456 base::ReplaceChars(scheme, ".", "\\.", &scheme);
457 const std::string port = signon_realm.port();
458 // For a signon realm such as http://foo.bar/, this regexp will match
459 // domains on the form http://foo.bar/, http://www.foo.bar/,
460 // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/.
461 // The scheme and port has to be the same as the observed form.
462 std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" +
463 registered_domain + "(:" + port + ")?\\/$";
464 s.BindString(0, form.signon_realm);
465 s.BindString(1, regexp);
466 } else {
467 psl_domain_match_metric = PSLMatchingHelper::PSL_DOMAIN_MATCH_DISABLED;
468 s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str()));
469 s.BindString(0, form.signon_realm);
472 while (s.Step()) {
473 scoped_ptr<PasswordForm> new_form(new PasswordForm());
474 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
475 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
476 return false;
477 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
478 continue;
479 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
480 if (psl_helper_.IsMatchingEnabled()) {
481 if (!PSLMatchingHelper::IsPublicSuffixDomainMatch(new_form->signon_realm,
482 form.signon_realm)) {
483 // The database returned results that should not match. Skipping result.
484 continue;
486 if (form.signon_realm != new_form->signon_realm) {
487 psl_domain_match_metric = PSLMatchingHelper::PSL_DOMAIN_MATCH_FOUND;
488 // This is not a perfect match, so we need to create a new valid result.
489 // We do this by copying over origin, signon realm and action from the
490 // observed form and setting the original signon realm to what we found
491 // in the database. We use the fact that |original_signon_realm| is
492 // non-empty to communicate that this match was found using public
493 // suffix matching.
494 new_form->original_signon_realm = new_form->signon_realm;
495 new_form->origin = form.origin;
496 new_form->signon_realm = form.signon_realm;
497 new_form->action = form.action;
500 forms->push_back(new_form.release());
502 UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
503 psl_domain_match_metric,
504 PSLMatchingHelper::PSL_DOMAIN_MATCH_COUNT);
505 return s.Succeeded();
508 bool LoginDatabase::GetLoginsCreatedBetween(
509 const base::Time begin,
510 const base::Time end,
511 std::vector<autofill::PasswordForm*>* forms) const {
512 DCHECK(forms);
513 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
514 "SELECT origin_url, action_url, "
515 "username_element, username_value, "
516 "password_element, password_value, submit_element, "
517 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
518 "scheme, password_type, possible_usernames, times_used, form_data, "
519 "use_additional_auth FROM logins "
520 "WHERE date_created >= ? AND date_created < ?"
521 "ORDER BY origin_url"));
522 s.BindInt64(0, begin.ToTimeT());
523 s.BindInt64(1, end.is_null() ? std::numeric_limits<int64>::max()
524 : end.ToTimeT());
526 while (s.Step()) {
527 scoped_ptr<PasswordForm> new_form(new PasswordForm());
528 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
529 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
530 return false;
531 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
532 continue;
533 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
534 forms->push_back(new_form.release());
536 return s.Succeeded();
539 bool LoginDatabase::GetAutofillableLogins(
540 std::vector<PasswordForm*>* forms) const {
541 return GetAllLoginsWithBlacklistSetting(false, forms);
544 bool LoginDatabase::GetBlacklistLogins(
545 std::vector<PasswordForm*>* forms) const {
546 return GetAllLoginsWithBlacklistSetting(true, forms);
549 bool LoginDatabase::GetAllLoginsWithBlacklistSetting(
550 bool blacklisted, std::vector<PasswordForm*>* forms) const {
551 DCHECK(forms);
552 // You *must* change LoginTableColumns if this query changes.
553 sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
554 "SELECT origin_url, action_url, "
555 "username_element, username_value, "
556 "password_element, password_value, submit_element, "
557 "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
558 "scheme, password_type, possible_usernames, times_used, form_data, "
559 "use_additional_auth FROM logins WHERE blacklisted_by_user == ? "
560 "ORDER BY origin_url"));
561 s.BindInt(0, blacklisted ? 1 : 0);
563 while (s.Step()) {
564 scoped_ptr<PasswordForm> new_form(new PasswordForm());
565 EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
566 if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
567 return false;
568 if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
569 continue;
570 DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
571 forms->push_back(new_form.release());
573 return s.Succeeded();
576 bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
577 DCHECK(db_.is_open());
578 meta_table_.Reset();
579 db_.Close();
580 sql::Connection::Delete(db_path_);
581 return Init(db_path_);
584 Pickle LoginDatabase::SerializeVector(
585 const std::vector<base::string16>& vec) const {
586 Pickle p;
587 for (size_t i = 0; i < vec.size(); ++i) {
588 p.WriteString16(vec[i]);
590 return p;
593 std::vector<base::string16> LoginDatabase::DeserializeVector(
594 const Pickle& p) const {
595 std::vector<base::string16> ret;
596 base::string16 str;
598 PickleIterator iterator(p);
599 while (iterator.ReadString16(&str)) {
600 ret.push_back(str);
602 return ret;