1 // Copyright 2024 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_DEVICE_BOUND_SESSIONS_SESSION_STORE_IMPL_H_ 6 #define NET_DEVICE_BOUND_SESSIONS_SESSION_STORE_IMPL_H_ 7 8 #include <optional> 9 #include <string> 10 11 #include "base/files/file_path.h" 12 #include "base/functional/callback.h" 13 #include "base/functional/callback_forward.h" 14 #include "base/gtest_prod_util.h" 15 #include "base/memory/scoped_refptr.h" 16 #include "components/sqlite_proto/key_value_data.h" 17 #include "components/sqlite_proto/key_value_table.h" 18 #include "components/sqlite_proto/proto_table_manager.h" 19 #include "components/unexportable_keys/service_error.h" 20 #include "components/unexportable_keys/unexportable_key_id.h" 21 #include "net/base/net_export.h" 22 #include "net/device_bound_sessions/proto/storage.pb.h" 23 #include "net/device_bound_sessions/session_store.h" 24 25 namespace unexportable_keys { 26 class UnexportableKeyService; 27 } 28 29 namespace net::device_bound_sessions { 30 31 // `SessionStoreImpl` implements a persistent store for sessions data. 32 // It uses the sqlite-proto library to store the data in a string-to-proto 33 // SQLite table. The key is a serialized `SchemefulSite` string that 34 // represents an eTLD+1 site. The value is a protobuf of session objects 35 // associated the site. 36 class NET_EXPORT SessionStoreImpl : public SessionStore { 37 public: 38 enum DBStatus { 39 kSuccess, 40 kFailure, 41 kNotLoaded, 42 }; 43 44 // Instantiates a store object. 45 // `db_storage_path` is the path to the underlying SQLite DB file. 46 // `key_service` is used to convert a session binding key to/from 47 // its persistable form. 48 SessionStoreImpl(base::FilePath db_storage_path, 49 unexportable_keys::UnexportableKeyService& key_service); 50 51 SessionStoreImpl(const SessionStoreImpl& other) = delete; 52 SessionStoreImpl& operator=(const SessionStoreImpl& other) = delete; 53 SessionStoreImpl(SessionStoreImpl&& other) = delete; 54 SessionStoreImpl& operator=(SessionStoreImpl&& other) = delete; 55 56 ~SessionStoreImpl() override; 57 58 // SessionStore implementation: 59 void LoadSessions(LoadSessionsCallback callback) override; 60 void SaveSession(const SchemefulSite& site, const Session& session) override; 61 void DeleteSession(const SchemefulSite& site, 62 const Session::Id& session_id) override; 63 SessionsMap GetAllSessions() const override; 64 void RestoreSessionBindingKey( 65 const SchemefulSite& site, 66 const Session::Id& session_id, 67 RestoreSessionBindingKeyCallback callback) override; 68 db_status()69 DBStatus db_status() const { return db_status_; } 70 71 // Allows test to wait until DB shutdown tasks are complete. 72 void SetShutdownCallbackForTesting(base::OnceClosure shutdown_callback); 73 74 private: 75 FRIEND_TEST_ALL_PREFIXES(SessionStoreImplTest, 76 PruneLoadedEntryWithInvalidSite); 77 FRIEND_TEST_ALL_PREFIXES(SessionStoreImplTest, 78 PruneLoadedEntryWithInvalidSession); 79 FRIEND_TEST_ALL_PREFIXES(SessionStoreImplTest, 80 PruneLoadedEntryWithSessionMissingWrappedKey); 81 82 void OnDatabaseLoaded(LoadSessionsCallback callback, DBStatus status); 83 84 // Helper function called by `OnDatabaseLoaded` to prune out any invalid 85 // entries found in the data loaded from disk. Returns a map of valid 86 // session objects that is returned to the caller of `LoadSessions` via 87 // the provided callback. `keys_to_delete` represents the list of invalid 88 // keys that are deleted from the store. 89 static SessionsMap CreateSessionsFromLoadedData( 90 const std::map<std::string, proto::SiteSessions>& loaded_data, 91 std::vector<std::string>& keys_to_delete); 92 93 // Key service used to wrap/unwrap unexportable session keys. 94 const raw_ref<unexportable_keys::UnexportableKeyService> key_service_; 95 96 // Background task runner used to perform DB tasks. 97 scoped_refptr<base::SequencedTaskRunner> db_task_runner_; 98 // Path to the backing database file. 99 base::FilePath db_storage_path_; 100 101 // The following objects are use to work with an SQLite database. 102 //`db_`, `proto_table_manager_` are deleted on the db sequence, 103 // while `session_table_` and `session_data_` are deleted on the 104 // main sequence. 105 std::unique_ptr<sql::Database> db_; 106 scoped_refptr<sqlite_proto::ProtoTableManager> table_manager_; 107 std::unique_ptr<sqlite_proto::KeyValueTable<proto::SiteSessions>> 108 session_table_; 109 // TODO(crbug.com/371556007) : Keeping the `session_data_` around 110 // facilitates DB operations that would otherwise require read+write 111 // operations. However, it does create some redundancy in the cached 112 // data since we also convert the cached data into `Session` objects. 113 // Look into reducing the cached data storage size. 114 std::unique_ptr<sqlite_proto::KeyValueData<proto::SiteSessions>> 115 session_data_; 116 117 DBStatus db_status_ = kNotLoaded; 118 119 // Used only for tests to notify that shutdown tasks are completed on 120 // the DB sequence. 121 base::OnceClosure shutdown_callback_; 122 123 SEQUENCE_CHECKER(sequence_checker_); 124 125 base::WeakPtrFactory<SessionStoreImpl> weak_ptr_factory_{this}; 126 }; 127 128 } // namespace net::device_bound_sessions 129 130 #endif // NET_DEVICE_BOUND_SESSIONS_SESSION_STORE_IMPL_H_ 131