Chromium Code Reviews| Index: content/browser/net/sqlite_persistent_cookie_store.cc |
| diff --git a/content/browser/net/sqlite_persistent_cookie_store.cc b/content/browser/net/sqlite_persistent_cookie_store.cc |
| index 517a8c18a1646d10af600c125a9e1b00d754d606..dbf6e4f3734ce3fe7b90e29b9b7bd24affeed4e8 100644 |
| --- a/content/browser/net/sqlite_persistent_cookie_store.cc |
| +++ b/content/browser/net/sqlite_persistent_cookie_store.cc |
| @@ -27,6 +27,7 @@ |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "base/time/time.h" |
| #include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/cookie_crypto_delegate.h" |
| #include "content/public/browser/cookie_store_factory.h" |
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| #include "net/cookies/canonical_cookie.h" |
| @@ -74,7 +75,8 @@ class SQLitePersistentCookieStore::Backend |
| const scoped_refptr<base::SequencedTaskRunner>& client_task_runner, |
| const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, |
| bool restore_old_session_cookies, |
| - quota::SpecialStoragePolicy* special_storage_policy) |
| + quota::SpecialStoragePolicy* special_storage_policy, |
| + scoped_ptr<CookieCryptoDelegate> crypto_delegate) |
| : path_(path), |
| num_pending_(0), |
| force_keep_session_state_(false), |
| @@ -86,7 +88,8 @@ class SQLitePersistentCookieStore::Backend |
| client_task_runner_(client_task_runner), |
| background_task_runner_(background_task_runner), |
| num_priority_waiting_(0), |
| - total_priority_requests_(0) {} |
| + total_priority_requests_(0), |
| + crypto_(crypto_delegate.Pass()) {} |
| // Creates or loads the SQLite database. |
| void Load(const LoadedCallback& loaded_callback); |
| @@ -269,6 +272,9 @@ class SQLitePersistentCookieStore::Backend |
| // The cumulative duration of time when |num_priority_waiting_| was greater |
| // than 1. |
| base::TimeDelta priority_wait_duration_; |
| + // Class with functions that do cryptographic operations (for protecting |
| + // cookies stored persistently). |
| + scoped_ptr<CookieCryptoDelegate> crypto_; |
| DISALLOW_COPY_AND_ASSIGN(Backend); |
| }; |
| @@ -277,6 +283,9 @@ namespace { |
| // Version number of the database. |
| // |
| +// Version 7 adds encrypted values. Old values will continue to be used but |
| +// all new values written will be encrypted on selected operating systems. |
|
erikwright (departed)
2013/10/22 23:58:14
Add backwards-compatibility statement.
i.e., new
bcwhite
2013/10/23 19:36:23
Done.
|
| +// |
| // Version 6 adds cookie priorities. This allows developers to influence the |
| // order in which cookies are evicted in order to meet domain cookie limits. |
| // |
| @@ -293,7 +302,7 @@ namespace { |
| // Version 3 updated the database to include the last access time, so we can |
| // expire them in decreasing order of use when we've reached the maximum |
| // number of cookies. |
| -const int kCurrentVersionNumber = 6; |
| +const int kCurrentVersionNumber = 7; |
| const int kCompatibleVersionNumber = 5; |
| // Possible values for the 'priority' column. |
| @@ -370,7 +379,8 @@ bool InitTable(sql::Connection* db) { |
| "last_access_utc INTEGER NOT NULL, " |
| "has_expires INTEGER NOT NULL DEFAULT 1, " |
| "persistent INTEGER NOT NULL DEFAULT 1," |
| - "priority INTEGER NOT NULL DEFAULT %d)", |
| + "priority INTEGER NOT NULL DEFAULT %d," |
| + "encrypted_value BLOB DEFAULT '')", |
| CookiePriorityToDBCookiePriority(net::COOKIE_PRIORITY_DEFAULT))); |
| if (!db->Execute(stmt.c_str())) |
| return false; |
| @@ -679,15 +689,16 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains( |
| if (restore_old_session_cookies_) { |
| smt.Assign(db_->GetCachedStatement( |
| SQL_FROM_HERE, |
| - "SELECT creation_utc, host_key, name, value, path, expires_utc, " |
| - "secure, httponly, last_access_utc, has_expires, persistent, priority " |
| - "FROM cookies WHERE host_key = ?")); |
| + "SELECT creation_utc, host_key, name, value, encrypted_value, path, " |
| + "expires_utc, secure, httponly, last_access_utc, has_expires, " |
| + "persistent, priority FROM cookies WHERE host_key = ?")); |
| } else { |
| smt.Assign(db_->GetCachedStatement( |
| SQL_FROM_HERE, |
| - "SELECT creation_utc, host_key, name, value, path, expires_utc, " |
| - "secure, httponly, last_access_utc, has_expires, persistent, priority " |
| - "FROM cookies WHERE host_key = ? AND persistent = 1")); |
| + "SELECT creation_utc, host_key, name, value, encrypted_value, path, " |
| + "expires_utc, secure, httponly, last_access_utc, has_expires, " |
| + "persistent, priority FROM cookies WHERE host_key = ? " |
| + "AND persistent = 1")); |
| } |
| if (!smt.is_valid()) { |
| smt.Clear(); // Disconnect smt_ref from db_. |
| @@ -701,20 +712,29 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains( |
| for (; it != domains.end(); ++it) { |
| smt.BindString(0, *it); |
| while (smt.Step()) { |
| + std::string value; |
| + std::string encrypted_value = smt.ColumnString(4); |
| + if (!encrypted_value.empty() && crypto_.get()) { |
| + DCHECK(value.empty()); |
|
erikwright (departed)
2013/10/22 23:58:14
This DCHECK serves no purpose; there is no assignm
bcwhite
2013/10/23 19:36:23
Right. It used to be loaded from ColumnString(3)
|
| + crypto_->DecryptString(encrypted_value, &value); |
| + } else { |
| + DCHECK(encrypted_value.empty()); |
| + value = smt.ColumnString(3); |
| + } |
| scoped_ptr<net::CanonicalCookie> cc(new net::CanonicalCookie( |
| // The "source" URL is not used with persisted cookies. |
| GURL(), // Source |
| smt.ColumnString(2), // name |
| - smt.ColumnString(3), // value |
| + value, // value |
| smt.ColumnString(1), // domain |
| - smt.ColumnString(4), // path |
| + smt.ColumnString(5), // path |
| Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc |
| - Time::FromInternalValue(smt.ColumnInt64(5)), // expires_utc |
| - Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc |
| - smt.ColumnInt(6) != 0, // secure |
| - smt.ColumnInt(7) != 0, // httponly |
| + Time::FromInternalValue(smt.ColumnInt64(6)), // expires_utc |
| + Time::FromInternalValue(smt.ColumnInt64(9)), // last_access_utc |
| + smt.ColumnInt(7) != 0, // secure |
| + smt.ColumnInt(8) != 0, // httponly |
| DBCookiePriorityToCookiePriority( |
| - static_cast<DBCookiePriority>(smt.ColumnInt(11))))); // priority |
| + static_cast<DBCookiePriority>(smt.ColumnInt(12))))); // priority |
| DLOG_IF(WARNING, |
| cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; |
| cookies_per_origin_[CookieOrigin(cc->Domain(), cc->IsSecure())]++; |
| @@ -837,6 +857,26 @@ bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() { |
| base::TimeTicks::Now() - start_time); |
| } |
| + if (cur_version == 6) { |
| + const base::TimeTicks start_time = base::TimeTicks::Now(); |
| + sql::Transaction transaction(db_.get()); |
| + if (!transaction.Begin()) |
| + return false; |
| + // Alter the table to add empty "encrypted value" column. |
| + if (!db_->Execute("ALTER TABLE cookies " |
| + "ADD COLUMN encrypted_value BLOB DEFAULT ''")) { |
| + LOG(WARNING) << "Unable to update cookie database to version 7."; |
| + return false; |
| + } |
| + ++cur_version; |
| + meta_table_.SetVersionNumber(cur_version); |
| + meta_table_.SetCompatibleVersionNumber( |
| + std::min(cur_version, kCompatibleVersionNumber)); |
| + transaction.Commit(); |
| + UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV7", |
| + base::TimeTicks::Now() - start_time); |
| + } |
| + |
| // Put future migration cases here. |
| if (cur_version < kCurrentVersionNumber) { |
| @@ -921,10 +961,10 @@ void SQLitePersistentCookieStore::Backend::Commit() { |
| return; |
| sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE, |
| - "INSERT INTO cookies (creation_utc, host_key, name, value, path, " |
| - "expires_utc, secure, httponly, last_access_utc, has_expires, " |
| - "persistent, priority) " |
| - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)")); |
| + "INSERT INTO cookies (creation_utc, host_key, name, value, " |
| + "encrypted_value, path, expires_utc, secure, httponly, last_access_utc, " |
| + "has_expires, persistent, priority) " |
| + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)")); |
| if (!add_smt.is_valid()) |
| return; |
| @@ -954,16 +994,26 @@ void SQLitePersistentCookieStore::Backend::Commit() { |
| add_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); |
| add_smt.BindString(1, po->cc().Domain()); |
| add_smt.BindString(2, po->cc().Name()); |
| - add_smt.BindString(3, po->cc().Value()); |
| - add_smt.BindString(4, po->cc().Path()); |
| - add_smt.BindInt64(5, po->cc().ExpiryDate().ToInternalValue()); |
| - add_smt.BindInt(6, po->cc().IsSecure()); |
| - add_smt.BindInt(7, po->cc().IsHttpOnly()); |
| - add_smt.BindInt64(8, po->cc().LastAccessDate().ToInternalValue()); |
| - add_smt.BindInt(9, po->cc().IsPersistent()); |
| + if (crypto_.get()) { |
| + std::string encrypted_value; |
| + add_smt.BindCString(3, ""); // value |
| + crypto_->EncryptString(po->cc().Value(), &encrypted_value); |
| + // BindBlob() immediately makes an internal copy of the data. |
| + add_smt.BindBlob(4, encrypted_value.data(), |
| + static_cast<int>(encrypted_value.length())); |
| + } else { |
| + add_smt.BindString(3, po->cc().Value()); |
| + add_smt.BindBlob(4, "", 0); // encrypted_value |
| + } |
| + add_smt.BindString(5, po->cc().Path()); |
| + add_smt.BindInt64(6, po->cc().ExpiryDate().ToInternalValue()); |
| + add_smt.BindInt(7, po->cc().IsSecure()); |
| + add_smt.BindInt(8, po->cc().IsHttpOnly()); |
| + add_smt.BindInt64(9, po->cc().LastAccessDate().ToInternalValue()); |
| add_smt.BindInt(10, po->cc().IsPersistent()); |
| + add_smt.BindInt(11, po->cc().IsPersistent()); |
| add_smt.BindInt( |
| - 11, CookiePriorityToDBCookiePriority(po->cc().Priority())); |
| + 12, CookiePriorityToDBCookiePriority(po->cc().Priority())); |
| if (!add_smt.Run()) |
| NOTREACHED() << "Could not add a cookie to the DB."; |
| break; |
| @@ -1149,12 +1199,14 @@ SQLitePersistentCookieStore::SQLitePersistentCookieStore( |
| const scoped_refptr<base::SequencedTaskRunner>& client_task_runner, |
| const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, |
| bool restore_old_session_cookies, |
| - quota::SpecialStoragePolicy* special_storage_policy) |
| + quota::SpecialStoragePolicy* special_storage_policy, |
| + scoped_ptr<CookieCryptoDelegate> crypto_delegate) |
| : backend_(new Backend(path, |
| client_task_runner, |
| background_task_runner, |
| restore_old_session_cookies, |
| - special_storage_policy)) { |
| + special_storage_policy, |
| + crypto_delegate.Pass())) { |
| } |
| void SQLitePersistentCookieStore::Load(const LoadedCallback& loaded_callback) { |
| @@ -1199,7 +1251,8 @@ net::CookieStore* CreatePersistentCookieStore( |
| bool restore_old_session_cookies, |
| quota::SpecialStoragePolicy* storage_policy, |
| net::CookieMonster::Delegate* cookie_monster_delegate, |
| - const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) { |
| + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, |
| + scoped_ptr<CookieCryptoDelegate> crypto_delegate) { |
| SQLitePersistentCookieStore* persistent_store = |
| new SQLitePersistentCookieStore( |
| path, |
| @@ -1208,7 +1261,8 @@ net::CookieStore* CreatePersistentCookieStore( |
| BrowserThread::GetBlockingPool()->GetSequencedTaskRunner( |
| BrowserThread::GetBlockingPool()->GetSequenceToken()), |
| restore_old_session_cookies, |
| - storage_policy); |
| + storage_policy, |
| + crypto_delegate.Pass()); |
| net::CookieMonster* cookie_monster = |
| new net::CookieMonster(persistent_store, cookie_monster_delegate); |