Commit 67bb274e authored by avayvod@chromium.org's avatar avayvod@chromium.org

Backup keywords, sign all backup settings together.

R=sky@chromium.org
BUG=94447
TEST=Verify that migration to this build of Chrome goes smoothly and changing any search engine in Web Data file triggers the bubble.

Review URL: http://codereview.chromium.org/8567004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112884 0039d316-1c4b-4281-b951-d872f2087c98
parent a4674842
......@@ -14,11 +14,6 @@ namespace protector {
const char kProtectorHistogramDefaultSearchProvider[] =
"Protector.DefaultSearchProvider";
const char kProtectorBackupInvalidCounter[] =
"Protector.BackupInvalidCounter";
const char kProtectorValueChangedCounter[] = "Protector.ValueChangedCounter";
const char kProtectorValueValidCounter[] = "Protector.ValueValidCounter";
const char kProtectorHistogramNewSearchProvider[] =
"Protector.SearchProvider.New";
const char kProtectorHistogramSearchProviderApplied[] =
......
......@@ -14,18 +14,12 @@ namespace protector {
// provider. Values are below.
extern const char kProtectorHistogramDefaultSearchProvider[];
// Histogram value to report that the backup value is invalid or missing.
extern const char kProtectorBackupInvalidCounter[];
// Histogram value to report that the value does not match the backup.
extern const char kProtectorValueChangedCounter[];
// Histogram value to report that the value matches the backup.
extern const char kProtectorValueValidCounter[];
// Protector histogram values.
enum ProtectorError {
kProtectorErrorBackupInvalid,
kProtectorErrorValueChanged,
kProtectorErrorValueValid,
kProtectorErrorValueValidZero,
// This is for convenience only, must always be the last.
kProtectorErrorCount
......
......@@ -17,6 +17,7 @@
#include "chrome/browser/search_engines/template_url.h"
#include "googleurl/src/gurl.h"
#include "sql/statement.h"
#include "sql/transaction.h"
using base::Time;
......@@ -30,12 +31,16 @@ const char kDefaultSearchProviderKey[] = "Default Search Provider ID";
const char kBuiltinKeywordVersion[] = "Builtin Keyword Version";
// Meta table key to store backup value for the default search provider.
const char kDefaultSearchProviderBackupKey[] =
const char kDefaultSearchBackupKey[] = "Default Search Provider Backup";
// Meta table key to store backup value for the default search provider id.
const char kDefaultSearchIDBackupKey[] =
"Default Search Provider ID Backup";
// Meta table key to store backup value signature for the default search
// provider.
const char kDefaultSearchProviderBackupSignatureKey[] =
// provider. Default search provider id, its row in |keywords| table and
// the whole |keywords| table are signed.
const char kBackupSignatureKey[] =
"Default Search Provider ID Backup Signature";
void BindURLToStatement(const TemplateURL& url, sql::Statement* s) {
......@@ -89,7 +94,8 @@ KeywordTable::~KeywordTable() {}
bool KeywordTable::Init() {
if (!db_->DoesTableExist("keywords")) {
if (!db_->Execute("CREATE TABLE keywords ("
if (!db_->Execute(
"CREATE TABLE keywords ("
"id INTEGER PRIMARY KEY,"
"short_name VARCHAR NOT NULL,"
"keyword VARCHAR NOT NULL,"
......@@ -112,10 +118,8 @@ bool KeywordTable::Init() {
NOTREACHED();
return false;
}
// Initialize default search engine provider for new profile to have it
// signed properly. TemplateURLService treats 0 as not existing id and
// resets the value to the actual default search provider id.
SetDefaultSearchProviderID(0);
if (!UpdateBackupSignature())
return false;
}
return true;
}
......@@ -127,7 +131,7 @@ bool KeywordTable::IsSyncable() {
bool KeywordTable::AddKeyword(const TemplateURL& url) {
DCHECK(url.id());
// Be sure to change kUrlIdPosition if you add columns
sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE,
sql::Statement s(db_->GetUniqueStatement(
"INSERT INTO keywords "
"(short_name, keyword, favicon_url, url, safe_for_autoreplace, "
"originating_url, date_created, usage_count, input_encodings, "
......@@ -145,19 +149,18 @@ bool KeywordTable::AddKeyword(const TemplateURL& url) {
NOTREACHED();
return false;
}
return true;
return UpdateBackupSignature();
}
bool KeywordTable::RemoveKeyword(TemplateURLID id) {
DCHECK(id);
sql::Statement s(
db_->GetUniqueStatement("DELETE FROM keywords WHERE id = ?"));
sql::Statement s(db_->GetUniqueStatement("DELETE FROM keywords WHERE id=?"));
if (!s) {
NOTREACHED() << "Statement prepare failed";
return false;
}
s.BindInt64(0, id);
return s.Run();
return s.Run() && UpdateBackupSignature();
}
bool KeywordTable::GetKeywords(std::vector<TemplateURL*>* urls) {
......@@ -174,53 +177,7 @@ bool KeywordTable::GetKeywords(std::vector<TemplateURL*>* urls) {
}
while (s.Step()) {
TemplateURL* template_url = new TemplateURL();
template_url->set_id(s.ColumnInt64(0));
std::string tmp;
tmp = s.ColumnString(1);
DCHECK(!tmp.empty());
template_url->set_short_name(UTF8ToUTF16(tmp));
template_url->set_keyword(UTF8ToUTF16(s.ColumnString(2)));
tmp = s.ColumnString(3);
if (!tmp.empty())
template_url->SetFaviconURL(GURL(tmp));
template_url->SetURL(s.ColumnString(4), 0, 0);
template_url->set_safe_for_autoreplace(s.ColumnInt(5) == 1);
tmp = s.ColumnString(6);
if (!tmp.empty())
template_url->set_originating_url(GURL(tmp));
template_url->set_date_created(Time::FromTimeT(s.ColumnInt64(7)));
template_url->set_usage_count(s.ColumnInt(8));
std::vector<std::string> encodings;
base::SplitString(s.ColumnString(9), ';', &encodings);
template_url->set_input_encodings(encodings);
template_url->set_show_in_default_list(s.ColumnInt(10) == 1);
template_url->SetSuggestionsURL(s.ColumnString(11), 0, 0);
template_url->SetPrepopulateId(s.ColumnInt(12));
template_url->set_autogenerate_keyword(s.ColumnInt(13) == 1);
template_url->set_logo_id(s.ColumnInt(14));
template_url->set_created_by_policy(s.ColumnBool(15));
template_url->SetInstantURL(s.ColumnString(16), 0, 0);
template_url->set_last_modified(Time::FromTimeT(s.ColumnInt64(17)));
template_url->set_sync_guid(s.ColumnString(18));
GetURLFromStatement(s, template_url);
urls->push_back(template_url);
}
return s.Succeeded();
......@@ -243,12 +200,12 @@ bool KeywordTable::UpdateKeyword(const TemplateURL& url) {
}
BindURLToStatement(url, &s);
s.BindInt64(kUrlIdPosition, url.id());
return s.Run();
return s.Run() && UpdateBackupSignature();
}
bool KeywordTable::SetDefaultSearchProviderID(int64 id) {
return meta_table_->SetValue(kDefaultSearchProviderKey, id) &&
SetDefaultSearchProviderBackupID(id);
UpdateBackupSignature();
}
int64 KeywordTable::GetDefaultSearchProviderID() {
......@@ -258,43 +215,52 @@ int64 KeywordTable::GetDefaultSearchProviderID() {
}
int64 KeywordTable::GetDefaultSearchProviderIDBackup() {
int64 backup_value = 0;
meta_table_->GetValue(kDefaultSearchProviderBackupKey, &backup_value);
std::string backup_signature;
meta_table_->GetValue(
kDefaultSearchProviderBackupSignatureKey, &backup_signature);
if (!IsSearchProviderIDValid(backup_value, backup_signature))
if (!IsBackupSignatureValid())
return 0;
int64 backup_value = 0;
meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_value);
return backup_value;
}
bool KeywordTable::DidDefaultSearchProviderChange() {
int64 backup_value = 0;
meta_table_->GetValue(kDefaultSearchProviderBackupKey, &backup_value);
std::string backup_signature;
meta_table_->GetValue(
kDefaultSearchProviderBackupSignatureKey, &backup_signature);
if (!IsSearchProviderIDValid(backup_value, backup_signature)) {
if (!IsBackupSignatureValid()) {
UMA_HISTOGRAM_ENUMERATION(
protector::kProtectorHistogramDefaultSearchProvider,
protector::kProtectorErrorBackupInvalid,
protector::kProtectorErrorCount);
SIMPLE_STATS_COUNTER(protector::kProtectorBackupInvalidCounter);
return true;
} else if (backup_value != GetDefaultSearchProviderID()) {
}
int64 backup_id = 0;
meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_id);
int64 current_id = GetDefaultSearchProviderID();
if (backup_id == current_id) {
std::string backup_url;
std::string current_url;
// Either this is a new profile and both IDs are zero or the search
// engines with the ids are equal.
if (backup_id == 0) {
UMA_HISTOGRAM_ENUMERATION(
protector::kProtectorHistogramDefaultSearchProvider,
protector::kProtectorErrorValueChanged,
protector::kProtectorErrorValueValidZero,
protector::kProtectorErrorCount);
SIMPLE_STATS_COUNTER(protector::kProtectorValueChangedCounter);
return true;
}
return false;
} else if (meta_table_->GetValue(kDefaultSearchBackupKey, &backup_url) &&
GetTemplateURLBackup(current_id, &current_url) &&
current_url == backup_url) {
UMA_HISTOGRAM_ENUMERATION(
protector::kProtectorHistogramDefaultSearchProvider,
protector::kProtectorErrorValueValid,
protector::kProtectorErrorCount);
SIMPLE_STATS_COUNTER(protector::kProtectorValueValidCounter);
return false;
}
}
UMA_HISTOGRAM_ENUMERATION(
protector::kProtectorHistogramDefaultSearchProvider,
protector::kProtectorErrorValueChanged,
protector::kProtectorErrorCount);
return true;
}
bool KeywordTable::SetBuiltinKeywordVersion(int version) {
......@@ -385,31 +351,191 @@ bool KeywordTable::MigrateToVersion39AddSyncGUIDColumn() {
bool KeywordTable::MigrateToVersion40AddDefaultSearchProviderBackup() {
int64 value = 0;
if (!meta_table_->GetValue(kDefaultSearchProviderKey, &value)) {
// Set default search provider ID and its backup.
return SetDefaultSearchProviderID(0);
// Write default search provider id if it's absent. TemplateURLService
// will replace 0 with some real value.
if (!meta_table_->SetValue(kDefaultSearchProviderKey, 0))
return false;
}
return SetDefaultSearchProviderBackupID(value);
return meta_table_->SetValue(kDefaultSearchIDBackupKey, value) &&
meta_table_->SetValue(
kBackupSignatureKey,
GetSearchProviderIDSignature(value));
}
bool KeywordTable::MigrateToVersion41RewriteDefaultSearchProviderBackup() {
// Due to crbug.com/101815 version 40 may contain corrupt or empty
// signature. So ignore the signature and simply rewrite it.
int64 value = 0;
if (!meta_table_->GetValue(kDefaultSearchProviderKey, &value)) {
// Set default search provider ID and its backup.
return SetDefaultSearchProviderID(0);
return MigrateToVersion40AddDefaultSearchProviderBackup();
}
bool KeywordTable::MigrateToVersion42AddKeywordsBackupTable() {
return UpdateBackupSignature();
}
std::string KeywordTable::GetSignatureData() {
int64 backup_value = 0;
if (!meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_value)) {
NOTREACHED() << "Couldn't get id backup.";
return std::string();
}
std::string backup_data = base::Int64ToString(backup_value);
std::string backup_url;
if (!meta_table_->GetValue(kDefaultSearchBackupKey, &backup_url)) {
NOTREACHED() << "Couldn't get backup url";
return std::string();
}
backup_data += backup_url;
sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE,
"SELECT id || short_name || keyword || favicon_url || url || "
"safe_for_autoreplace || originating_url || date_created || "
"usage_count || input_encodings || show_in_default_list || "
"suggest_url || prepopulate_id || autogenerate_keyword || logo_id || "
"created_by_policy || instant_url || last_modified || sync_guid "
"FROM keywords ORDER BY id ASC"));
if (!s) {
NOTREACHED() << "Statement prepare failed";
return std::string();
}
while (s.Step())
backup_data += s.ColumnString(0);
if (!s.Succeeded()) {
NOTREACHED() << "Statement execution failed";
return std::string();
}
return backup_data;
}
bool KeywordTable::UpdateBackupSignature() {
sql::Transaction transaction(db_);
if (!transaction.Begin()) {
NOTREACHED() << "Failed to begin transaction.";
return false;
}
// Backup of default search provider id.
int64 id = GetDefaultSearchProviderID();
if (!meta_table_->SetValue(kDefaultSearchIDBackupKey, id)) {
NOTREACHED() << "Failed to write backup id.";
return false;
}
// Backup of the default search provider info.
if (!UpdateDefaultSearchProviderBackup(id)) {
NOTREACHED() << "Failed to update backup.";
return false;
}
// Now calculate and update the signature.
std::string data_to_sign = GetSignatureData();
if (data_to_sign.empty()) {
NOTREACHED() << "Can't get data to sign";
return false;
}
std::string signature = protector::SignSetting(data_to_sign);
if (signature.empty()) {
NOTREACHED() << "Signature is empty";
return false;
}
return SetDefaultSearchProviderBackupID(value);
if (!meta_table_->SetValue(kBackupSignatureKey, signature)) {
NOTREACHED() << "Failed to write signature.";
return false;
}
return transaction.Commit();
}
bool KeywordTable::IsBackupSignatureValid() {
std::string signature;
return meta_table_->GetValue(kBackupSignatureKey, &signature) &&
protector::IsSettingValid(GetSignatureData(), signature);
}
void KeywordTable::GetURLFromStatement(
const sql::Statement& s,
TemplateURL* url) {
url->set_id(s.ColumnInt64(0));
std::string tmp;
tmp = s.ColumnString(1);
DCHECK(!tmp.empty());
url->set_short_name(UTF8ToUTF16(tmp));
url->set_keyword(UTF8ToUTF16(s.ColumnString(2)));
tmp = s.ColumnString(3);
if (!tmp.empty())
url->SetFaviconURL(GURL(tmp));
url->SetURL(s.ColumnString(4), 0, 0);
url->set_safe_for_autoreplace(s.ColumnInt(5) == 1);
tmp = s.ColumnString(6);
if (!tmp.empty())
url->set_originating_url(GURL(tmp));
url->set_date_created(Time::FromTimeT(s.ColumnInt64(7)));
url->set_usage_count(s.ColumnInt(8));
std::vector<std::string> encodings;
base::SplitString(s.ColumnString(9), ';', &encodings);
url->set_input_encodings(encodings);
url->set_show_in_default_list(s.ColumnInt(10) == 1);
url->SetSuggestionsURL(s.ColumnString(11), 0, 0);
url->SetPrepopulateId(s.ColumnInt(12));
url->set_autogenerate_keyword(s.ColumnInt(13) == 1);
url->set_logo_id(s.ColumnInt(14));
url->set_created_by_policy(s.ColumnBool(15));
url->SetInstantURL(s.ColumnString(16), 0, 0);
url->set_last_modified(Time::FromTimeT(s.ColumnInt64(17)));
url->set_sync_guid(s.ColumnString(18));
}
bool KeywordTable::SetDefaultSearchProviderBackupID(int64 id) {
return
meta_table_->SetValue(kDefaultSearchProviderBackupKey, id) &&
SetDefaultSearchProviderBackupIDSignature(id);
bool KeywordTable::GetTemplateURLBackup(TemplateURLID id,
std::string* result) {
sql::Statement s(db_->GetUniqueStatement(
"SELECT id || short_name || keyword || favicon_url || url || "
"safe_for_autoreplace || originating_url || date_created || "
"usage_count || input_encodings || show_in_default_list || "
"suggest_url || prepopulate_id || autogenerate_keyword || logo_id || "
"created_by_policy || instant_url || last_modified || sync_guid "
"FROM keywords WHERE id=?"));
if (!s) {
NOTREACHED() << "Statement prepare failed";
return false;
}
s.BindInt64(0, id);
if (!s.Step()) {
LOG(WARNING) << "No keyword with id: " << id << ", ignoring.";
return true;
}
if (!s.Succeeded()) {
NOTREACHED() << "Statement failed.";
return false;
}
*result = s.ColumnString(0);
return true;
}
bool KeywordTable::SetDefaultSearchProviderBackupIDSignature(int64 id) {
return meta_table_->SetValue(
kDefaultSearchProviderBackupSignatureKey,
GetSearchProviderIDSignature(id));
bool KeywordTable::UpdateDefaultSearchProviderBackup(TemplateURLID id) {
std::string backup;
if (id != 0 && !GetTemplateURLBackup(id, &backup)) {
NOTREACHED() << "Failed to get the keyword with id " << id;
return false;
}
return meta_table_->SetValue(kDefaultSearchBackupKey, backup);
}
......@@ -16,6 +16,10 @@
class TemplateURL;
namespace sql {
class Statement;
} // namespace sql
// This class manages the |keywords| MetaTable within the SQLite database
// passed to the constructor. It expects the following schema:
//
......@@ -50,6 +54,24 @@ class TemplateURL;
// sync_guid See TemplateURL::sync_guid. This was added in
// version 39.
//
// This class also manages some fields in the |meta| table:
// Default Search Provider ID The id of the default search provider.
// Default Search Provider ID Backup
// Backup copy of the above for restoring it
// in case the setting was hijacked or
// corrupted. This was added in version 40.
// Default Search Provider Backup Backup copy of the raw in |keywords|
// with the default search provider ID to
// restore all provider info. This was added
// in version 42.
// Default Search Provider ID Backup Signature
// The signature of backup data and
// |keywords| table contents to be able to
// verify the backup and understand when the
// settings were changed. This was added
// in version 40.
// Builtin Keyword Version The version of builtin keywords data.
//
class KeywordTable : public WebDatabaseTable {
public:
KeywordTable(sql::Connection* db, sql::MetaTable* meta_table)
......@@ -101,17 +123,35 @@ class KeywordTable : public WebDatabaseTable {
bool MigrateToVersion39AddSyncGUIDColumn();
bool MigrateToVersion40AddDefaultSearchProviderBackup();
bool MigrateToVersion41RewriteDefaultSearchProviderBackup();
bool MigrateToVersion42AddKeywordsBackupTable();
private:
FRIEND_TEST_ALL_PREFIXES(KeywordTableTest, DefaultSearchProviderBackup);
// Sets backup for id of the default search provider.
// Backup value is used to notice when unexpected change of the id
// occurred (i.e. by third-party process trying to modify user settings).
bool SetDefaultSearchProviderBackupID(int64 id);
// Returns contents of |keywords| table and default search provider backup
// as a string.
std::string GetSignatureData();
// Updates settings backup, signs it and stores the signature in the
// database. Returns true on success.
bool UpdateBackupSignature();
// Checks the signature for the current settings backup. Returns true
// if signature is valid, false otherwise.
bool IsBackupSignatureValid();
// Parses TemplateURL out of SQL statement result.
void GetURLFromStatement(const sql::Statement& s, TemplateURL* url);
// Gets a string representation for TemplateURL with id specified.
// Used to store its result in |meta| table or to compare with this
// backup. Returns true on success, false otherwise.
bool GetTemplateURLBackup(TemplateURLID id, std::string* result);
// Sets signature for the backup field.
bool SetDefaultSearchProviderBackupIDSignature(int64 id);
// Updates default search provider backup with TemplateURL data with
// specified id. Returns true on success.
// If id is 0, sets an empty string as a backup.
bool UpdateDefaultSearchProviderBackup(TemplateURLID id);
DISALLOW_COPY_AND_ASSIGN(KeywordTable);
};
......
......@@ -11,6 +11,7 @@
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/webdata/keyword_table.h"
#include "chrome/browser/webdata/web_database.h"
#include "sql/statement.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
......@@ -149,6 +150,30 @@ TEST_F(KeywordTableTest, KeywordMisc) {
ASSERT_EQ(0, db.GetKeywordTable()->GetDefaultSearchProviderID());
ASSERT_EQ(0, db.GetKeywordTable()->GetBuiltinKeywordVersion());
TemplateURL template_url;
template_url.set_short_name(ASCIIToUTF16("short_name"));
template_url.set_keyword(ASCIIToUTF16("keyword"));
GURL favicon_url("http://favicon.url/");
GURL originating_url("http://google.com/");
template_url.SetFaviconURL(favicon_url);
template_url.SetURL("http://url/", 0, 0);
template_url.set_safe_for_autoreplace(true);
Time created_time = Time::Now();
template_url.set_date_created(created_time);
Time last_modified_time = created_time + TimeDelta::FromSeconds(10);
template_url.set_last_modified(last_modified_time);
template_url.set_show_in_default_list(true);
template_url.set_originating_url(originating_url);
template_url.set_usage_count(32);
template_url.add_input_encoding("UTF-8");
template_url.add_input_encoding("UTF-16");
set_prepopulate_id(&template_url, 10);
set_logo_id(&template_url, 1000);
template_url.set_created_by_policy(true);
template_url.SetInstantURL("http://instant/", 0, 0);
SetID(10, &template_url);
ASSERT_TRUE(db.GetKeywordTable()->AddKeyword(template_url));
ASSERT_TRUE(db.GetKeywordTable()->SetDefaultSearchProviderID(10));
ASSERT_TRUE(db.GetKeywordTable()->SetBuiltinKeywordVersion(11));
......@@ -163,14 +188,62 @@ TEST_F(KeywordTableTest, DefaultSearchProviderBackup) {
EXPECT_EQ(0, db.GetKeywordTable()->GetDefaultSearchProviderID());
ASSERT_TRUE(db.GetKeywordTable()->SetDefaultSearchProviderID(10));
EXPECT_EQ(10, db.GetKeywordTable()->GetDefaultSearchProviderID());
EXPECT_EQ(10, db.GetKeywordTable()->GetDefaultSearchProviderIDBackup());
TemplateURL template_url;
template_url.set_short_name(ASCIIToUTF16("short_name"));
template_url.set_keyword(ASCIIToUTF16("keyword"));
GURL favicon_url("http://favicon.url/");
GURL originating_url("http://originating.url/");
template_url.SetFaviconURL(favicon_url);
template_url.SetURL("http://url/", 0, 0);
template_url.set_safe_for_autoreplace(true);
template_url.set_show_in_default_list(true);
template_url.SetSuggestionsURL("url2", 0, 0);
SetID(1, &template_url);
EXPECT_TRUE(db.GetKeywordTable()->AddKeyword(template_url));
ASSERT_TRUE(db.GetKeywordTable()->SetDefaultSearchProviderID(1));
EXPECT_TRUE(db.GetKeywordTable()->IsBackupSignatureValid());
EXPECT_EQ(1, db.GetKeywordTable()->GetDefaultSearchProviderID());
EXPECT_EQ(1, db.GetKeywordTable()->GetDefaultSearchProviderIDBackup());
EXPECT_FALSE(db.GetKeywordTable()->DidDefaultSearchProviderChange());
ASSERT_TRUE(db.GetKeywordTable()->SetDefaultSearchProviderBackupID(11));
EXPECT_EQ(10, db.GetKeywordTable()->GetDefaultSearchProviderID());
EXPECT_EQ(11, db.GetKeywordTable()->GetDefaultSearchProviderIDBackup());
// Change the actual setting.
ASSERT_TRUE(db.GetKeywordTable()->meta_table_->SetValue(
"Default Search Provider ID", 2));
EXPECT_TRUE(db.GetKeywordTable()->IsBackupSignatureValid());
EXPECT_EQ(2, db.GetKeywordTable()->GetDefaultSearchProviderID());
EXPECT_EQ(1, db.GetKeywordTable()->GetDefaultSearchProviderIDBackup());
EXPECT_TRUE(db.GetKeywordTable()->DidDefaultSearchProviderChange());
// Change the backup.
ASSERT_TRUE(db.GetKeywordTable()->meta_table_->SetValue(
"Default Search Provider ID", 1));
ASSERT_TRUE(db.GetKeywordTable()->meta_table_->SetValue(
"Default Search Provider ID Backup", 2));
EXPECT_FALSE(db.GetKeywordTable()->IsBackupSignatureValid());
EXPECT_EQ(1, db.GetKeywordTable()->GetDefaultSearchProviderID());
EXPECT_EQ(0, db.GetKeywordTable()->GetDefaultSearchProviderIDBackup());
EXPECT_TRUE(db.GetKeywordTable()->DidDefaultSearchProviderChange());
// Change the signature.
ASSERT_TRUE(db.GetKeywordTable()->meta_table_->SetValue(
"Default Search Provider ID Backup", 1));
ASSERT_TRUE(db.GetKeywordTable()->meta_table_->SetValue(
"Default Search Provider ID Backup Signature", ""));
EXPECT_FALSE(db.GetKeywordTable()->IsBackupSignatureValid());
EXPECT_EQ(1, db.GetKeywordTable()->GetDefaultSearchProviderID());
EXPECT_EQ(0, db.GetKeywordTable()->GetDefaultSearchProviderIDBackup());
EXPECT_TRUE(db.GetKeywordTable()->DidDefaultSearchProviderChange());
// Change keywords.
ASSERT_TRUE(db.GetKeywordTable()->UpdateBackupSignature());
sql::Statement remove_keyword(db.GetKeywordTable()->db_->GetUniqueStatement(
"DELETE FROM keywords WHERE id=1"));
ASSERT_TRUE(remove_keyword.Run());
EXPECT_FALSE(db.GetKeywordTable()->IsBackupSignatureValid());
EXPECT_EQ(1, db.GetKeywordTable()->GetDefaultSearchProviderID());
EXPECT_EQ(0, db.GetKeywordTable()->GetDefaultSearchProviderIDBackup());
EXPECT_TRUE(db.GetKeywordTable()->DidDefaultSearchProviderChange());
}
......
......@@ -22,8 +22,8 @@ namespace {
// Current version number. Note: when changing the current version number,
// corresponding changes must happen in the unit tests, and new migration test
// added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
const int kCurrentVersionNumber = 41;
const int kCompatibleVersionNumber = 41;
const int kCurrentVersionNumber = 42;
const int kCompatibleVersionNumber = 42;
// Change the version number and possibly the compatibility version of
// |meta_table_|.
......@@ -319,6 +319,13 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() {
ChangeVersion(&meta_table_, 41, true);
// FALL THROUGH
case 41:
if (!keyword_table_->MigrateToVersion42AddKeywordsBackupTable())
return FailedMigrationTo(42);
ChangeVersion(&meta_table_, 42, true);
// FALL THROUGH
// Add successive versions here. Each should set the version number and
// compatible version number as appropriate, then fall through to the next
// case.
......
......@@ -196,7 +196,7 @@ class WebDatabaseMigrationTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
};
const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 41;
const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 42;
void WebDatabaseMigrationTest::LoadDatabase(const FilePath::StringType& file) {
std::string contents;
......@@ -1655,3 +1655,104 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion40ToCurrent) {
}
}
// Tests that all keywords are backed up and signed.
TEST_F(WebDatabaseMigrationTest, MigrateVersion41ToCurrent) {
ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_41.sql")));
// Verify pre-conditions. These are expectations for version 40 of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
sql::MetaTable meta_table;
ASSERT_TRUE(meta_table.Init(&connection, 41, 41));
int64 default_search_provider_id = 0;
EXPECT_TRUE(meta_table.GetValue(
"Default Search Provider ID",
&default_search_provider_id));
int64 default_search_provider_id_backup = 0;
EXPECT_TRUE(meta_table.GetValue(
"Default Search Provider ID Backup",
&default_search_provider_id_backup));
std::string default_search_provider_id_backup_signature;
EXPECT_TRUE(meta_table.GetValue(
"Default Search Provider ID Backup Signature",
&default_search_provider_id_backup_signature));
EXPECT_FALSE(default_search_provider_id_backup_signature.empty());
std::string default_search_provider_backup;
EXPECT_FALSE(meta_table.GetValue(
"Default Search Provider Backup",
&default_search_provider_backup));
}
// Load the database via the WebDatabase class and migrate the database to
// the current version.
{
WebDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
}
// Verify post-conditions. These are expectations for current version of the
// database.
{
sql::Connection connection;
ASSERT_TRUE(connection.Open(GetDatabasePath()));
ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
sql::MetaTable meta_table;
ASSERT_TRUE(meta_table.Init(
&connection,
kCurrentTestedVersionNumber,
kCurrentTestedVersionNumber));
int64 default_search_provider_id = 0;
EXPECT_TRUE(meta_table.GetValue(
"Default Search Provider ID",
&default_search_provider_id));
EXPECT_NE(0, default_search_provider_id);
int64 default_search_provider_id_backup = 0;
EXPECT_TRUE(meta_table.GetValue(
"Default Search Provider ID Backup",
&default_search_provider_id_backup));
EXPECT_EQ(default_search_provider_id, default_search_provider_id_backup);
std::string default_search_provider_id_backup_signature;
EXPECT_TRUE(meta_table.GetValue(
"Default Search Provider ID Backup Signature",
&default_search_provider_id_backup_signature));
EXPECT_FALSE(default_search_provider_id_backup_signature.empty());
std::string default_search_provider_backup;
EXPECT_TRUE(meta_table.GetValue(
"Default Search Provider Backup",
&default_search_provider_backup));
EXPECT_EQ("2"
"Google"
"google.com"
"http://www.google.com/favicon.ico"
"{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}"
"{google:originalQueryForSuggestion}sourceid=chrome&"
"ie={inputEncoding}&q={searchTerms}"
"100"
"UTF-8"
"1"
"{google:baseSuggestURL}search?client=chrome&hl={language}&"
"q={searchTerms}"
"1162620"
"{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&"
"ie={inputEncoding}&ion=1{searchTerms}&nord=10"
"{1234-5678-90AB-CDEF}",
default_search_provider_backup);
}
}
......@@ -3,7 +3,6 @@ BEGIN TRANSACTION;
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
INSERT INTO "meta" VALUES('version','24');
INSERT INTO "meta" VALUES('last_compatible_version','24');
INSERT INTO "meta" VALUES('Default Search Provider ID','2');
INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0);
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));
......
......@@ -3,7 +3,6 @@ BEGIN TRANSACTION;
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
INSERT INTO "meta" VALUES('version','25');
INSERT INTO "meta" VALUES('last_compatible_version','25');
INSERT INTO "meta" VALUES('Default Search Provider ID','2');
INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0);
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));
......
......@@ -3,7 +3,6 @@ BEGIN TRANSACTION;
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
INSERT INTO "meta" VALUES('version','26');
INSERT INTO "meta" VALUES('last_compatible_version','26');
INSERT INTO "meta" VALUES('Default Search Provider ID','2');
INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0);
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));
......
......@@ -3,7 +3,6 @@ BEGIN TRANSACTION;
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
INSERT INTO "meta" VALUES('version','27');
INSERT INTO "meta" VALUES('last_compatible_version','27');
INSERT INTO "meta" VALUES('Default Search Provider ID','2');
INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0);
INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6245,0);
......
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
INSERT INTO "meta" VALUES('version','40');
INSERT INTO "meta" VALUES('last_compatible_version','40');
INSERT INTO "meta" VALUES('Default Search Provider ID','2');
INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','Signature');
INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR);
INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}');
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));
CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
CREATE INDEX logins_signon ON logins (signon_realm);
CREATE INDEX web_apps_url_index ON web_apps (url);
CREATE INDEX autofill_name ON autofill (name);
CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
COMMIT;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment