summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorandybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-01 13:34:53 +0000
committerandybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-01 13:34:53 +0000
commit9268173603c6ee2b9292fe53017fd27a444307b6 (patch)
tree400fbb906d2a2f7f264261c2ad2873a61ffda1db /chrome
parent0414411f67979897882bbad4f7b5f218c30c1f76 (diff)
downloadchromium_src-9268173603c6ee2b9292fe53017fd27a444307b6.zip
chromium_src-9268173603c6ee2b9292fe53017fd27a444307b6.tar.gz
chromium_src-9268173603c6ee2b9292fe53017fd27a444307b6.tar.bz2
Split out the rest of the tables within WebDatabase.
Logins, WebApps and TokenService BUG=none TEST=WebDatabaseMigrationTest,LoginsTableTest,WebAppsTableTest,TokenServiceTableTest Review URL: http://codereview.chromium.org/6670122 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80150 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/webdata/autofill_table_unittest.cc72
-rw-r--r--chrome/browser/webdata/logins_table.cc296
-rw-r--r--chrome/browser/webdata/logins_table.h99
-rw-r--r--chrome/browser/webdata/logins_table_unittest.cc278
-rw-r--r--chrome/browser/webdata/logins_table_win.cc (renamed from chrome/browser/webdata/web_database_win.cc)22
-rw-r--r--chrome/browser/webdata/token_service_table.cc92
-rw-r--r--chrome/browser/webdata/token_service_table.h38
-rw-r--r--chrome/browser/webdata/token_service_table_unittest.cc100
-rw-r--r--chrome/browser/webdata/web_apps_table.cc141
-rw-r--r--chrome/browser/webdata/web_apps_table.h54
-rw-r--r--chrome/browser/webdata/web_apps_table_unittest.cc133
-rw-r--r--chrome/browser/webdata/web_data_service.cc40
-rw-r--r--chrome/browser/webdata/web_data_service_win.cc8
-rw-r--r--chrome/browser/webdata/web_database.cc541
-rw-r--r--chrome/browser/webdata/web_database.h135
-rw-r--r--chrome/browser/webdata/web_database_migration_unittest.cc (renamed from chrome/browser/webdata/web_database_unittest.cc)427
-rw-r--r--chrome/chrome_browser.gypi8
-rw-r--r--chrome/chrome_tests.gypi5
18 files changed, 1354 insertions, 1135 deletions
diff --git a/chrome/browser/webdata/autofill_table_unittest.cc b/chrome/browser/webdata/autofill_table_unittest.cc
index 22d2ad5..e3f90f6 100644
--- a/chrome/browser/webdata/autofill_table_unittest.cc
+++ b/chrome/browser/webdata/autofill_table_unittest.cc
@@ -678,7 +678,7 @@ TEST_F(AutofillTableTest, AutofillProfile) {
ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
home_profile.guid(), &db_profile));
EXPECT_EQ(home_profile, *db_profile);
- sql::Statement s_home(db.db_.GetUniqueStatement(
+ sql::Statement s_home(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified "
"FROM autofill_profiles WHERE guid=?"));
s_home.BindString(0, home_profile.guid());
@@ -704,7 +704,7 @@ TEST_F(AutofillTableTest, AutofillProfile) {
ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
billing_profile.guid(), &db_profile));
EXPECT_EQ(billing_profile, *db_profile);
- sql::Statement s_billing(db.db_.GetUniqueStatement(
+ sql::Statement s_billing(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles WHERE guid=?"));
s_billing.BindString(0, billing_profile.guid());
ASSERT_TRUE(s_billing);
@@ -723,7 +723,7 @@ TEST_F(AutofillTableTest, AutofillProfile) {
ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
billing_profile.guid(), &db_profile));
EXPECT_EQ(billing_profile, *db_profile);
- sql::Statement s_billing_updated(db.db_.GetUniqueStatement(
+ sql::Statement s_billing_updated(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles WHERE guid=?"));
s_billing_updated.BindString(0, billing_profile.guid());
ASSERT_TRUE(s_billing_updated);
@@ -756,7 +756,7 @@ TEST_F(AutofillTableTest, AutofillProfile) {
ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
billing_profile.guid(), &db_profile));
EXPECT_EQ(billing_profile, *db_profile);
- sql::Statement s_billing_updated_2(db.db_.GetUniqueStatement(
+ sql::Statement s_billing_updated_2(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles WHERE guid=?"));
s_billing_updated_2.BindString(0, billing_profile.guid());
ASSERT_TRUE(s_billing_updated_2);
@@ -1096,7 +1096,7 @@ TEST_F(AutofillTableTest, CreditCard) {
ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(work_creditcard.guid(),
&db_creditcard));
EXPECT_EQ(work_creditcard, *db_creditcard);
- sql::Statement s_work(db.db_.GetUniqueStatement(
+ sql::Statement s_work(db.GetSQLConnection()->GetUniqueStatement(
"SELECT guid, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards WHERE guid=?"));
@@ -1122,7 +1122,7 @@ TEST_F(AutofillTableTest, CreditCard) {
ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(target_creditcard.guid(),
&db_creditcard));
EXPECT_EQ(target_creditcard, *db_creditcard);
- sql::Statement s_target(db.db_.GetUniqueStatement(
+ sql::Statement s_target(db.GetSQLConnection()->GetUniqueStatement(
"SELECT guid, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards WHERE guid=?"));
@@ -1142,7 +1142,7 @@ TEST_F(AutofillTableTest, CreditCard) {
ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(target_creditcard.guid(),
&db_creditcard));
EXPECT_EQ(target_creditcard, *db_creditcard);
- sql::Statement s_target_updated(db.db_.GetUniqueStatement(
+ sql::Statement s_target_updated(db.GetSQLConnection()->GetUniqueStatement(
"SELECT guid, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, date_modified "
"FROM credit_cards WHERE guid=?"));
@@ -1184,7 +1184,7 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) {
// Set a mocked value for the profile's creation time.
const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
- sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
+ sql::Statement s_mock_creation_date(db.GetSQLConnection()->GetUniqueStatement(
"UPDATE autofill_profiles SET date_modified = ?"));
ASSERT_TRUE(s_mock_creation_date);
s_mock_creation_date.BindInt64(0, mock_creation_date);
@@ -1196,7 +1196,7 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) {
&tmp_profile));
scoped_ptr<AutofillProfile> db_profile(tmp_profile);
EXPECT_EQ(profile, *db_profile);
- sql::Statement s_original(db.db_.GetUniqueStatement(
+ sql::Statement s_original(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_original);
ASSERT_TRUE(s_original.Step());
@@ -1213,7 +1213,7 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) {
&tmp_profile));
db_profile.reset(tmp_profile);
EXPECT_EQ(profile, *db_profile);
- sql::Statement s_updated(db.db_.GetUniqueStatement(
+ sql::Statement s_updated(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_updated);
ASSERT_TRUE(s_updated.Step());
@@ -1222,8 +1222,9 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) {
// Set a mocked value for the profile's modification time.
const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
- sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
- "UPDATE autofill_profiles SET date_modified = ?"));
+ sql::Statement s_mock_modification_date(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "UPDATE autofill_profiles SET date_modified = ?"));
ASSERT_TRUE(s_mock_modification_date);
s_mock_modification_date.BindInt64(0, mock_modification_date);
ASSERT_TRUE(s_mock_modification_date.Run());
@@ -1237,7 +1238,7 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) {
&tmp_profile));
db_profile.reset(tmp_profile);
EXPECT_EQ(profile, *db_profile);
- sql::Statement s_unchanged(db.db_.GetUniqueStatement(
+ sql::Statement s_unchanged(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_unchanged);
ASSERT_TRUE(s_unchanged.Step());
@@ -1259,7 +1260,7 @@ TEST_F(AutofillTableTest, UpdateCreditCard) {
// Set a mocked value for the credit card's creation time.
const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
- sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
+ sql::Statement s_mock_creation_date(db.GetSQLConnection()->GetUniqueStatement(
"UPDATE credit_cards SET date_modified = ?"));
ASSERT_TRUE(s_mock_creation_date);
s_mock_creation_date.BindInt64(0, mock_creation_date);
@@ -1271,7 +1272,7 @@ TEST_F(AutofillTableTest, UpdateCreditCard) {
&tmp_credit_card));
scoped_ptr<CreditCard> db_credit_card(tmp_credit_card);
EXPECT_EQ(credit_card, *db_credit_card);
- sql::Statement s_original(db.db_.GetUniqueStatement(
+ sql::Statement s_original(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_original);
ASSERT_TRUE(s_original.Step());
@@ -1288,7 +1289,7 @@ TEST_F(AutofillTableTest, UpdateCreditCard) {
&tmp_credit_card));
db_credit_card.reset(tmp_credit_card);
EXPECT_EQ(credit_card, *db_credit_card);
- sql::Statement s_updated(db.db_.GetUniqueStatement(
+ sql::Statement s_updated(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_updated);
ASSERT_TRUE(s_updated.Step());
@@ -1297,8 +1298,9 @@ TEST_F(AutofillTableTest, UpdateCreditCard) {
// Set a mocked value for the credit card's modification time.
const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
- sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
- "UPDATE credit_cards SET date_modified = ?"));
+ sql::Statement s_mock_modification_date(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "UPDATE credit_cards SET date_modified = ?"));
ASSERT_TRUE(s_mock_modification_date);
s_mock_modification_date.BindInt64(0, mock_modification_date);
ASSERT_TRUE(s_mock_modification_date.Run());
@@ -1312,7 +1314,7 @@ TEST_F(AutofillTableTest, UpdateCreditCard) {
&tmp_credit_card));
db_credit_card.reset(tmp_credit_card);
EXPECT_EQ(credit_card, *db_credit_card);
- sql::Statement s_unchanged(db.db_.GetUniqueStatement(
+ sql::Statement s_unchanged(db.GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_unchanged);
ASSERT_TRUE(s_unchanged.Step());
@@ -1325,7 +1327,7 @@ TEST_F(AutofillTableTest, RemoveAutofillProfilesAndCreditCardsModifiedBetween) {
ASSERT_EQ(sql::INIT_OK, db.Init(file_));
// Populate the autofill_profiles and credit_cards tables.
- ASSERT_TRUE(db.db_.Execute(
+ ASSERT_TRUE(db.GetSQLConnection()->Execute(
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000000', 11);"
"INSERT INTO autofill_profiles (guid, date_modified) "
@@ -1354,8 +1356,9 @@ TEST_F(AutofillTableTest, RemoveAutofillProfilesAndCreditCardsModifiedBetween) {
// Remove all entries modified in the bounded time range [17,41).
db.GetAutofillTable()->RemoveAutofillProfilesAndCreditCardsModifiedBetween(
Time::FromTimeT(17), Time::FromTimeT(41));
- sql::Statement s_autofill_profiles_bounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
+ sql::Statement s_autofill_profiles_bounded(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_autofill_profiles_bounded);
ASSERT_TRUE(s_autofill_profiles_bounded.Step());
EXPECT_EQ(11, s_autofill_profiles_bounded.ColumnInt64(0));
@@ -1366,8 +1369,9 @@ TEST_F(AutofillTableTest, RemoveAutofillProfilesAndCreditCardsModifiedBetween) {
ASSERT_TRUE(s_autofill_profiles_bounded.Step());
EXPECT_EQ(61, s_autofill_profiles_bounded.ColumnInt64(0));
EXPECT_FALSE(s_autofill_profiles_bounded.Step());
- sql::Statement s_credit_cards_bounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
+ sql::Statement s_credit_cards_bounded(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_credit_cards_bounded);
ASSERT_TRUE(s_credit_cards_bounded.Step());
EXPECT_EQ(47, s_credit_cards_bounded.ColumnInt64(0));
@@ -1380,16 +1384,18 @@ TEST_F(AutofillTableTest, RemoveAutofillProfilesAndCreditCardsModifiedBetween) {
// Remove all entries modified on or after time 51 (unbounded range).
db.GetAutofillTable()->RemoveAutofillProfilesAndCreditCardsModifiedBetween(
Time::FromTimeT(51), Time());
- sql::Statement s_autofill_profiles_unbounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
+ sql::Statement s_autofill_profiles_unbounded(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_autofill_profiles_unbounded);
ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
EXPECT_EQ(11, s_autofill_profiles_unbounded.ColumnInt64(0));
ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
EXPECT_EQ(41, s_autofill_profiles_unbounded.ColumnInt64(0));
EXPECT_FALSE(s_autofill_profiles_unbounded.Step());
- sql::Statement s_credit_cards_unbounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
+ sql::Statement s_credit_cards_unbounded(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_credit_cards_unbounded);
ASSERT_TRUE(s_credit_cards_unbounded.Step());
EXPECT_EQ(47, s_credit_cards_unbounded.ColumnInt64(0));
@@ -1398,12 +1404,14 @@ TEST_F(AutofillTableTest, RemoveAutofillProfilesAndCreditCardsModifiedBetween) {
// Remove all remaining entries.
db.GetAutofillTable()->RemoveAutofillProfilesAndCreditCardsModifiedBetween(
Time(), Time());
- sql::Statement s_autofill_profiles_empty(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
+ sql::Statement s_autofill_profiles_empty(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_autofill_profiles_empty);
EXPECT_FALSE(s_autofill_profiles_empty.Step());
- sql::Statement s_credit_cards_empty(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
+ sql::Statement s_credit_cards_empty(
+ db.GetSQLConnection()->GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
ASSERT_TRUE(s_credit_cards_empty);
EXPECT_FALSE(s_credit_cards_empty.Step());
}
diff --git a/chrome/browser/webdata/logins_table.cc b/chrome/browser/webdata/logins_table.cc
new file mode 100644
index 0000000..cfa28aa
--- /dev/null
+++ b/chrome/browser/webdata/logins_table.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webdata/logins_table.h"
+
+#include <limits>
+#include <string>
+
+#include "app/sql/statement.h"
+#include "base/logging.h"
+#include "chrome/browser/password_manager/encryptor.h"
+#include "webkit/glue/password_form.h"
+
+using webkit_glue::PasswordForm;
+
+namespace {
+
+void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) {
+ std::string tmp;
+ string16 decrypted_password;
+ tmp = s->ColumnString(0);
+ form->origin = GURL(tmp);
+ tmp = s->ColumnString(1);
+ form->action = GURL(tmp);
+ form->username_element = s->ColumnString16(2);
+ form->username_value = s->ColumnString16(3);
+ form->password_element = s->ColumnString16(4);
+
+ int encrypted_password_len = s->ColumnByteLength(5);
+ std::string encrypted_password;
+ if (encrypted_password_len) {
+ encrypted_password.resize(encrypted_password_len);
+ memcpy(&encrypted_password[0], s->ColumnBlob(5), encrypted_password_len);
+ Encryptor::DecryptString16(encrypted_password, &decrypted_password);
+ }
+
+ form->password_value = decrypted_password;
+ form->submit_element = s->ColumnString16(6);
+ tmp = s->ColumnString(7);
+ form->signon_realm = tmp;
+ form->ssl_valid = (s->ColumnInt(8) > 0);
+ form->preferred = (s->ColumnInt(9) > 0);
+ form->date_created = base::Time::FromTimeT(s->ColumnInt64(10));
+ form->blacklisted_by_user = (s->ColumnInt(11) > 0);
+ int scheme_int = s->ColumnInt(12);
+ DCHECK((scheme_int >= 0) && (scheme_int <= PasswordForm::SCHEME_OTHER));
+ form->scheme = static_cast<PasswordForm::Scheme>(scheme_int);
+}
+
+} // anonymous namespace
+
+bool LoginsTable::Init() {
+ if (!db_->DoesTableExist("logins")) {
+ if (!db_->Execute("CREATE TABLE logins ("
+ "origin_url VARCHAR NOT NULL, "
+ "action_url VARCHAR, "
+ "username_element VARCHAR, "
+ "username_value VARCHAR, "
+ "password_element VARCHAR, "
+ "password_value BLOB, "
+ "submit_element VARCHAR, "
+ "signon_realm VARCHAR NOT NULL,"
+ "ssl_valid INTEGER NOT NULL,"
+ "preferred INTEGER NOT NULL,"
+ "date_created INTEGER NOT NULL,"
+ "blacklisted_by_user INTEGER NOT NULL,"
+ "scheme INTEGER NOT NULL,"
+ "UNIQUE "
+ "(origin_url, username_element, "
+ "username_value, password_element, "
+ "submit_element, signon_realm))")) {
+ NOTREACHED();
+ return false;
+ }
+ if (!db_->Execute("CREATE INDEX logins_signon ON logins (signon_realm)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+
+#if defined(OS_WIN)
+ if (!db_->DoesTableExist("ie7_logins")) {
+ if (!db_->Execute("CREATE TABLE ie7_logins ("
+ "url_hash VARCHAR NOT NULL, "
+ "password_value BLOB, "
+ "date_created INTEGER NOT NULL,"
+ "UNIQUE "
+ "(url_hash))")) {
+ NOTREACHED();
+ return false;
+ }
+ if (!db_->Execute("CREATE INDEX ie7_logins_hash ON "
+ "ie7_logins (url_hash)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+#endif
+
+ return true;
+}
+
+bool LoginsTable::IsSyncable() {
+ return true;
+}
+
+bool LoginsTable::AddLogin(const PasswordForm& form) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT OR REPLACE INTO logins "
+ "(origin_url, action_url, username_element, username_value, "
+ " password_element, password_value, submit_element, "
+ " signon_realm, ssl_valid, preferred, date_created, "
+ " blacklisted_by_user, scheme) "
+ "VALUES "
+ "(?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ std::string encrypted_password;
+ s.BindString(0, form.origin.spec());
+ s.BindString(1, form.action.spec());
+ s.BindString16(2, form.username_element);
+ s.BindString16(3, form.username_value);
+ s.BindString16(4, form.password_element);
+ Encryptor::EncryptString16(form.password_value, &encrypted_password);
+ s.BindBlob(5, encrypted_password.data(),
+ static_cast<int>(encrypted_password.length()));
+ s.BindString16(6, form.submit_element);
+ s.BindString(7, form.signon_realm);
+ s.BindInt(8, form.ssl_valid);
+ s.BindInt(9, form.preferred);
+ s.BindInt64(10, form.date_created.ToTimeT());
+ s.BindInt(11, form.blacklisted_by_user);
+ s.BindInt(12, form.scheme);
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+bool LoginsTable::UpdateLogin(const PasswordForm& form) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "UPDATE logins SET "
+ "action_url = ?, "
+ "password_value = ?, "
+ "ssl_valid = ?, "
+ "preferred = ? "
+ "WHERE origin_url = ? AND "
+ "username_element = ? AND "
+ "username_value = ? AND "
+ "password_element = ? AND "
+ "signon_realm = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString(0, form.action.spec());
+ std::string encrypted_password;
+ Encryptor::EncryptString16(form.password_value, &encrypted_password);
+ s.BindBlob(1, encrypted_password.data(),
+ static_cast<int>(encrypted_password.length()));
+ s.BindInt(2, form.ssl_valid);
+ s.BindInt(3, form.preferred);
+ s.BindString(4, form.origin.spec());
+ s.BindString16(5, form.username_element);
+ s.BindString16(6, form.username_value);
+ s.BindString16(7, form.password_element);
+ s.BindString(8, form.signon_realm);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+bool LoginsTable::RemoveLogin(const PasswordForm& form) {
+ // Remove a login by UNIQUE-constrained fields.
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM logins WHERE "
+ "origin_url = ? AND "
+ "username_element = ? AND "
+ "username_value = ? AND "
+ "password_element = ? AND "
+ "submit_element = ? AND "
+ "signon_realm = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, form.origin.spec());
+ s.BindString16(1, form.username_element);
+ s.BindString16(2, form.username_value);
+ s.BindString16(3, form.password_element);
+ s.BindString16(4, form.submit_element);
+ s.BindString(5, form.signon_realm);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+bool LoginsTable::RemoveLoginsCreatedBetween(base::Time delete_begin,
+ base::Time delete_end) {
+ sql::Statement s1(db_->GetUniqueStatement(
+ "DELETE FROM logins WHERE "
+ "date_created >= ? AND date_created < ?"));
+ if (!s1) {
+ NOTREACHED() << "Statement 1 prepare failed";
+ return false;
+ }
+ s1.BindInt64(0, delete_begin.ToTimeT());
+ s1.BindInt64(1,
+ delete_end.is_null() ?
+ std::numeric_limits<int64>::max() :
+ delete_end.ToTimeT());
+ bool success = s1.Run();
+
+#if defined(OS_WIN)
+ sql::Statement s2(db_->GetUniqueStatement(
+ "DELETE FROM ie7_logins WHERE date_created >= ? AND date_created < ?"));
+ if (!s2) {
+ NOTREACHED() << "Statement 2 prepare failed";
+ return false;
+ }
+ s2.BindInt64(0, delete_begin.ToTimeT());
+ s2.BindInt64(1,
+ delete_end.is_null() ?
+ std::numeric_limits<int64>::max() :
+ delete_end.ToTimeT());
+ success = success && s2.Run();
+#endif
+
+ return success;
+}
+
+bool LoginsTable::GetLogins(const PasswordForm& form,
+ std::vector<PasswordForm*>* forms) {
+ DCHECK(forms);
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT origin_url, action_url, "
+ "username_element, username_value, "
+ "password_element, password_value, "
+ "submit_element, signon_realm, "
+ "ssl_valid, preferred, "
+ "date_created, blacklisted_by_user, scheme FROM logins "
+ "WHERE signon_realm == ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString(0, form.signon_realm);
+
+ while (s.Step()) {
+ PasswordForm* new_form = new PasswordForm();
+ InitPasswordFormFromStatement(new_form, &s);
+
+ forms->push_back(new_form);
+ }
+ return s.Succeeded();
+}
+
+bool LoginsTable::GetAllLogins(std::vector<PasswordForm*>* forms,
+ bool include_blacklisted) {
+ DCHECK(forms);
+ std::string stmt = "SELECT origin_url, action_url, "
+ "username_element, username_value, "
+ "password_element, password_value, "
+ "submit_element, signon_realm, ssl_valid, preferred, "
+ "date_created, blacklisted_by_user, scheme FROM logins ";
+ if (!include_blacklisted)
+ stmt.append("WHERE blacklisted_by_user == 0 ");
+ stmt.append("ORDER BY origin_url");
+
+ sql::Statement s(db_->GetUniqueStatement(stmt.c_str()));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ while (s.Step()) {
+ PasswordForm* new_form = new PasswordForm();
+ InitPasswordFormFromStatement(new_form, &s);
+
+ forms->push_back(new_form);
+ }
+ return s.Succeeded();
+}
diff --git a/chrome/browser/webdata/logins_table.h b/chrome/browser/webdata/logins_table.h
new file mode 100644
index 0000000..db8cb98
--- /dev/null
+++ b/chrome/browser/webdata/logins_table.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBDATA_LOGINS_TABLE_H_
+#define CHROME_BROWSER_WEBDATA_LOGINS_TABLE_H_
+#pragma once
+
+#include <vector>
+
+#include "chrome/browser/webdata/web_database_table.h"
+
+namespace base {
+class Time;
+}
+
+namespace webkit_glue {
+struct PasswordForm;
+}
+
+#if defined(OS_WIN)
+struct IE7PasswordInfo;
+#endif
+
+// This class manages the logins table within the SQLite database passed to the
+// constructor. It expects the following schemas:
+//
+// Note: The database stores time in seconds, UTC.
+//
+// logins
+// origin_url
+// action_url
+// username_element
+// username_value
+// password_element
+// password_value
+// submit_element
+// signon_realm The authority (scheme, host, port).
+// ssl_valid SSL status of page containing the form at first
+// impression.
+// preferred MRU bit.
+// date_created This column was added after logins support. "Legacy"
+// entries have a value of 0.
+// blacklisted_by_user Tracks whether or not the user opted to 'never
+// remember'
+// passwords for this site.
+//
+class LoginsTable : public WebDatabaseTable {
+ public:
+ LoginsTable(sql::Connection* db, sql::MetaTable* meta_table)
+ : WebDatabaseTable(db, meta_table) {}
+ virtual ~LoginsTable() {}
+ virtual bool Init();
+ virtual bool IsSyncable();
+
+ // Adds |form| to the list of remembered password forms.
+ bool AddLogin(const webkit_glue::PasswordForm& form);
+
+#if defined(OS_WIN)
+ // Adds |info| to the list of imported passwords from ie7/ie8.
+ bool AddIE7Login(const IE7PasswordInfo& info);
+
+ // Removes |info| from the list of imported passwords from ie7/ie8.
+ bool RemoveIE7Login(const IE7PasswordInfo& info);
+
+ // Return the ie7/ie8 login matching |info|.
+ bool GetIE7Login(const IE7PasswordInfo& info, IE7PasswordInfo* result);
+#endif
+
+ // Updates remembered password form.
+ bool UpdateLogin(const webkit_glue::PasswordForm& form);
+
+ // Removes |form| from the list of remembered password forms.
+ bool RemoveLogin(const webkit_glue::PasswordForm& form);
+
+ // Removes all logins created from |delete_begin| onwards (inclusive) and
+ // before |delete_end|. You may use a null Time value to do an unbounded
+ // delete in either direction.
+ bool RemoveLoginsCreatedBetween(base::Time delete_begin,
+ base::Time delete_end);
+
+ // Loads a list of matching password forms into the specified vector |forms|.
+ // The list will contain all possibly relevant entries to the observed |form|,
+ // including blacklisted matches.
+ bool GetLogins(const webkit_glue::PasswordForm& form,
+ std::vector<webkit_glue::PasswordForm*>* forms);
+
+ // Loads the complete list of password forms into the specified vector |forms|
+ // if include_blacklisted is true, otherwise only loads those which are
+ // actually autofill-able; i.e haven't been blacklisted by the user selecting
+ // the 'Never for this site' button.
+ bool GetAllLogins(std::vector<webkit_glue::PasswordForm*>* forms,
+ bool include_blacklisted);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoginsTable);
+};
+
+#endif // CHROME_BROWSER_WEBDATA_LOGINS_TABLE_H_
diff --git a/chrome/browser/webdata/logins_table_unittest.cc b/chrome/browser/webdata/logins_table_unittest.cc
new file mode 100644
index 0000000..ad8aac7
--- /dev/null
+++ b/chrome/browser/webdata/logins_table_unittest.cc
@@ -0,0 +1,278 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/password_form.h"
+
+using base::Time;
+using base::TimeDelta;
+using webkit_glue::PasswordForm;
+
+class LoginsTableTest : public testing::Test {
+ public:
+ LoginsTableTest() {}
+ virtual ~LoginsTableTest() {}
+
+ protected:
+ virtual void SetUp() {
+ PathService::Get(chrome::DIR_TEST_DATA, &file_);
+ const std::string test_db = "TestWebDatabase" +
+ base::Int64ToString(Time::Now().ToTimeT()) +
+ ".db";
+ file_ = file_.AppendASCII(test_db);
+ file_util::Delete(file_, false);
+ }
+
+ virtual void TearDown() {
+ file_util::Delete(file_, false);
+ }
+
+ FilePath file_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoginsTableTest);
+};
+
+TEST_F(LoginsTableTest, Logins) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::vector<PasswordForm*> result;
+
+ // Verify the database is empty.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(0U, result.size());
+
+ // Example password form.
+ PasswordForm form;
+ form.origin = GURL("http://www.google.com/accounts/LoginAuth");
+ form.action = GURL("http://www.google.com/accounts/Login");
+ form.username_element = ASCIIToUTF16("Email");
+ form.username_value = ASCIIToUTF16("test@gmail.com");
+ form.password_element = ASCIIToUTF16("Passwd");
+ form.password_value = ASCIIToUTF16("test");
+ form.submit_element = ASCIIToUTF16("signIn");
+ form.signon_realm = "http://www.google.com/";
+ form.ssl_valid = false;
+ form.preferred = false;
+ form.scheme = PasswordForm::SCHEME_HTML;
+
+ // Add it and make sure it is there.
+ EXPECT_TRUE(db.GetLoginsTable()->AddLogin(form));
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+
+ // Match against an exact copy.
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form, &result));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+
+ // The example site changes...
+ PasswordForm form2(form);
+ form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth");
+ form2.submit_element = ASCIIToUTF16("reallySignIn");
+
+ // Match against an inexact copy
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form2, &result));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+
+ // Uh oh, the site changed origin & action URL's all at once!
+ PasswordForm form3(form2);
+ form3.action = GURL("http://www.google.com/new/accounts/Login");
+
+ // signon_realm is the same, should match.
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form3, &result));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+
+ // Imagine the site moves to a secure server for login.
+ PasswordForm form4(form3);
+ form4.signon_realm = "https://www.google.com/";
+ form4.ssl_valid = true;
+
+ // We have only an http record, so no match for this.
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form4, &result));
+ EXPECT_EQ(0U, result.size());
+
+ // Let's imagine the user logs into the secure site.
+ EXPECT_TRUE(db.GetLoginsTable()->AddLogin(form4));
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(2U, result.size());
+ delete result[0];
+ delete result[1];
+ result.clear();
+
+ // Now the match works
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form4, &result));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+
+ // The user chose to forget the original but not the new.
+ EXPECT_TRUE(db.GetLoginsTable()->RemoveLogin(form));
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+
+ // The old form wont match the new site (http vs https).
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form, &result));
+ EXPECT_EQ(0U, result.size());
+
+ // The user's request for the HTTPS site is intercepted
+ // by an attacker who presents an invalid SSL cert.
+ PasswordForm form5(form4);
+ form5.ssl_valid = 0;
+
+ // It will match in this case.
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form5, &result));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+
+ // User changes his password.
+ PasswordForm form6(form5);
+ form6.password_value = ASCIIToUTF16("test6");
+ form6.preferred = true;
+
+ // We update, and check to make sure it matches the
+ // old form, and there is only one record.
+ EXPECT_TRUE(db.GetLoginsTable()->UpdateLogin(form6));
+ // matches
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form5, &result));
+ EXPECT_EQ(1U, result.size());
+ delete result[0];
+ result.clear();
+ // Only one record.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(1U, result.size());
+ // password element was updated.
+ EXPECT_EQ(form6.password_value, result[0]->password_value);
+ // Preferred login.
+ EXPECT_TRUE(form6.preferred);
+ delete result[0];
+ result.clear();
+
+ // Make sure everything can disappear.
+ EXPECT_TRUE(db.GetLoginsTable()->RemoveLogin(form4));
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(0U, result.size());
+}
+
+static bool AddTimestampedLogin(WebDatabase* db, std::string url,
+ const std::string& unique_string,
+ const Time& time) {
+ // Example password form.
+ PasswordForm form;
+ form.origin = GURL(url + std::string("/LoginAuth"));
+ form.username_element = ASCIIToUTF16(unique_string);
+ form.username_value = ASCIIToUTF16(unique_string);
+ form.password_element = ASCIIToUTF16(unique_string);
+ form.submit_element = ASCIIToUTF16("signIn");
+ form.signon_realm = url;
+ form.date_created = time;
+ return db->GetLoginsTable()->AddLogin(form);
+}
+
+static void ClearResults(std::vector<PasswordForm*>* results) {
+ for (size_t i = 0; i < results->size(); ++i) {
+ delete (*results)[i];
+ }
+ results->clear();
+}
+
+TEST_F(LoginsTableTest, ClearPrivateData_SavedPasswords) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::vector<PasswordForm*> result;
+
+ // Verify the database is empty.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(0U, result.size());
+
+ Time now = Time::Now();
+ TimeDelta one_day = TimeDelta::FromDays(1);
+
+ // Create one with a 0 time.
+ EXPECT_TRUE(AddTimestampedLogin(&db, "1", "foo1", Time()));
+ // Create one for now and +/- 1 day.
+ EXPECT_TRUE(AddTimestampedLogin(&db, "2", "foo2", now - one_day));
+ EXPECT_TRUE(AddTimestampedLogin(&db, "3", "foo3", now));
+ EXPECT_TRUE(AddTimestampedLogin(&db, "4", "foo4", now + one_day));
+
+ // Verify inserts worked.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(4U, result.size());
+ ClearResults(&result);
+
+ // Delete everything from today's date and on.
+ db.GetLoginsTable()->RemoveLoginsCreatedBetween(now, Time());
+
+ // Should have deleted half of what we inserted.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(2U, result.size());
+ ClearResults(&result);
+
+ // Delete with 0 date (should delete all).
+ db.GetLoginsTable()->RemoveLoginsCreatedBetween(Time(), Time());
+
+ // Verify nothing is left.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(0U, result.size());
+}
+
+TEST_F(LoginsTableTest, BlacklistedLogins) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+ std::vector<PasswordForm*> result;
+
+ // Verify the database is empty.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ ASSERT_EQ(0U, result.size());
+
+ // Save a form as blacklisted.
+ PasswordForm form;
+ form.origin = GURL("http://www.google.com/accounts/LoginAuth");
+ form.action = GURL("http://www.google.com/accounts/Login");
+ form.username_element = ASCIIToUTF16("Email");
+ form.password_element = ASCIIToUTF16("Passwd");
+ form.submit_element = ASCIIToUTF16("signIn");
+ form.signon_realm = "http://www.google.com/";
+ form.ssl_valid = false;
+ form.preferred = true;
+ form.blacklisted_by_user = true;
+ form.scheme = PasswordForm::SCHEME_HTML;
+ EXPECT_TRUE(db.GetLoginsTable()->AddLogin(form));
+
+ // Get all non-blacklisted logins (should be none).
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, false));
+ ASSERT_EQ(0U, result.size());
+
+ // GetLogins should give the blacklisted result.
+ EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form, &result));
+ EXPECT_EQ(1U, result.size());
+ ClearResults(&result);
+
+ // So should GetAll including blacklisted.
+ EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
+ EXPECT_EQ(1U, result.size());
+ ClearResults(&result);
+}
diff --git a/chrome/browser/webdata/web_database_win.cc b/chrome/browser/webdata/logins_table_win.cc
index d9d3e19..3445f42 100644
--- a/chrome/browser/webdata/web_database_win.cc
+++ b/chrome/browser/webdata/logins_table_win.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/webdata/web_database.h"
+#include "chrome/browser/webdata/logins_table.h"
#include "app/sql/statement.h"
#include "base/logging.h"
@@ -10,13 +10,13 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/ie7_password.h"
-bool WebDatabase::AddIE7Login(const IE7PasswordInfo& info) {
- sql::Statement s(db_.GetUniqueStatement(
+bool LoginsTable::AddIE7Login(const IE7PasswordInfo& info) {
+ sql::Statement s(db_->GetUniqueStatement(
"INSERT OR REPLACE INTO ie7_logins "
"(url_hash, password_value, date_created) "
"VALUES (?,?,?)"));
if (!s) {
- NOTREACHED() << db_.GetErrorMessage();
+ NOTREACHED() << db_->GetErrorMessage();
return false;
}
@@ -31,12 +31,12 @@ bool WebDatabase::AddIE7Login(const IE7PasswordInfo& info) {
return true;
}
-bool WebDatabase::RemoveIE7Login(const IE7PasswordInfo& info) {
+bool LoginsTable::RemoveIE7Login(const IE7PasswordInfo& info) {
// Remove a login by UNIQUE-constrained fields.
- sql::Statement s(db_.GetUniqueStatement(
+ sql::Statement s(db_->GetUniqueStatement(
"DELETE FROM ie7_logins WHERE url_hash = ?"));
if (!s) {
- NOTREACHED() << db_.GetErrorMessage();
+ NOTREACHED() << db_->GetErrorMessage();
return false;
}
s.BindString(0, WideToUTF8(info.url_hash));
@@ -48,14 +48,14 @@ bool WebDatabase::RemoveIE7Login(const IE7PasswordInfo& info) {
return true;
}
-bool WebDatabase::GetIE7Login(const IE7PasswordInfo& info,
+bool LoginsTable::GetIE7Login(const IE7PasswordInfo& info,
IE7PasswordInfo* result) {
DCHECK(result);
- sql::Statement s(db_.GetUniqueStatement(
+ sql::Statement s(db_->GetUniqueStatement(
"SELECT password_value, date_created FROM ie7_logins "
"WHERE url_hash == ? "));
if (!s) {
- NOTREACHED() << db_.GetErrorMessage();
+ NOTREACHED() << db_->GetErrorMessage();
return false;
}
diff --git a/chrome/browser/webdata/token_service_table.cc b/chrome/browser/webdata/token_service_table.cc
new file mode 100644
index 0000000..8567112
--- /dev/null
+++ b/chrome/browser/webdata/token_service_table.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webdata/token_service_table.h"
+
+#include <map>
+#include <string>
+
+#include "app/sql/statement.h"
+#include "base/logging.h"
+#include "chrome/browser/password_manager/encryptor.h"
+
+bool TokenServiceTable::Init() {
+ if (!db_->DoesTableExist("token_service")) {
+ if (!db_->Execute("CREATE TABLE token_service ("
+ "service VARCHAR PRIMARY KEY NOT NULL,"
+ "encrypted_token BLOB)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TokenServiceTable::IsSyncable() {
+ return true;
+}
+
+bool TokenServiceTable::RemoveAllTokens() {
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM token_service"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ return s.Run();
+}
+
+bool TokenServiceTable::SetTokenForService(const std::string& service,
+ const std::string& token) {
+ // Don't bother with a cached statement since this will be a relatively
+ // infrequent operation.
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT OR REPLACE INTO token_service "
+ "(service, encrypted_token) VALUES (?, ?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ std::string encrypted_token;
+
+ bool encrypted = Encryptor::EncryptString(token, &encrypted_token);
+ if (!encrypted) {
+ return false;
+ }
+
+ s.BindString(0, service);
+ s.BindBlob(1, encrypted_token.data(),
+ static_cast<int>(encrypted_token.length()));
+ return s.Run();
+}
+
+bool TokenServiceTable::GetAllTokens(
+ std::map<std::string, std::string>* tokens) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT service, encrypted_token FROM token_service"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ while (s.Step()) {
+ std::string encrypted_token;
+ std::string decrypted_token;
+ std::string service;
+ service = s.ColumnString(0);
+ bool entry_ok = !service.empty() &&
+ s.ColumnBlobAsString(1, &encrypted_token);
+ if (entry_ok) {
+ Encryptor::DecryptString(encrypted_token, &decrypted_token);
+ (*tokens)[service] = decrypted_token;
+ } else {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
diff --git a/chrome/browser/webdata/token_service_table.h b/chrome/browser/webdata/token_service_table.h
new file mode 100644
index 0000000..db80fd6
--- /dev/null
+++ b/chrome/browser/webdata/token_service_table.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBDATA_TOKEN_SERVICE_TABLE_H_
+#define CHROME_BROWSER_WEBDATA_TOKEN_SERVICE_TABLE_H_
+#pragma once
+
+#include "chrome/browser/webdata/web_database_table.h"
+
+class TokenServiceTable : public WebDatabaseTable {
+ public:
+ TokenServiceTable(sql::Connection* db, sql::MetaTable* meta_table)
+ : WebDatabaseTable(db, meta_table) {}
+ virtual ~TokenServiceTable() {}
+ virtual bool Init();
+ virtual bool IsSyncable();
+
+ // Remove all tokens previously set with SetTokenForService.
+ bool RemoveAllTokens();
+
+ // Retrieves all tokens previously set with SetTokenForService.
+ // Returns true if there were tokens and we decrypted them,
+ // false if there was a failure somehow
+ bool GetAllTokens(std::map<std::string, std::string>* tokens);
+
+ // Store a token in the token_service table. Stored encrypted. May cause
+ // a mac keychain popup.
+ // True if we encrypted a token and stored it, false otherwise.
+ bool SetTokenForService(const std::string& service,
+ const std::string& token);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TokenServiceTable);
+};
+
+
+#endif // CHROME_BROWSER_WEBDATA_TOKEN_SERVICE_TABLE_H_
diff --git a/chrome/browser/webdata/token_service_table_unittest.cc b/chrome/browser/webdata/token_service_table_unittest.cc
new file mode 100644
index 0000000..b167822
--- /dev/null
+++ b/chrome/browser/webdata/token_service_table_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+
+class TokenServiceTableTest : public testing::Test {
+ public:
+ TokenServiceTableTest() {}
+ virtual ~TokenServiceTableTest() {}
+
+ protected:
+ virtual void SetUp() {
+ PathService::Get(chrome::DIR_TEST_DATA, &file_);
+ const std::string test_db = "TestWebDatabase" +
+ base::Int64ToString(Time::Now().ToTimeT()) +
+ ".db";
+ file_ = file_.AppendASCII(test_db);
+ file_util::Delete(file_, false);
+ }
+
+ virtual void TearDown() {
+ file_util::Delete(file_, false);
+ }
+
+ FilePath file_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TokenServiceTableTest);
+};
+
+TEST_F(TokenServiceTableTest, TokenServiceGetAllRemoveAll) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::map<std::string, std::string> out_map;
+ std::string service;
+ std::string service2;
+ service = "testservice";
+ service2 = "othertestservice";
+
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_TRUE(out_map.empty());
+
+ // Check that get all tokens works
+ EXPECT_TRUE(db.GetTokenServiceTable()->SetTokenForService(service,
+ "pepperoni"));
+ EXPECT_TRUE(db.GetTokenServiceTable()->SetTokenForService(service2, "steak"));
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "pepperoni");
+ EXPECT_EQ(out_map.find(service2)->second, "steak");
+ out_map.clear();
+
+ // Purge
+ EXPECT_TRUE(db.GetTokenServiceTable()->RemoveAllTokens());
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_TRUE(out_map.empty());
+
+ // Check that you can still add it back in
+ EXPECT_TRUE(db.GetTokenServiceTable()->SetTokenForService(service, "cheese"));
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "cheese");
+}
+
+TEST_F(TokenServiceTableTest, TokenServiceGetSet) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::map<std::string, std::string> out_map;
+ std::string service;
+ service = "testservice";
+
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_TRUE(out_map.empty());
+
+ EXPECT_TRUE(db.GetTokenServiceTable()->SetTokenForService(service,
+ "pepperoni"));
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "pepperoni");
+ out_map.clear();
+
+ // try blanking it - won't remove it from the db though!
+ EXPECT_TRUE(db.GetTokenServiceTable()->SetTokenForService(service, ""));
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "");
+ out_map.clear();
+
+ // try mutating it
+ EXPECT_TRUE(db.GetTokenServiceTable()->SetTokenForService(service, "ham"));
+ EXPECT_TRUE(db.GetTokenServiceTable()->GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "ham");
+}
diff --git a/chrome/browser/webdata/web_apps_table.cc b/chrome/browser/webdata/web_apps_table.cc
new file mode 100644
index 0000000..2b8812c
--- /dev/null
+++ b/chrome/browser/webdata/web_apps_table.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webdata/web_apps_table.h"
+
+#include "app/sql/statement.h"
+#include "base/logging.h"
+#include "chrome/browser/history/history_database.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/codec/png_codec.h"
+
+bool WebAppsTable::Init() {
+ return (InitWebAppIconsTable() && InitWebAppsTable());
+}
+
+bool WebAppsTable::IsSyncable() {
+ return true;
+}
+
+bool WebAppsTable::InitWebAppIconsTable() {
+ if (!db_->DoesTableExist("web_app_icons")) {
+ if (!db_->Execute("CREATE TABLE web_app_icons ("
+ "url LONGVARCHAR,"
+ "width int,"
+ "height int,"
+ "image BLOB, UNIQUE (url, width, height))")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool WebAppsTable::InitWebAppsTable() {
+ if (!db_->DoesTableExist("web_apps")) {
+ if (!db_->Execute("CREATE TABLE web_apps ("
+ "url LONGVARCHAR UNIQUE,"
+ "has_all_images INTEGER NOT NULL)")) {
+ NOTREACHED();
+ return false;
+ }
+ if (!db_->Execute("CREATE INDEX web_apps_url_index ON web_apps (url)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool WebAppsTable::SetWebAppImage(const GURL& url, const SkBitmap& image) {
+ // Don't bother with a cached statement since this will be a relatively
+ // infrequent operation.
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT OR REPLACE INTO web_app_icons "
+ "(url, width, height, image) VALUES (?, ?, ?, ?)"));
+ if (!s)
+ return false;
+
+ std::vector<unsigned char> image_data;
+ gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data);
+
+ s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
+ s.BindInt(1, image.width());
+ s.BindInt(2, image.height());
+ s.BindBlob(3, &image_data.front(), static_cast<int>(image_data.size()));
+ return s.Run();
+}
+
+bool WebAppsTable::GetWebAppImages(const GURL& url,
+ std::vector<SkBitmap>* images) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT image FROM web_app_icons WHERE url=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
+ while (s.Step()) {
+ SkBitmap image;
+ int col_bytes = s.ColumnByteLength(0);
+ if (col_bytes > 0) {
+ if (gfx::PNGCodec::Decode(
+ reinterpret_cast<const unsigned char*>(s.ColumnBlob(0)),
+ col_bytes, &image)) {
+ images->push_back(image);
+ } else {
+ // Should only have valid image data in the db.
+ NOTREACHED();
+ }
+ }
+ }
+ return true;
+}
+
+bool WebAppsTable::SetWebAppHasAllImages(const GURL& url,
+ bool has_all_images) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT OR REPLACE INTO web_apps (url, has_all_images) VALUES (?, ?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
+ s.BindInt(1, has_all_images ? 1 : 0);
+ return s.Run();
+}
+
+bool WebAppsTable::GetWebAppHasAllImages(const GURL& url) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT has_all_images FROM web_apps WHERE url=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
+ return (s.Step() && s.ColumnInt(0) == 1);
+}
+
+bool WebAppsTable::RemoveWebApp(const GURL& url) {
+ sql::Statement delete_s(db_->GetUniqueStatement(
+ "DELETE FROM web_app_icons WHERE url = ?"));
+ if (!delete_s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ delete_s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
+ if (!delete_s.Run())
+ return false;
+
+ sql::Statement delete_s2(db_->GetUniqueStatement(
+ "DELETE FROM web_apps WHERE url = ?"));
+ if (!delete_s2) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ delete_s2.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
+ return delete_s2.Run();
+}
+
diff --git a/chrome/browser/webdata/web_apps_table.h b/chrome/browser/webdata/web_apps_table.h
new file mode 100644
index 0000000..b39ac9c
--- /dev/null
+++ b/chrome/browser/webdata/web_apps_table.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBDATA_WEB_APPS_TABLE_H_
+#define CHROME_BROWSER_WEBDATA_WEB_APPS_TABLE_H_
+#pragma once
+
+#include <vector>
+
+#include "chrome/browser/webdata/web_database_table.h"
+
+class GURL;
+class SkBitmap;
+
+// This class manages the WebApps tables within the SQLite database passed to
+// the constructor. It expects the following schema:
+//
+// Note: The database stores time in seconds, UTC.
+//
+// web_apps
+// url URL of the web app.
+// has_all_images Do we have all the images?
+//
+// web_app_icons
+// url URL of the web app.
+// width Width of the image.
+// height Height of the image.
+// image PNG encoded image data.
+//
+class WebAppsTable : public WebDatabaseTable {
+ public:
+ WebAppsTable(sql::Connection* db, sql::MetaTable* meta_table)
+ : WebDatabaseTable(db, meta_table) {}
+ virtual ~WebAppsTable() {}
+ virtual bool Init();
+ virtual bool IsSyncable();
+
+ bool SetWebAppImage(const GURL& url, const SkBitmap& image);
+ bool GetWebAppImages(const GURL& url, std::vector<SkBitmap>* images);
+
+ bool SetWebAppHasAllImages(const GURL& url, bool has_all_images);
+ bool GetWebAppHasAllImages(const GURL& url);
+
+ bool RemoveWebApp(const GURL& url);
+
+ private:
+ bool InitWebAppIconsTable();
+ bool InitWebAppsTable();
+
+ DISALLOW_COPY_AND_ASSIGN(WebAppsTable);
+};
+
+#endif // CHROME_BROWSER_WEBDATA_WEB_APPS_TABLE_H_
diff --git a/chrome/browser/webdata/web_apps_table_unittest.cc b/chrome/browser/webdata/web_apps_table_unittest.cc
new file mode 100644
index 0000000..5cbd3e6
--- /dev/null
+++ b/chrome/browser/webdata/web_apps_table_unittest.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/chrome_paths.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+using base::Time;
+
+class WebAppsTableTest : public testing::Test {
+ public:
+ WebAppsTableTest() {}
+ virtual ~WebAppsTableTest() {}
+
+ protected:
+ virtual void SetUp() {
+ PathService::Get(chrome::DIR_TEST_DATA, &file_);
+ const std::string test_db = "TestWebDatabase" +
+ base::Int64ToString(Time::Now().ToTimeT()) +
+ ".db";
+ file_ = file_.AppendASCII(test_db);
+ file_util::Delete(file_, false);
+ }
+
+ virtual void TearDown() {
+ file_util::Delete(file_, false);
+ }
+
+ FilePath file_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebAppsTableTest);
+};
+
+
+TEST_F(WebAppsTableTest, WebAppHasAllImages) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+ GURL url("http://google.com/");
+
+ // Initial value for unknown web app should be false.
+ EXPECT_FALSE(db.GetWebAppsTable()->GetWebAppHasAllImages(url));
+
+ // Set the value and make sure it took.
+ EXPECT_TRUE(db.GetWebAppsTable()->SetWebAppHasAllImages(url, true));
+ EXPECT_TRUE(db.GetWebAppsTable()->GetWebAppHasAllImages(url));
+
+ // Remove the app and make sure value reverts to default.
+ EXPECT_TRUE(db.GetWebAppsTable()->RemoveWebApp(url));
+ EXPECT_FALSE(db.GetWebAppsTable()->GetWebAppHasAllImages(url));
+}
+
+TEST_F(WebAppsTableTest, WebAppImages) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+ GURL url("http://google.com/");
+
+ // Web app should initially have no images.
+ std::vector<SkBitmap> images;
+ ASSERT_TRUE(db.GetWebAppsTable()->GetWebAppImages(url, &images));
+ ASSERT_EQ(0U, images.size());
+
+ // Add an image.
+ SkBitmap image;
+ image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ image.allocPixels();
+ image.eraseColor(SK_ColorBLACK);
+ ASSERT_TRUE(db.GetWebAppsTable()->SetWebAppImage(url, image));
+
+ // Make sure we get the image back.
+ ASSERT_TRUE(db.GetWebAppsTable()->GetWebAppImages(url, &images));
+ ASSERT_EQ(1U, images.size());
+ ASSERT_EQ(16, images[0].width());
+ ASSERT_EQ(16, images[0].height());
+
+ // Add another 16x16 image and make sure it replaces the original.
+ image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ image.allocPixels();
+ image.eraseColor(SK_ColorBLACK);
+
+ // Set some random pixels so that we can identify the image. We don't use
+ // transparent images because of pre-multiplication rounding errors.
+ SkColor test_pixel_1 = 0xffccbbaa;
+ SkColor test_pixel_2 = 0xffaabbaa;
+ SkColor test_pixel_3 = 0xff339966;
+ image.getAddr32(0, 1)[0] = test_pixel_1;
+ image.getAddr32(0, 1)[1] = test_pixel_2;
+ image.getAddr32(0, 1)[2] = test_pixel_3;
+
+ ASSERT_TRUE(db.GetWebAppsTable()->SetWebAppImage(url, image));
+ images.clear();
+ ASSERT_TRUE(db.GetWebAppsTable()->GetWebAppImages(url, &images));
+ ASSERT_EQ(1U, images.size());
+ ASSERT_EQ(16, images[0].width());
+ ASSERT_EQ(16, images[0].height());
+ images[0].lockPixels();
+ ASSERT_TRUE(images[0].getPixels() != NULL);
+ ASSERT_EQ(test_pixel_1, images[0].getAddr32(0, 1)[0]);
+ ASSERT_EQ(test_pixel_2, images[0].getAddr32(0, 1)[1]);
+ ASSERT_EQ(test_pixel_3, images[0].getAddr32(0, 1)[2]);
+ images[0].unlockPixels();
+
+ // Add another image at a bigger size.
+ image.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
+ image.allocPixels();
+ image.eraseColor(SK_ColorBLACK);
+ ASSERT_TRUE(db.GetWebAppsTable()->SetWebAppImage(url, image));
+
+ // Make sure we get both images back.
+ images.clear();
+ ASSERT_TRUE(db.GetWebAppsTable()->GetWebAppImages(url, &images));
+ ASSERT_EQ(2U, images.size());
+ if (images[0].width() == 16) {
+ ASSERT_EQ(16, images[0].width());
+ ASSERT_EQ(16, images[0].height());
+ ASSERT_EQ(32, images[1].width());
+ ASSERT_EQ(32, images[1].height());
+ } else {
+ ASSERT_EQ(32, images[0].width());
+ ASSERT_EQ(32, images[0].height());
+ ASSERT_EQ(16, images[1].width());
+ ASSERT_EQ(16, images[1].height());
+ }
+}
diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc
index 8e4483c..122aadf 100644
--- a/chrome/browser/webdata/web_data_service.cc
+++ b/chrome/browser/webdata/web_data_service.cc
@@ -743,7 +743,8 @@ void WebDataService::SetWebAppImageImpl(
GenericRequest2<GURL, SkBitmap>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- db_->SetWebAppImage(request->GetArgument1(), request->GetArgument2());
+ db_->GetWebAppsTable()->SetWebAppImage(
+ request->GetArgument1(), request->GetArgument2());
ScheduleCommit();
}
request->RequestComplete();
@@ -753,8 +754,8 @@ void WebDataService::SetWebAppHasAllImagesImpl(
GenericRequest2<GURL, bool>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- db_->SetWebAppHasAllImages(request->GetArgument1(),
- request->GetArgument2());
+ db_->GetWebAppsTable()->SetWebAppHasAllImages(request->GetArgument1(),
+ request->GetArgument2());
ScheduleCommit();
}
request->RequestComplete();
@@ -763,7 +764,7 @@ void WebDataService::SetWebAppHasAllImagesImpl(
void WebDataService::RemoveWebAppImpl(GenericRequest<GURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- db_->RemoveWebApp(request->GetArgument());
+ db_->GetWebAppsTable()->RemoveWebApp(request->GetArgument());
ScheduleCommit();
}
request->RequestComplete();
@@ -773,8 +774,10 @@ void WebDataService::GetWebAppImagesImpl(GenericRequest<GURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
WDAppImagesResult result;
- result.has_all_images = db_->GetWebAppHasAllImages(request->GetArgument());
- db_->GetWebAppImages(request->GetArgument(), &result.images);
+ result.has_all_images =
+ db_->GetWebAppsTable()->GetWebAppHasAllImages(request->GetArgument());
+ db_->GetWebAppsTable()->GetWebAppImages(
+ request->GetArgument(), &result.images);
request->SetResult(
new WDResult<WDAppImagesResult>(WEB_APP_IMAGES, result));
}
@@ -792,7 +795,7 @@ void WebDataService::RemoveAllTokensImpl(
GenericRequest<std::string>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (db_->RemoveAllTokens()) {
+ if (db_->GetTokenServiceTable()->RemoveAllTokens()) {
ScheduleCommit();
}
}
@@ -803,8 +806,8 @@ void WebDataService::SetTokenForServiceImpl(
GenericRequest2<std::string, std::string>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (db_->SetTokenForService(request->GetArgument1(),
- request->GetArgument2())) {
+ if (db_->GetTokenServiceTable()->SetTokenForService(
+ request->GetArgument1(), request->GetArgument2())) {
ScheduleCommit();
}
}
@@ -817,7 +820,7 @@ void WebDataService::GetAllTokensImpl(
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::map<std::string, std::string> map;
- db_->GetAllTokens(&map);
+ db_->GetTokenServiceTable()->GetAllTokens(&map);
request->SetResult(
new WDResult<std::map<std::string, std::string> >(TOKEN_RESULT, map));
}
@@ -833,7 +836,7 @@ void WebDataService::GetAllTokensImpl(
void WebDataService::AddLoginImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (db_->AddLogin(request->GetArgument()))
+ if (db_->GetLoginsTable()->AddLogin(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
@@ -842,7 +845,7 @@ void WebDataService::AddLoginImpl(GenericRequest<PasswordForm>* request) {
void WebDataService::UpdateLoginImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (db_->UpdateLogin(request->GetArgument()))
+ if (db_->GetLoginsTable()->UpdateLogin(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
@@ -851,7 +854,7 @@ void WebDataService::UpdateLoginImpl(GenericRequest<PasswordForm>* request) {
void WebDataService::RemoveLoginImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (db_->RemoveLogin(request->GetArgument()))
+ if (db_->GetLoginsTable()->RemoveLogin(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
@@ -861,9 +864,10 @@ void WebDataService::RemoveLoginsCreatedBetweenImpl(
GenericRequest2<Time, Time>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (db_->RemoveLoginsCreatedBetween(request->GetArgument1(),
- request->GetArgument2()))
+ if (db_->GetLoginsTable()->RemoveLoginsCreatedBetween(
+ request->GetArgument1(), request->GetArgument2())) {
ScheduleCommit();
+ }
}
request->RequestComplete();
}
@@ -872,7 +876,7 @@ void WebDataService::GetLoginsImpl(GenericRequest<PasswordForm>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<PasswordForm*> forms;
- db_->GetLogins(request->GetArgument(), &forms);
+ db_->GetLoginsTable()->GetLogins(request->GetArgument(), &forms);
request->SetResult(
new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT, forms));
}
@@ -883,7 +887,7 @@ void WebDataService::GetAutofillableLoginsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<PasswordForm*> forms;
- db_->GetAllLogins(&forms, false);
+ db_->GetLoginsTable()->GetAllLogins(&forms, false);
request->SetResult(
new WDResult<std::vector<PasswordForm*> >(PASSWORD_RESULT, forms));
}
@@ -894,7 +898,7 @@ void WebDataService::GetBlacklistLoginsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<PasswordForm*> all_forms;
- db_->GetAllLogins(&all_forms, true);
+ db_->GetLoginsTable()->GetAllLogins(&all_forms, true);
std::vector<PasswordForm*> blacklist_forms;
for (std::vector<PasswordForm*>::iterator i = all_forms.begin();
i != all_forms.end(); ++i) {
diff --git a/chrome/browser/webdata/web_data_service_win.cc b/chrome/browser/webdata/web_data_service_win.cc
index 1c4f307..3167c82 100644
--- a/chrome/browser/webdata/web_data_service_win.cc
+++ b/chrome/browser/webdata/web_data_service_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,7 +40,7 @@ WebDataService::Handle WebDataService::GetIE7Login(
void WebDataService::AddIE7LoginImpl(GenericRequest<IE7PasswordInfo>* request) {
if (db_ && !request->IsCancelled()) {
- if (db_->AddIE7Login(request->GetArgument()))
+ if (db_->GetLoginsTable()->AddIE7Login(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
@@ -49,7 +49,7 @@ void WebDataService::AddIE7LoginImpl(GenericRequest<IE7PasswordInfo>* request) {
void WebDataService::RemoveIE7LoginImpl(
GenericRequest<IE7PasswordInfo>* request) {
if (db_ && !request->IsCancelled()) {
- if (db_->RemoveIE7Login(request->GetArgument()))
+ if (db_->GetLoginsTable()->RemoveIE7Login(request->GetArgument()))
ScheduleCommit();
}
request->RequestComplete();
@@ -59,7 +59,7 @@ void WebDataService::GetIE7LoginImpl(
GenericRequest<IE7PasswordInfo>* request) {
if (db_ && !request->IsCancelled()) {
IE7PasswordInfo result;
- db_->GetIE7Login(request->GetArgument(), &result);
+ db_->GetLoginsTable()->GetIE7Login(request->GetArgument(), &result);
request->SetResult(
new WDResult<IE7PasswordInfo>(PASSWORD_IE7_RESULT, result));
}
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index 5fa4413..c3fe4d0 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -17,60 +17,11 @@
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
-#include "chrome/browser/history/history_database.h"
-#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/webdata/autofill_util.h"
-#include "chrome/browser/webdata/keyword_table.h"
#include "chrome/common/guid.h"
#include "content/common/notification_service.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "webkit/glue/password_form.h"
-
-// Encryptor is now in place for Windows and Mac. The Linux implementation
-// currently obfuscates only. Mac Encryptor implementation can block the
-// active thread while presenting UI to the user. See |encryptor_mac.mm| for
-// details.
-// For details on the Linux work see:
-// http://crbug.com/25404
-//
-////////////////////////////////////////////////////////////////////////////////
-//
-// Schema
-// Note: The database stores time in seconds, UTC.
-//
-// logins
-// origin_url
-// action_url
-// username_element
-// username_value
-// password_element
-// password_value
-// submit_element
-// signon_realm The authority (scheme, host, port).
-// ssl_valid SSL status of page containing the form at first
-// impression.
-// preferred MRU bit.
-// date_created This column was added after logins support. "Legacy"
-// entries have a value of 0.
-// blacklisted_by_user Tracks whether or not the user opted to 'never
-// remember'
-// passwords for this site.
-//
-// web_app_icons
-// url URL of the web app.
-// width Width of the image.
-// height Height of the image.
-// image PNG encoded image data.
-//
-// web_apps
-// url URL of the web app.
-// has_all_images Do we have all the images?
-//
-////////////////////////////////////////////////////////////////////////////////
using base::Time;
-using webkit_glue::PasswordForm;
namespace {
@@ -80,38 +31,6 @@ namespace {
const int kCurrentVersionNumber = 36;
const int kCompatibleVersionNumber = 36;
-void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) {
- std::string tmp;
- string16 decrypted_password;
- tmp = s->ColumnString(0);
- form->origin = GURL(tmp);
- tmp = s->ColumnString(1);
- form->action = GURL(tmp);
- form->username_element = s->ColumnString16(2);
- form->username_value = s->ColumnString16(3);
- form->password_element = s->ColumnString16(4);
-
- int encrypted_password_len = s->ColumnByteLength(5);
- std::string encrypted_password;
- if (encrypted_password_len) {
- encrypted_password.resize(encrypted_password_len);
- memcpy(&encrypted_password[0], s->ColumnBlob(5), encrypted_password_len);
- Encryptor::DecryptString16(encrypted_password, &decrypted_password);
- }
-
- form->password_value = decrypted_password;
- form->submit_element = s->ColumnString16(6);
- tmp = s->ColumnString(7);
- form->signon_realm = tmp;
- form->ssl_valid = (s->ColumnInt(8) > 0);
- form->preferred = (s->ColumnInt(9) > 0);
- form->date_created = Time::FromTimeT(s->ColumnInt64(10));
- form->blacklisted_by_user = (s->ColumnInt(11) > 0);
- int scheme_int = s->ColumnInt(12);
- DCHECK((scheme_int >= 0) && (scheme_int <= PasswordForm::SCHEME_OTHER));
- form->scheme = static_cast<PasswordForm::Scheme>(scheme_int);
-}
-
// TODO(dhollowa): Find a common place for this. It is duplicated in
// personal_data_manager.cc.
template<typename T>
@@ -119,7 +38,7 @@ T* address_of(T& v) {
return &v;
}
-} // namespace
+} // anonymous namespace
WebDatabase::WebDatabase() {}
@@ -141,6 +60,22 @@ KeywordTable* WebDatabase::GetKeywordTable() {
return keyword_table_.get();
}
+LoginsTable* WebDatabase::GetLoginsTable() {
+ return logins_table_.get();
+}
+
+TokenServiceTable* WebDatabase::GetTokenServiceTable() {
+ return token_service_table_.get();
+}
+
+WebAppsTable* WebDatabase::GetWebAppsTable() {
+ return web_apps_table_.get();
+}
+
+sql::Connection* WebDatabase::GetSQLConnection() {
+ return &db_;
+}
+
sql::InitStatus WebDatabase::Init(const FilePath& db_name) {
// When running in unit tests, there is already a NotificationService object.
// Since only one can exist at a time per thread, check first.
@@ -182,11 +117,14 @@ sql::InitStatus WebDatabase::Init(const FilePath& db_name) {
// Create the tables.
autofill_table_.reset(new AutofillTable(&db_, &meta_table_));
keyword_table_.reset(new KeywordTable(&db_, &meta_table_));
+ logins_table_.reset(new LoginsTable(&db_, &meta_table_));
+ token_service_table_.reset(new TokenServiceTable(&db_, &meta_table_));
+ web_apps_table_.reset(new WebAppsTable(&db_, &meta_table_));
// Initialize the tables.
if (!keyword_table_->Init() || !autofill_table_->Init() ||
- !InitLoginsTable() || !InitWebAppIconsTable() || !InitWebAppsTable() ||
- !InitTokenServiceTable()) {
+ !logins_table_->Init() || !web_apps_table_->Init() ||
+ !token_service_table_->Init()) {
LOG(WARNING) << "Unable to initialize the web database.";
return sql::INIT_FAILURE;
}
@@ -201,441 +139,6 @@ sql::InitStatus WebDatabase::Init(const FilePath& db_name) {
return transaction.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
}
-bool WebDatabase::SetWebAppImage(const GURL& url, const SkBitmap& image) {
- // Don't bother with a cached statement since this will be a relatively
- // infrequent operation.
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT OR REPLACE INTO web_app_icons "
- "(url, width, height, image) VALUES (?, ?, ?, ?)"));
- if (!s)
- return false;
-
- std::vector<unsigned char> image_data;
- gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data);
-
- s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
- s.BindInt(1, image.width());
- s.BindInt(2, image.height());
- s.BindBlob(3, &image_data.front(), static_cast<int>(image_data.size()));
- return s.Run();
-}
-
-bool WebDatabase::GetWebAppImages(const GURL& url,
- std::vector<SkBitmap>* images) {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT image FROM web_app_icons WHERE url=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
- while (s.Step()) {
- SkBitmap image;
- int col_bytes = s.ColumnByteLength(0);
- if (col_bytes > 0) {
- if (gfx::PNGCodec::Decode(
- reinterpret_cast<const unsigned char*>(s.ColumnBlob(0)),
- col_bytes, &image)) {
- images->push_back(image);
- } else {
- // Should only have valid image data in the db.
- NOTREACHED();
- }
- }
- }
- return true;
-}
-
-bool WebDatabase::SetWebAppHasAllImages(const GURL& url,
- bool has_all_images) {
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT OR REPLACE INTO web_apps (url, has_all_images) VALUES (?, ?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
- s.BindInt(1, has_all_images ? 1 : 0);
- return s.Run();
-}
-
-bool WebDatabase::GetWebAppHasAllImages(const GURL& url) {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT has_all_images FROM web_apps WHERE url=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
- return (s.Step() && s.ColumnInt(0) == 1);
-}
-
-bool WebDatabase::RemoveWebApp(const GURL& url) {
- sql::Statement delete_s(db_.GetUniqueStatement(
- "DELETE FROM web_app_icons WHERE url = ?"));
- if (!delete_s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- delete_s.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
- if (!delete_s.Run())
- return false;
-
- sql::Statement delete_s2(db_.GetUniqueStatement(
- "DELETE FROM web_apps WHERE url = ?"));
- if (!delete_s2) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- delete_s2.BindString(0, history::HistoryDatabase::GURLToDatabaseURL(url));
- return delete_s2.Run();
-}
-
-bool WebDatabase::RemoveAllTokens() {
- sql::Statement s(db_.GetUniqueStatement(
- "DELETE FROM token_service"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- return s.Run();
-}
-
-bool WebDatabase::SetTokenForService(const std::string& service,
- const std::string& token) {
- // Don't bother with a cached statement since this will be a relatively
- // infrequent operation.
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT OR REPLACE INTO token_service "
- "(service, encrypted_token) VALUES (?, ?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- std::string encrypted_token;
-
- bool encrypted = Encryptor::EncryptString(token, &encrypted_token);
- if (!encrypted) {
- return false;
- }
-
- s.BindString(0, service);
- s.BindBlob(1, encrypted_token.data(),
- static_cast<int>(encrypted_token.length()));
- return s.Run();
-}
-
-bool WebDatabase::GetAllTokens(std::map<std::string, std::string>* tokens) {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT service, encrypted_token FROM token_service"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- while (s.Step()) {
- std::string encrypted_token;
- std::string decrypted_token;
- std::string service;
- service = s.ColumnString(0);
- bool entry_ok = !service.empty() &&
- s.ColumnBlobAsString(1, &encrypted_token);
- if (entry_ok) {
- Encryptor::DecryptString(encrypted_token, &decrypted_token);
- (*tokens)[service] = decrypted_token;
- } else {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitLoginsTable() {
- if (!db_.DoesTableExist("logins")) {
- if (!db_.Execute("CREATE TABLE logins ("
- "origin_url VARCHAR NOT NULL, "
- "action_url VARCHAR, "
- "username_element VARCHAR, "
- "username_value VARCHAR, "
- "password_element VARCHAR, "
- "password_value BLOB, "
- "submit_element VARCHAR, "
- "signon_realm VARCHAR NOT NULL,"
- "ssl_valid INTEGER NOT NULL,"
- "preferred INTEGER NOT NULL,"
- "date_created INTEGER NOT NULL,"
- "blacklisted_by_user INTEGER NOT NULL,"
- "scheme INTEGER NOT NULL,"
- "UNIQUE "
- "(origin_url, username_element, "
- "username_value, password_element, "
- "submit_element, signon_realm))")) {
- NOTREACHED();
- return false;
- }
- if (!db_.Execute("CREATE INDEX logins_signon ON logins (signon_realm)")) {
- NOTREACHED();
- return false;
- }
- }
-
-#if defined(OS_WIN)
- if (!db_.DoesTableExist("ie7_logins")) {
- if (!db_.Execute("CREATE TABLE ie7_logins ("
- "url_hash VARCHAR NOT NULL, "
- "password_value BLOB, "
- "date_created INTEGER NOT NULL,"
- "UNIQUE "
- "(url_hash))")) {
- NOTREACHED();
- return false;
- }
- if (!db_.Execute("CREATE INDEX ie7_logins_hash ON "
- "ie7_logins (url_hash)")) {
- NOTREACHED();
- return false;
- }
- }
-#endif
-
- return true;
-}
-
-bool WebDatabase::InitWebAppIconsTable() {
- if (!db_.DoesTableExist("web_app_icons")) {
- if (!db_.Execute("CREATE TABLE web_app_icons ("
- "url LONGVARCHAR,"
- "width int,"
- "height int,"
- "image BLOB, UNIQUE (url, width, height))")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitWebAppsTable() {
- if (!db_.DoesTableExist("web_apps")) {
- if (!db_.Execute("CREATE TABLE web_apps ("
- "url LONGVARCHAR UNIQUE,"
- "has_all_images INTEGER NOT NULL)")) {
- NOTREACHED();
- return false;
- }
- if (!db_.Execute("CREATE INDEX web_apps_url_index ON web_apps (url)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitTokenServiceTable() {
- if (!db_.DoesTableExist("token_service")) {
- if (!db_.Execute("CREATE TABLE token_service ("
- "service VARCHAR PRIMARY KEY NOT NULL,"
- "encrypted_token BLOB)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::AddLogin(const PasswordForm& form) {
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT OR REPLACE INTO logins "
- "(origin_url, action_url, username_element, username_value, "
- " password_element, password_value, submit_element, "
- " signon_realm, ssl_valid, preferred, date_created, "
- " blacklisted_by_user, scheme) "
- "VALUES "
- "(?,?,?,?,?,?,?,?,?,?,?,?,?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- std::string encrypted_password;
- s.BindString(0, form.origin.spec());
- s.BindString(1, form.action.spec());
- s.BindString16(2, form.username_element);
- s.BindString16(3, form.username_value);
- s.BindString16(4, form.password_element);
- Encryptor::EncryptString16(form.password_value, &encrypted_password);
- s.BindBlob(5, encrypted_password.data(),
- static_cast<int>(encrypted_password.length()));
- s.BindString16(6, form.submit_element);
- s.BindString(7, form.signon_realm);
- s.BindInt(8, form.ssl_valid);
- s.BindInt(9, form.preferred);
- s.BindInt64(10, form.date_created.ToTimeT());
- s.BindInt(11, form.blacklisted_by_user);
- s.BindInt(12, form.scheme);
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- return true;
-}
-
-bool WebDatabase::UpdateLogin(const PasswordForm& form) {
- sql::Statement s(db_.GetUniqueStatement(
- "UPDATE logins SET "
- "action_url = ?, "
- "password_value = ?, "
- "ssl_valid = ?, "
- "preferred = ? "
- "WHERE origin_url = ? AND "
- "username_element = ? AND "
- "username_value = ? AND "
- "password_element = ? AND "
- "signon_realm = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString(0, form.action.spec());
- std::string encrypted_password;
- Encryptor::EncryptString16(form.password_value, &encrypted_password);
- s.BindBlob(1, encrypted_password.data(),
- static_cast<int>(encrypted_password.length()));
- s.BindInt(2, form.ssl_valid);
- s.BindInt(3, form.preferred);
- s.BindString(4, form.origin.spec());
- s.BindString16(5, form.username_element);
- s.BindString16(6, form.username_value);
- s.BindString16(7, form.password_element);
- s.BindString(8, form.signon_realm);
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- return true;
-}
-
-bool WebDatabase::RemoveLogin(const PasswordForm& form) {
- // Remove a login by UNIQUE-constrained fields.
- sql::Statement s(db_.GetUniqueStatement(
- "DELETE FROM logins WHERE "
- "origin_url = ? AND "
- "username_element = ? AND "
- "username_value = ? AND "
- "password_element = ? AND "
- "submit_element = ? AND "
- "signon_realm = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, form.origin.spec());
- s.BindString16(1, form.username_element);
- s.BindString16(2, form.username_value);
- s.BindString16(3, form.password_element);
- s.BindString16(4, form.submit_element);
- s.BindString(5, form.signon_realm);
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- return true;
-}
-
-bool WebDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin,
- base::Time delete_end) {
- sql::Statement s1(db_.GetUniqueStatement(
- "DELETE FROM logins WHERE "
- "date_created >= ? AND date_created < ?"));
- if (!s1) {
- NOTREACHED() << "Statement 1 prepare failed";
- return false;
- }
- s1.BindInt64(0, delete_begin.ToTimeT());
- s1.BindInt64(1,
- delete_end.is_null() ?
- std::numeric_limits<int64>::max() :
- delete_end.ToTimeT());
- bool success = s1.Run();
-
-#if defined(OS_WIN)
- sql::Statement s2(db_.GetUniqueStatement(
- "DELETE FROM ie7_logins WHERE date_created >= ? AND date_created < ?"));
- if (!s2) {
- NOTREACHED() << "Statement 2 prepare failed";
- return false;
- }
- s2.BindInt64(0, delete_begin.ToTimeT());
- s2.BindInt64(1,
- delete_end.is_null() ?
- std::numeric_limits<int64>::max() :
- delete_end.ToTimeT());
- success = success && s2.Run();
-#endif
-
- return success;
-}
-
-bool WebDatabase::GetLogins(const PasswordForm& form,
- std::vector<PasswordForm*>* forms) {
- DCHECK(forms);
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT origin_url, action_url, "
- "username_element, username_value, "
- "password_element, password_value, "
- "submit_element, signon_realm, "
- "ssl_valid, preferred, "
- "date_created, blacklisted_by_user, scheme FROM logins "
- "WHERE signon_realm == ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString(0, form.signon_realm);
-
- while (s.Step()) {
- PasswordForm* new_form = new PasswordForm();
- InitPasswordFormFromStatement(new_form, &s);
-
- forms->push_back(new_form);
- }
- return s.Succeeded();
-}
-
-bool WebDatabase::GetAllLogins(std::vector<PasswordForm*>* forms,
- bool include_blacklisted) {
- DCHECK(forms);
- std::string stmt = "SELECT origin_url, action_url, "
- "username_element, username_value, "
- "password_element, password_value, "
- "submit_element, signon_realm, ssl_valid, preferred, "
- "date_created, blacklisted_by_user, scheme FROM logins ";
- if (!include_blacklisted)
- stmt.append("WHERE blacklisted_by_user == 0 ");
- stmt.append("ORDER BY origin_url");
-
- sql::Statement s(db_.GetUniqueStatement(stmt.c_str()));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- while (s.Step()) {
- PasswordForm* new_form = new PasswordForm();
- InitPasswordFormFromStatement(new_form, &s);
-
- forms->push_back(new_form);
- }
- return s.Succeeded();
-}
-
sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() {
// Migrate if necessary.
int current_version = meta_table_.GetVersionNumber();
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index ee69165..e743f38 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -6,44 +6,26 @@
#define CHROME_BROWSER_WEBDATA_WEB_DATABASE_H_
#pragma once
-#include <vector>
-
#include "app/sql/connection.h"
#include "app/sql/init_status.h"
#include "app/sql/meta_table.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/webdata/autofill_table.h"
#include "chrome/browser/webdata/keyword_table.h"
+#include "chrome/browser/webdata/logins_table.h"
+#include "chrome/browser/webdata/token_service_table.h"
+#include "chrome/browser/webdata/web_apps_table.h"
-class AutofillTableTest;
class FilePath;
-class GURL;
class NotificationService;
-class SkBitmap;
-
-namespace base {
-class Time;
-}
-
-namespace webkit_glue {
-struct PasswordForm;
-}
-#if defined(OS_WIN)
-struct IE7PasswordInfo;
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// A Sqlite database instance to store all the meta data we have about web pages
-//
-////////////////////////////////////////////////////////////////////////////////
+// This class manages a SQLite database that stores various web page meta data.
class WebDatabase {
public:
WebDatabase();
virtual ~WebDatabase();
- // Initialize the database given a name. The name defines where the sqlite
+ // Initialize the database given a name. The name defines where the SQLite
// file is. If this returns an error code, no other method should be called.
sql::InitStatus Init(const FilePath& db_name);
@@ -53,108 +35,14 @@ class WebDatabase {
virtual AutofillTable* GetAutofillTable();
virtual KeywordTable* GetKeywordTable();
+ virtual LoginsTable* GetLoginsTable();
+ virtual TokenServiceTable* GetTokenServiceTable();
+ virtual WebAppsTable* GetWebAppsTable();
- //////////////////////////////////////////////////////////////////////////////
- //
- // Password manager support
- //
- //////////////////////////////////////////////////////////////////////////////
-
- // Adds |form| to the list of remembered password forms.
- bool AddLogin(const webkit_glue::PasswordForm& form);
-
-#if defined(OS_WIN)
- // Adds |info| to the list of imported passwords from ie7/ie8.
- bool AddIE7Login(const IE7PasswordInfo& info);
-
- // Removes |info| from the list of imported passwords from ie7/ie8.
- bool RemoveIE7Login(const IE7PasswordInfo& info);
-
- // Return the ie7/ie8 login matching |info|.
- bool GetIE7Login(const IE7PasswordInfo& info, IE7PasswordInfo* result);
-#endif
-
- // Updates remembered password form.
- bool UpdateLogin(const webkit_glue::PasswordForm& form);
-
- // Removes |form| from the list of remembered password forms.
- bool RemoveLogin(const webkit_glue::PasswordForm& form);
-
- // Removes all logins created from |delete_begin| onwards (inclusive) and
- // before |delete_end|. You may use a null Time value to do an unbounded
- // delete in either direction.
- bool RemoveLoginsCreatedBetween(base::Time delete_begin,
- base::Time delete_end);
-
- // Loads a list of matching password forms into the specified vector |forms|.
- // The list will contain all possibly relevant entries to the observed |form|,
- // including blacklisted matches.
- bool GetLogins(const webkit_glue::PasswordForm& form,
- std::vector<webkit_glue::PasswordForm*>* forms);
-
- // Loads the complete list of password forms into the specified vector |forms|
- // if include_blacklisted is true, otherwise only loads those which are
- // actually autofill-able; i.e haven't been blacklisted by the user selecting
- // the 'Never for this site' button.
- bool GetAllLogins(std::vector<webkit_glue::PasswordForm*>* forms,
- bool include_blacklisted);
-
- //////////////////////////////////////////////////////////////////////////////
- //
- // Web Apps
- //
- //////////////////////////////////////////////////////////////////////////////
-
- bool SetWebAppImage(const GURL& url, const SkBitmap& image);
- bool GetWebAppImages(const GURL& url, std::vector<SkBitmap>* images);
-
- bool SetWebAppHasAllImages(const GURL& url, bool has_all_images);
- bool GetWebAppHasAllImages(const GURL& url);
-
- bool RemoveWebApp(const GURL& url);
-
- //////////////////////////////////////////////////////////////////////////////
- //
- // Token Service
- //
- //////////////////////////////////////////////////////////////////////////////
-
- // Remove all tokens previously set with SetTokenForService.
- bool RemoveAllTokens();
-
- // Retrieves all tokens previously set with SetTokenForService.
- // Returns true if there were tokens and we decrypted them,
- // false if there was a failure somehow
- bool GetAllTokens(std::map<std::string, std::string>* tokens);
-
- // Store a token in the token_service table. Stored encrypted. May cause
- // a mac keychain popup.
- // True if we encrypted a token and stored it, false otherwise.
- bool SetTokenForService(const std::string& service,
- const std::string& token);
+ // Exposed for testing only.
+ sql::Connection* GetSQLConnection();
private:
- // TODO(andybons): Remove this in the next refactor round.
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_AddChanges);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_RemoveBetweenChanges);
-
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_UpdateDontReplace);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_AddFormFieldValues);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfile);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateAutofillProfile);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfileTrash);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfileTrashInteraction);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest,
- RemoveAutofillProfilesAndCreditCardsModifiedBetween);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, CreditCard);
- FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateCreditCard);
-
- bool InitLoginsTable();
- bool InitTokenServiceTable();
- bool InitWebAppIconsTable();
- bool InitWebAppsTable();
-
// Used by |Init()| to migration database schema from older versions to
// current version.
sql::InitStatus MigrateOldVersionsAsNeeded();
@@ -164,6 +52,9 @@ class WebDatabase {
scoped_ptr<AutofillTable> autofill_table_;
scoped_ptr<KeywordTable> keyword_table_;
+ scoped_ptr<LoginsTable> logins_table_;
+ scoped_ptr<TokenServiceTable> token_service_table_;
+ scoped_ptr<WebAppsTable> web_apps_table_;
scoped_ptr<NotificationService> notification_service_;
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_migration_unittest.cc
index 9939284..0d2a365 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_migration_unittest.cc
@@ -2,17 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <list>
-#include <map>
-#include <set>
#include <string>
-#include <utility>
-#include <vector>
#include "app/sql/statement.h"
#include "base/file_util.h"
#include "base/memory/scoped_temp_dir.h"
-#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
@@ -22,7 +16,6 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/credit_card.h"
-#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
@@ -30,12 +23,8 @@
#include "chrome/common/guid.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/glue/password_form.h"
using base::Time;
-using base::TimeDelta;
-using webkit_glue::PasswordForm;
namespace {
@@ -160,422 +149,6 @@ void CreditCard32FromStatement(const sql::Statement& s,
} // anonymous namespace
-class WebDatabaseTest : public testing::Test {
- public:
- WebDatabaseTest() {}
- virtual ~WebDatabaseTest() {}
-
- protected:
- virtual void SetUp() {
-#if defined(OS_MACOSX)
- Encryptor::UseMockKeychain(true);
-#endif
- PathService::Get(chrome::DIR_TEST_DATA, &file_);
- const std::string test_db = "TestWebDatabase" +
- base::Int64ToString(Time::Now().ToTimeT()) +
- ".db";
- file_ = file_.AppendASCII(test_db);
- file_util::Delete(file_, false);
- }
-
- virtual void TearDown() {
- file_util::Delete(file_, false);
- }
-
- FilePath file_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WebDatabaseTest);
-};
-
-TEST_F(WebDatabaseTest, Logins) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- std::vector<PasswordForm*> result;
-
- // Verify the database is empty.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(0U, result.size());
-
- // Example password form.
- PasswordForm form;
- form.origin = GURL("http://www.google.com/accounts/LoginAuth");
- form.action = GURL("http://www.google.com/accounts/Login");
- form.username_element = ASCIIToUTF16("Email");
- form.username_value = ASCIIToUTF16("test@gmail.com");
- form.password_element = ASCIIToUTF16("Passwd");
- form.password_value = ASCIIToUTF16("test");
- form.submit_element = ASCIIToUTF16("signIn");
- form.signon_realm = "http://www.google.com/";
- form.ssl_valid = false;
- form.preferred = false;
- form.scheme = PasswordForm::SCHEME_HTML;
-
- // Add it and make sure it is there.
- EXPECT_TRUE(db.AddLogin(form));
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
-
- // Match against an exact copy.
- EXPECT_TRUE(db.GetLogins(form, &result));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
-
- // The example site changes...
- PasswordForm form2(form);
- form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth");
- form2.submit_element = ASCIIToUTF16("reallySignIn");
-
- // Match against an inexact copy
- EXPECT_TRUE(db.GetLogins(form2, &result));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
-
- // Uh oh, the site changed origin & action URL's all at once!
- PasswordForm form3(form2);
- form3.action = GURL("http://www.google.com/new/accounts/Login");
-
- // signon_realm is the same, should match.
- EXPECT_TRUE(db.GetLogins(form3, &result));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
-
- // Imagine the site moves to a secure server for login.
- PasswordForm form4(form3);
- form4.signon_realm = "https://www.google.com/";
- form4.ssl_valid = true;
-
- // We have only an http record, so no match for this.
- EXPECT_TRUE(db.GetLogins(form4, &result));
- EXPECT_EQ(0U, result.size());
-
- // Let's imagine the user logs into the secure site.
- EXPECT_TRUE(db.AddLogin(form4));
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(2U, result.size());
- delete result[0];
- delete result[1];
- result.clear();
-
- // Now the match works
- EXPECT_TRUE(db.GetLogins(form4, &result));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
-
- // The user chose to forget the original but not the new.
- EXPECT_TRUE(db.RemoveLogin(form));
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
-
- // The old form wont match the new site (http vs https).
- EXPECT_TRUE(db.GetLogins(form, &result));
- EXPECT_EQ(0U, result.size());
-
- // The user's request for the HTTPS site is intercepted
- // by an attacker who presents an invalid SSL cert.
- PasswordForm form5(form4);
- form5.ssl_valid = 0;
-
- // It will match in this case.
- EXPECT_TRUE(db.GetLogins(form5, &result));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
-
- // User changes his password.
- PasswordForm form6(form5);
- form6.password_value = ASCIIToUTF16("test6");
- form6.preferred = true;
-
- // We update, and check to make sure it matches the
- // old form, and there is only one record.
- EXPECT_TRUE(db.UpdateLogin(form6));
- // matches
- EXPECT_TRUE(db.GetLogins(form5, &result));
- EXPECT_EQ(1U, result.size());
- delete result[0];
- result.clear();
- // Only one record.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(1U, result.size());
- // password element was updated.
- EXPECT_EQ(form6.password_value, result[0]->password_value);
- // Preferred login.
- EXPECT_TRUE(form6.preferred);
- delete result[0];
- result.clear();
-
- // Make sure everything can disappear.
- EXPECT_TRUE(db.RemoveLogin(form4));
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(0U, result.size());
-}
-
-static bool AddTimestampedLogin(WebDatabase* db, std::string url,
- const std::string& unique_string,
- const Time& time) {
- // Example password form.
- PasswordForm form;
- form.origin = GURL(url + std::string("/LoginAuth"));
- form.username_element = ASCIIToUTF16(unique_string);
- form.username_value = ASCIIToUTF16(unique_string);
- form.password_element = ASCIIToUTF16(unique_string);
- form.submit_element = ASCIIToUTF16("signIn");
- form.signon_realm = url;
- form.date_created = time;
- return db->AddLogin(form);
-}
-
-static void ClearResults(std::vector<PasswordForm*>* results) {
- for (size_t i = 0; i < results->size(); ++i) {
- delete (*results)[i];
- }
- results->clear();
-}
-
-TEST_F(WebDatabaseTest, ClearPrivateData_SavedPasswords) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- std::vector<PasswordForm*> result;
-
- // Verify the database is empty.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(0U, result.size());
-
- Time now = Time::Now();
- TimeDelta one_day = TimeDelta::FromDays(1);
-
- // Create one with a 0 time.
- EXPECT_TRUE(AddTimestampedLogin(&db, "1", "foo1", Time()));
- // Create one for now and +/- 1 day.
- EXPECT_TRUE(AddTimestampedLogin(&db, "2", "foo2", now - one_day));
- EXPECT_TRUE(AddTimestampedLogin(&db, "3", "foo3", now));
- EXPECT_TRUE(AddTimestampedLogin(&db, "4", "foo4", now + one_day));
-
- // Verify inserts worked.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(4U, result.size());
- ClearResults(&result);
-
- // Delete everything from today's date and on.
- db.RemoveLoginsCreatedBetween(now, Time());
-
- // Should have deleted half of what we inserted.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(2U, result.size());
- ClearResults(&result);
-
- // Delete with 0 date (should delete all).
- db.RemoveLoginsCreatedBetween(Time(), Time());
-
- // Verify nothing is left.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(0U, result.size());
-}
-
-TEST_F(WebDatabaseTest, BlacklistedLogins) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
- std::vector<PasswordForm*> result;
-
- // Verify the database is empty.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- ASSERT_EQ(0U, result.size());
-
- // Save a form as blacklisted.
- PasswordForm form;
- form.origin = GURL("http://www.google.com/accounts/LoginAuth");
- form.action = GURL("http://www.google.com/accounts/Login");
- form.username_element = ASCIIToUTF16("Email");
- form.password_element = ASCIIToUTF16("Passwd");
- form.submit_element = ASCIIToUTF16("signIn");
- form.signon_realm = "http://www.google.com/";
- form.ssl_valid = false;
- form.preferred = true;
- form.blacklisted_by_user = true;
- form.scheme = PasswordForm::SCHEME_HTML;
- EXPECT_TRUE(db.AddLogin(form));
-
- // Get all non-blacklisted logins (should be none).
- EXPECT_TRUE(db.GetAllLogins(&result, false));
- ASSERT_EQ(0U, result.size());
-
- // GetLogins should give the blacklisted result.
- EXPECT_TRUE(db.GetLogins(form, &result));
- EXPECT_EQ(1U, result.size());
- ClearResults(&result);
-
- // So should GetAll including blacklisted.
- EXPECT_TRUE(db.GetAllLogins(&result, true));
- EXPECT_EQ(1U, result.size());
- ClearResults(&result);
-}
-
-TEST_F(WebDatabaseTest, WebAppHasAllImages) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
- GURL url("http://google.com/");
-
- // Initial value for unknown web app should be false.
- EXPECT_FALSE(db.GetWebAppHasAllImages(url));
-
- // Set the value and make sure it took.
- EXPECT_TRUE(db.SetWebAppHasAllImages(url, true));
- EXPECT_TRUE(db.GetWebAppHasAllImages(url));
-
- // Remove the app and make sure value reverts to default.
- EXPECT_TRUE(db.RemoveWebApp(url));
- EXPECT_FALSE(db.GetWebAppHasAllImages(url));
-}
-
-TEST_F(WebDatabaseTest, WebAppImages) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
- GURL url("http://google.com/");
-
- // Web app should initially have no images.
- std::vector<SkBitmap> images;
- ASSERT_TRUE(db.GetWebAppImages(url, &images));
- ASSERT_EQ(0U, images.size());
-
- // Add an image.
- SkBitmap image;
- image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
- image.allocPixels();
- image.eraseColor(SK_ColorBLACK);
- ASSERT_TRUE(db.SetWebAppImage(url, image));
-
- // Make sure we get the image back.
- ASSERT_TRUE(db.GetWebAppImages(url, &images));
- ASSERT_EQ(1U, images.size());
- ASSERT_EQ(16, images[0].width());
- ASSERT_EQ(16, images[0].height());
-
- // Add another 16x16 image and make sure it replaces the original.
- image.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
- image.allocPixels();
- image.eraseColor(SK_ColorBLACK);
-
- // Set some random pixels so that we can identify the image. We don't use
- // transparent images because of pre-multiplication rounding errors.
- SkColor test_pixel_1 = 0xffccbbaa;
- SkColor test_pixel_2 = 0xffaabbaa;
- SkColor test_pixel_3 = 0xff339966;
- image.getAddr32(0, 1)[0] = test_pixel_1;
- image.getAddr32(0, 1)[1] = test_pixel_2;
- image.getAddr32(0, 1)[2] = test_pixel_3;
-
- ASSERT_TRUE(db.SetWebAppImage(url, image));
- images.clear();
- ASSERT_TRUE(db.GetWebAppImages(url, &images));
- ASSERT_EQ(1U, images.size());
- ASSERT_EQ(16, images[0].width());
- ASSERT_EQ(16, images[0].height());
- images[0].lockPixels();
- ASSERT_TRUE(images[0].getPixels() != NULL);
- ASSERT_EQ(test_pixel_1, images[0].getAddr32(0, 1)[0]);
- ASSERT_EQ(test_pixel_2, images[0].getAddr32(0, 1)[1]);
- ASSERT_EQ(test_pixel_3, images[0].getAddr32(0, 1)[2]);
- images[0].unlockPixels();
-
- // Add another image at a bigger size.
- image.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
- image.allocPixels();
- image.eraseColor(SK_ColorBLACK);
- ASSERT_TRUE(db.SetWebAppImage(url, image));
-
- // Make sure we get both images back.
- images.clear();
- ASSERT_TRUE(db.GetWebAppImages(url, &images));
- ASSERT_EQ(2U, images.size());
- if (images[0].width() == 16) {
- ASSERT_EQ(16, images[0].width());
- ASSERT_EQ(16, images[0].height());
- ASSERT_EQ(32, images[1].width());
- ASSERT_EQ(32, images[1].height());
- } else {
- ASSERT_EQ(32, images[0].width());
- ASSERT_EQ(32, images[0].height());
- ASSERT_EQ(16, images[1].width());
- ASSERT_EQ(16, images[1].height());
- }
-}
-
-TEST_F(WebDatabaseTest, TokenServiceGetAllRemoveAll) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- std::map<std::string, std::string> out_map;
- std::string service;
- std::string service2;
- service = "testservice";
- service2 = "othertestservice";
-
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_TRUE(out_map.empty());
-
- // Check that get all tokens works
- EXPECT_TRUE(db.SetTokenForService(service, "pepperoni"));
- EXPECT_TRUE(db.SetTokenForService(service2, "steak"));
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_EQ(out_map.find(service)->second, "pepperoni");
- EXPECT_EQ(out_map.find(service2)->second, "steak");
- out_map.clear();
-
- // Purge
- EXPECT_TRUE(db.RemoveAllTokens());
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_TRUE(out_map.empty());
-
- // Check that you can still add it back in
- EXPECT_TRUE(db.SetTokenForService(service, "cheese"));
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_EQ(out_map.find(service)->second, "cheese");
-}
-
-TEST_F(WebDatabaseTest, TokenServiceGetSet) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- std::map<std::string, std::string> out_map;
- std::string service;
- service = "testservice";
-
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_TRUE(out_map.empty());
-
- EXPECT_TRUE(db.SetTokenForService(service, "pepperoni"));
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_EQ(out_map.find(service)->second, "pepperoni");
- out_map.clear();
-
- // try blanking it - won't remove it from the db though!
- EXPECT_TRUE(db.SetTokenForService(service, ""));
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_EQ(out_map.find(service)->second, "");
- out_map.clear();
-
- // try mutating it
- EXPECT_TRUE(db.SetTokenForService(service, "ham"));
- EXPECT_TRUE(db.GetAllTokens(&out_map));
- EXPECT_EQ(out_map.find(service)->second, "ham");
-}
-
// The WebDatabaseMigrationTest encapsulates testing of database migrations.
// Specifically, these tests are intended to exercise any schema changes in
// the WebDatabase and data migrations that occur in
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 73b3708..3d5a560 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3314,12 +3314,18 @@
'browser/webdata/autofill_util.h',
'browser/webdata/keyword_table.cc',
'browser/webdata/keyword_table.h',
+ 'browser/webdata/logins_table.cc',
+ 'browser/webdata/logins_table.h',
+ 'browser/webdata/logins_table_win.cc',
+ 'browser/webdata/token_service_table.cc',
+ 'browser/webdata/token_service_table.h',
+ 'browser/webdata/web_apps_table.cc',
+ 'browser/webdata/web_apps_table.h',
'browser/webdata/web_data_service.cc',
'browser/webdata/web_data_service.h',
'browser/webdata/web_data_service_win.cc',
'browser/webdata/web_database.cc',
'browser/webdata/web_database.h',
- 'browser/webdata/web_database_win.cc',
'browser/webdata/web_database_table.h',
# These files are generated by GRIT.
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index fd7c836..aa4ef48 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1755,9 +1755,12 @@
'browser/web_applications/web_app_unittest.cc',
'browser/webdata/autofill_table_unittest.cc',
'browser/webdata/keyword_table_unittest.cc',
+ 'browser/webdata/logins_table_unittest.cc',
+ 'browser/webdata/token_service_table_unittest.cc',
+ 'browser/webdata/web_apps_table_unittest.cc',
'browser/webdata/web_data_service_test_util.h',
'browser/webdata/web_data_service_unittest.cc',
- 'browser/webdata/web_database_unittest.cc',
+ 'browser/webdata/web_database_migration_unittest.cc',
'browser/web_resource/promo_resource_service_unittest.cc',
'common/bzip2_unittest.cc',
'common/child_process_logging_mac_unittest.mm',