diff options
Diffstat (limited to 'components')
18 files changed, 445 insertions, 4 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 05383f1..9c3ea50 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -346,6 +346,7 @@ 'password_manager/core/browser/password_store_unittest.cc', 'password_manager/core/browser/password_syncable_service_unittest.cc', 'password_manager/core/browser/psl_matching_helper_unittest.cc', + 'password_manager/core/browser/statistics_table_unittest.cc', 'password_manager/core/common/credential_manager_types_unittest.cc', ], 'policy_unittest_sources': [ diff --git a/components/password_manager.gypi b/components/password_manager.gypi index b560a66..62792ef 100644 --- a/components/password_manager.gypi +++ b/components/password_manager.gypi @@ -90,6 +90,8 @@ 'password_manager/core/browser/password_syncable_service.h', 'password_manager/core/browser/psl_matching_helper.cc', 'password_manager/core/browser/psl_matching_helper.h', + 'password_manager/core/browser/statistics_table.cc', + 'password_manager/core/browser/statistics_table.h', 'password_manager/core/browser/test_affiliation_fetcher_factory.h', 'password_manager/core/browser/webdata/logins_table.cc', 'password_manager/core/browser/webdata/logins_table.h', diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index 9880bd3..f46488d 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn @@ -72,6 +72,8 @@ static_library("browser") { "password_syncable_service.h", "psl_matching_helper.cc", "psl_matching_helper.h", + "statistics_table.cc", + "statistics_table.h", "test_affiliation_fetcher_factory.h", "webdata/logins_table.cc", "webdata/logins_table.h", diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index f59f8c6..91c71d0 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc @@ -29,7 +29,7 @@ using autofill::PasswordForm; namespace password_manager { -const int kCurrentVersionNumber = 12; +const int kCurrentVersionNumber = 13; static const int kCompatibleVersionNumber = 1; Pickle SerializeVector(const std::vector<base::string16>& vec) { @@ -233,7 +233,13 @@ bool LoginDatabase::Init() { // Initialize the tables. if (!InitLoginsTable()) { - LOG(WARNING) << "Unable to initialize the password store database."; + LOG(WARNING) << "Unable to initialize the logins table."; + db_.Close(); + return false; + } + + if (!stats_table_.Init(&db_)) { + LOG(WARNING) << "Unable to initialize the stats table."; db_.Close(); return false; } @@ -374,6 +380,9 @@ bool LoginDatabase::MigrateOldVersionsAsNeeded() { "generation_upload_status INTEGER")) return false; meta_table_.SetVersionNumber(12); + case 12: + // The stats table was added. Nothing to do really. + meta_table_.SetVersionNumber(13); case kCurrentVersionNumber: // Already up to date return true; diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index 008afa3..ca3db84 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h @@ -16,6 +16,7 @@ #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store_change.h" #include "components/password_manager/core/browser/psl_matching_helper.h" +#include "components/password_manager/core/browser/statistics_table.h" #include "sql/connection.h" #include "sql/meta_table.h" @@ -108,6 +109,8 @@ class LoginDatabase { // whether further use of this login database will succeed is unspecified. bool DeleteAndRecreateDatabaseFile(); + StatisticsTable& stats_table() { return stats_table_; } + private: // Result values for encryption/decryption actions. enum EncryptionResult { @@ -165,6 +168,7 @@ class LoginDatabase { base::FilePath db_path_; mutable sql::Connection db_; sql::MetaTable meta_table_; + StatisticsTable stats_table_; DISALLOW_COPY_AND_ASSIGN(LoginDatabase); }; diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h index 70f54e9..7b76b91 100644 --- a/components/password_manager/core/browser/mock_password_store.h +++ b/components/password_manager/core/browser/mock_password_store.h @@ -47,6 +47,12 @@ class MockPasswordStore : public PasswordStore { MOCK_METHOD1(FillBlacklistLogins, bool(ScopedVector<autofill::PasswordForm>*)); MOCK_METHOD1(NotifyLoginsChanged, void(const PasswordStoreChangeList&)); + void AddSiteStatsImpl(const InteractionsStats& stats) override {} + void RemoveSiteStatsImpl(const GURL& origin_domain) override {} + scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) override { + return scoped_ptr<InteractionsStats>(); + } PasswordStoreSync* GetSyncInterface() { return this; } diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index 5b13a3c..4a35791 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc @@ -59,6 +59,13 @@ void PasswordStore::GetLoginsRequest::NotifyConsumerWithResults( consumer_weak_, base::Passed(&results))); } +void PasswordStore::GetLoginsRequest::NotifyWithSiteStatistics( + scoped_ptr<InteractionsStats> stats) { + origin_loop_->PostTask(FROM_HERE, + base::Bind(&PasswordStoreConsumer::OnGetSiteStatistics, + consumer_weak_, base::Passed(&stats))); +} + PasswordStore::PasswordStore( scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner) @@ -163,6 +170,22 @@ void PasswordStore::ReportMetrics(const std::string& sync_username, } } +void PasswordStore::AddSiteStats(const InteractionsStats& stats) { + ScheduleTask(base::Bind(&PasswordStore::AddSiteStatsImpl, this, stats)); +} + +void PasswordStore::RemoveSiteStats(const GURL& origin_domain) { + ScheduleTask( + base::Bind(&PasswordStore::RemoveSiteStatsImpl, this, origin_domain)); +} + +void PasswordStore::GetSiteStats(const GURL& origin_domain, + PasswordStoreConsumer* consumer) { + scoped_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer)); + ScheduleTask(base::Bind(&PasswordStore::NotifySiteStats, this, origin_domain, + base::Passed(&request))); +} + void PasswordStore::AddObserver(Observer* observer) { observers_->AddObserver(observer); } @@ -302,6 +325,11 @@ void PasswordStore::RemoveLoginsSyncedBetweenInternal(base::Time delete_begin, NotifyLoginsChanged(changes); } +void PasswordStore::NotifySiteStats(const GURL& origin_domain, + scoped_ptr<GetLoginsRequest> request) { + request->NotifyWithSiteStatistics(GetSiteStatsImpl(origin_domain)); +} + void PasswordStore::GetLoginsWithAffiliationsImpl( const PasswordForm& form, AuthorizationPromptPolicy prompt_policy, diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index 74ff469..c1194cf 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h @@ -15,6 +15,7 @@ #include "base/time/time.h" #include "components/password_manager/core/browser/password_store_change.h" #include "components/password_manager/core/browser/password_store_sync.h" +#include "components/password_manager/core/browser/statistics_table.h" #include "sync/api/syncable_service.h" namespace autofill { @@ -128,6 +129,16 @@ class PasswordStore : protected PasswordStoreSync, virtual void ReportMetrics(const std::string& sync_username, bool custom_passphrase_sync_enabled); + // Adds or replaces the statistics for the domain |stats.origin_domain|. + void AddSiteStats(const InteractionsStats& stats); + + // Removes the statistics for |origin_domain|. + void RemoveSiteStats(const GURL& origin_domain); + + // Retrieves the statistics for |origin_domain| and notifies |consumer| on + // completion. The request will be cancelled if the consumer is destroyed. + void GetSiteStats(const GURL& origin_domain, PasswordStoreConsumer* consumer); + // Adds an observer to be notified when the password store data changes. void AddObserver(Observer* observer); @@ -162,6 +173,8 @@ class PasswordStore : protected PasswordStoreSync, void NotifyConsumerWithResults( ScopedVector<autofill::PasswordForm> results); + void NotifyWithSiteStatistics(scoped_ptr<InteractionsStats> stats); + void set_ignore_logins_cutoff(base::Time cutoff) { ignore_logins_cutoff_ = cutoff; } @@ -235,6 +248,13 @@ class PasswordStore : protected PasswordStoreSync, // Finds all blacklist PasswordForms, and notifies the consumer. virtual void GetBlacklistLoginsImpl(scoped_ptr<GetLoginsRequest> request) = 0; + // Synchronous implementation for manipulating with statistics. + virtual void AddSiteStatsImpl(const InteractionsStats& stats) = 0; + virtual void RemoveSiteStatsImpl(const GURL& origin_domain) = 0; + // Returns a raw pointer so that InteractionsStats can be forward declared. + virtual scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) WARN_UNUSED_RESULT = 0; + // Log UMA stats for number of bulk deletions. void LogStatsForBulkDeletion(int num_deletions); @@ -288,6 +308,10 @@ class PasswordStore : protected PasswordStoreSync, void RemoveLoginsSyncedBetweenInternal(base::Time delete_begin, base::Time delete_end); + // Notifies |request| about the stats for |origin_domain|. + void NotifySiteStats(const GURL& origin_domain, + scoped_ptr<GetLoginsRequest> request); + // Extended version of GetLoginsImpl that also returns credentials stored for // the specified affiliated Android applications. That is, it finds all // PasswordForms with a signon_realm that is either: diff --git a/components/password_manager/core/browser/password_store_consumer.cc b/components/password_manager/core/browser/password_store_consumer.cc index da62aed..8347f2b 100644 --- a/components/password_manager/core/browser/password_store_consumer.cc +++ b/components/password_manager/core/browser/password_store_consumer.cc @@ -4,6 +4,8 @@ #include "components/password_manager/core/browser/password_store_consumer.h" +#include "components/password_manager/core/browser/statistics_table.h" + namespace password_manager { PasswordStoreConsumer::PasswordStoreConsumer() : weak_ptr_factory_(this) { @@ -12,4 +14,8 @@ PasswordStoreConsumer::PasswordStoreConsumer() : weak_ptr_factory_(this) { PasswordStoreConsumer::~PasswordStoreConsumer() { } +void PasswordStoreConsumer::OnGetSiteStatistics( + scoped_ptr<InteractionsStats> stats) { +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/password_store_consumer.h b/components/password_manager/core/browser/password_store_consumer.h index 1ffdae3..b8934995 100644 --- a/components/password_manager/core/browser/password_store_consumer.h +++ b/components/password_manager/core/browser/password_store_consumer.h @@ -16,6 +16,8 @@ struct PasswordForm; namespace password_manager { +struct InteractionsStats; + // Reads from the PasswordStore are done asynchronously on a separate // thread. PasswordStoreConsumer provides the virtual callback method, which is // guaranteed to be executed on this (the UI) thread. It also provides the @@ -25,10 +27,13 @@ class PasswordStoreConsumer { public: PasswordStoreConsumer(); - // Called when the request is finished, with the associated |results|. + // Called when the GetLogins() request is finished, with the associated + // |results|. virtual void OnGetPasswordStoreResults( ScopedVector<autofill::PasswordForm> results) = 0; + virtual void OnGetSiteStatistics(scoped_ptr<InteractionsStats> stats); + // The base::CancelableTaskTracker can be used for cancelling the // tasks associated with the consumer. base::CancelableTaskTracker* cancelable_task_tracker() { diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc index 4e24ad1..54be8f8 100644 --- a/components/password_manager/core/browser/password_store_default.cc +++ b/components/password_manager/core/browser/password_store_default.cc @@ -148,4 +148,23 @@ bool PasswordStoreDefault::FillBlacklistLogins( return login_db_ && login_db_->GetBlacklistLogins(forms); } +void PasswordStoreDefault::AddSiteStatsImpl(const InteractionsStats& stats) { + DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); + if (login_db_) + login_db_->stats_table().AddRow(stats); +} + +void PasswordStoreDefault::RemoveSiteStatsImpl(const GURL& origin_domain) { + DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); + if (login_db_) + login_db_->stats_table().RemoveRow(origin_domain); +} + +scoped_ptr<InteractionsStats> PasswordStoreDefault::GetSiteStatsImpl( + const GURL& origin_domain) { + DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); + return login_db_ ? login_db_->stats_table().GetRow(origin_domain) + : scoped_ptr<InteractionsStats>(); +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h index ecfd38f..ab02004 100644 --- a/components/password_manager/core/browser/password_store_default.h +++ b/components/password_manager/core/browser/password_store_default.h @@ -59,8 +59,11 @@ class PasswordStoreDefault : public PasswordStore { ScopedVector<autofill::PasswordForm>* forms) override; bool FillBlacklistLogins( ScopedVector<autofill::PasswordForm>* forms) override; + void AddSiteStatsImpl(const InteractionsStats& stats) override; + void RemoveSiteStatsImpl(const GURL& origin_domain) override; + scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) override; - protected: inline bool DeleteAndRecreateDatabaseFile() { return login_db_->DeleteAndRecreateDatabaseFile(); } diff --git a/components/password_manager/core/browser/statistics_table.cc b/components/password_manager/core/browser/statistics_table.cc new file mode 100644 index 0000000..1246ee9 --- /dev/null +++ b/components/password_manager/core/browser/statistics_table.cc @@ -0,0 +1,83 @@ +// Copyright 2015 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 "components/password_manager/core/browser/statistics_table.h" + +#include "sql/connection.h" +#include "sql/statement.h" + +namespace password_manager { +namespace { + +// Convenience enum for interacting with SQL queries that use all the columns. +enum LoginTableColumns { + COLUMN_ORIGIN_DOMAIN = 0, + COLUMN_NOPES, + COLUMN_DISMISSALS, + COLUMN_DATE, +}; + +} // namespace + +StatisticsTable::StatisticsTable() : db_(nullptr) { +} + +StatisticsTable::~StatisticsTable() { +} + +bool StatisticsTable::Init(sql::Connection* db) { + db_ = db; + if (!db_->DoesTableExist("stats")) { + const char query[] = + "CREATE TABLE stats (" + "origin_domain VARCHAR NOT NULL PRIMARY KEY, " + "nopes_count INTEGER, " + "dismissal_count INTEGER, " + "start_date INTEGER NOT NULL)"; + if (!db_->Execute(query)) + return false; + } + return true; +} + +bool StatisticsTable::AddRow(const InteractionsStats& stats) { + sql::Statement s(db_->GetCachedStatement( + SQL_FROM_HERE, + "INSERT OR REPLACE INTO stats " + "(origin_domain, nopes_count, dismissal_count, start_date) " + "VALUES (?, ?, ?, ?)")); + s.BindString(COLUMN_ORIGIN_DOMAIN, stats.origin_domain.spec()); + s.BindInt(COLUMN_NOPES, stats.nopes_count); + s.BindInt(COLUMN_DISMISSALS, stats.dismissal_count); + s.BindInt64(COLUMN_DATE, stats.start_date.ToInternalValue()); + return s.Run(); +} + +bool StatisticsTable::RemoveRow(const GURL& domain) { + sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, + "DELETE FROM stats WHERE " + "origin_domain = ? ")); + s.BindString(0, domain.spec()); + return s.Run(); +} + +scoped_ptr<InteractionsStats> StatisticsTable::GetRow(const GURL& domain) { + const char query[] = + "SELECT origin_domain, nopes_count, " + "dismissal_count, start_date FROM stats WHERE origin_domain == ?"; + sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, query)); + s.BindString(0, domain.spec()); + if (s.Step()) { + scoped_ptr<InteractionsStats> stats(new InteractionsStats); + stats->origin_domain = GURL(s.ColumnString(COLUMN_ORIGIN_DOMAIN)); + stats->nopes_count = s.ColumnInt(COLUMN_NOPES); + stats->dismissal_count = s.ColumnInt(COLUMN_DISMISSALS); + stats->start_date = + base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE)); + return stats.Pass(); + } + return scoped_ptr<InteractionsStats>(); +} + +} // namespace password_manager diff --git a/components/password_manager/core/browser/statistics_table.h b/components/password_manager/core/browser/statistics_table.h new file mode 100644 index 0000000..d135309 --- /dev/null +++ b/components/password_manager/core/browser/statistics_table.h @@ -0,0 +1,61 @@ +// Copyright 2015 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STATISTICS_TABLE_H_ +#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STATISTICS_TABLE_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "url/gurl.h" + +namespace sql { +class Connection; +} + +namespace password_manager { + +// The statistics containing user interactions with a site. +struct InteractionsStats { + // The domain of the site. + GURL origin_domain; + + // Number of times the user clicked "Don't save the password". + int nopes_count; + + // Number of times the user dismissed the bubble. + int dismissal_count; + + // The beginning date of the measurements. + base::Time start_date; +}; + +// Represents 'stats' table in the Login Database. +class StatisticsTable { + public: + StatisticsTable(); + ~StatisticsTable(); + + // Initializes |db_| and creates the statistics table if it doesn't exist. + bool Init(sql::Connection* db); + + // Adds or replaces the statistics about |stats.origin_domain|. + bool AddRow(const InteractionsStats& stats); + + // Removes the statistics for |domain|. Returns true if the SQL completed + // successfully. + bool RemoveRow(const GURL& domain); + + // Returns the statistics for |domain| if it exists. + scoped_ptr<InteractionsStats> GetRow(const GURL& domain); + + private: + sql::Connection* db_; + + DISALLOW_COPY_AND_ASSIGN(StatisticsTable); +}; + +} // namespace password_manager + +#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STATISTICS_TABLE_H_ diff --git a/components/password_manager/core/browser/statistics_table_unittest.cc b/components/password_manager/core/browser/statistics_table_unittest.cc new file mode 100644 index 0000000..c3d28ff --- /dev/null +++ b/components/password_manager/core/browser/statistics_table_unittest.cc @@ -0,0 +1,91 @@ +// Copyright 2015 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 "components/password_manager/core/browser/statistics_table.h" + +#include "base/files/scoped_temp_dir.h" +#include "sql/connection.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace password_manager { +namespace { + +const char kTestDomain[] = "http://google.com"; + +void CheckStatsAreEqual(const InteractionsStats& left, + const InteractionsStats& right) { + EXPECT_EQ(left.origin_domain, right.origin_domain); + EXPECT_EQ(left.nopes_count, right.nopes_count); + EXPECT_EQ(left.dismissal_count, right.dismissal_count); + EXPECT_EQ(left.start_date, right.start_date); +} + +class StatisticsTableTest : public testing::Test { + protected: + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ReloadDatabase(); + + test_data_.origin_domain = GURL(kTestDomain); + test_data_.nopes_count = 5; + test_data_.dismissal_count = 10; + test_data_.start_date = base::Time::FromTimeT(1); + } + + void ReloadDatabase() { + base::FilePath file = temp_dir_.path().AppendASCII("TestDatabase"); + db_.reset(new StatisticsTable); + connection_.reset(new sql::Connection); + connection_->set_exclusive_locking(); + ASSERT_TRUE(connection_->Open(file)); + ASSERT_TRUE(db_->Init(connection_.get())); + } + + InteractionsStats& test_data() { return test_data_; } + StatisticsTable* db() { return db_.get(); } + + private: + base::ScopedTempDir temp_dir_; + scoped_ptr<sql::Connection> connection_; + scoped_ptr<StatisticsTable> db_; + InteractionsStats test_data_; +}; + +TEST_F(StatisticsTableTest, Sanity) { + EXPECT_TRUE(db()->AddRow(test_data())); + scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain); + ASSERT_TRUE(stats); + CheckStatsAreEqual(test_data(), *stats); + EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain)); + EXPECT_FALSE(db()->GetRow(test_data().origin_domain)); +} + +TEST_F(StatisticsTableTest, Reload) { + EXPECT_TRUE(db()->AddRow(test_data())); + EXPECT_TRUE(db()->GetRow(test_data().origin_domain)); + + ReloadDatabase(); + + scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain); + ASSERT_TRUE(stats); + CheckStatsAreEqual(test_data(), *stats); +} + +TEST_F(StatisticsTableTest, DoubleOperation) { + EXPECT_TRUE(db()->AddRow(test_data())); + test_data().nopes_count++; + EXPECT_TRUE(db()->AddRow(test_data())); + + scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain); + ASSERT_TRUE(stats); + CheckStatsAreEqual(test_data(), *stats); + + EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain)); + EXPECT_FALSE(db()->GetRow(test_data().origin_domain)); + EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain)); + EXPECT_FALSE(db()->GetRow(test_data().origin_domain)); +} + +} // namespace +} // namespace password_manager diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc index a420e9e..60f2536 100644 --- a/components/password_manager/core/browser/test_password_store.cc +++ b/components/password_manager/core/browser/test_password_store.cc @@ -139,4 +139,15 @@ bool TestPasswordStore::FillBlacklistLogins( return true; } +void TestPasswordStore::AddSiteStatsImpl(const InteractionsStats& stats) { +} + +void TestPasswordStore::RemoveSiteStatsImpl(const GURL& origin_domain) { +} + +scoped_ptr<InteractionsStats> TestPasswordStore::GetSiteStatsImpl( + const GURL& origin_domain) { + return scoped_ptr<InteractionsStats>(); +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h index 96f6104..72addcd 100644 --- a/components/password_manager/core/browser/test_password_store.h +++ b/components/password_manager/core/browser/test_password_store.h @@ -66,6 +66,10 @@ class TestPasswordStore : public PasswordStore { ScopedVector<autofill::PasswordForm>* forms) override; bool FillBlacklistLogins( ScopedVector<autofill::PasswordForm>* forms) override; + void AddSiteStatsImpl(const InteractionsStats& stats) override; + void RemoveSiteStatsImpl(const GURL& origin_domain) override; + scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) override; private: PasswordMap stored_passwords_; diff --git a/components/test/data/password_manager/login_db_v12.sql b/components/test/data/password_manager/login_db_v12.sql new file mode 100644 index 0000000..6f746fe --- /dev/null +++ b/components/test/data/password_manager/login_db_v12.sql @@ -0,0 +1,82 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); +INSERT INTO "meta" VALUES('last_compatible_version','1'); +INSERT INTO "meta" VALUES('version','12'); +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, +password_type INTEGER, +possible_usernames BLOB, +times_used INTEGER, +form_data BLOB, +date_synced INTEGER, +display_name VARCHAR, +avatar_url VARCHAR, +federation_url VARCHAR, +skip_zero_click INTEGER, +generation_upload_status INTEGER, +UNIQUE (origin_url, username_element, username_value, password_element, signon_realm)); +INSERT INTO "logins" VALUES( +'https://accounts.google.com/ServiceLogin', /* origin_url */ +'https://accounts.google.com/ServiceLoginAuth', /* action_url */ +'Email', /* username_element */ +'theerikchen', /* username_value */ +'Passwd', /* password_element */ +X'', /* password_value */ +'', /* submit_element */ +'https://accounts.google.com/', /* signon_realm */ +1, /* ssl_valid */ +1, /* preferred */ +13047429345000000, /* date_created */ +0, /* blacklisted_by_user */ +0, /* scheme */ +0, /* password_type */ +X'00000000', /* possible_usernames */ +1, /* times_used */ +X'18000000020000000000000000000000000000000000000000000000', /* form_data */ +0, /* date_synced */ +'', /* display_name */ +'', /* avatar_url */ +'', /* federation_url */ +0, /* skip_zero_click */ +0 /* generation_upload_status */ +); +INSERT INTO "logins" VALUES( +'https://accounts.google.com/ServiceLogin', /* origin_url */ +'https://accounts.google.com/ServiceLoginAuth', /* action_url */ +'Email', /* username_element */ +'theerikchen2', /* username_value */ +'Passwd', /* password_element */ +X'', /* password_value */ +'non-empty', /* submit_element */ +'https://accounts.google.com/', /* signon_realm */ +1, /* ssl_valid */ +1, /* preferred */ +13047423600000000, /* date_created */ +0, /* blacklisted_by_user */ +0, /* scheme */ +0, /* password_type */ +X'00000000', /* possible_usernames */ +1, /* times_used */ +X'18000000020000000000000000000000000000000000000000000000', /* form_data */ +0, /* date_synced */ +'', /* display_name */ +'', /* avatar_url */ +'', /* federation_url */ +0, /* skip_zero_click */ +0 /* generation_upload_status */ +); +CREATE INDEX logins_signon ON logins (signon_realm); +COMMIT; |