summary refs log tree commit diff
path: root/src/Cache.cc
diff options
context:
space:
mode:
authorKonstantinos Sideris <sideris.konstantin@gmail.com>2018-06-10 20:03:45 +0300
committerKonstantinos Sideris <sideris.konstantin@gmail.com>2018-06-10 20:03:45 +0300
commit626c68091126f84819091840a011c50e26dcbd8d (patch)
tree132afdb12f858a6a2a20e00e0c2a0417caf4ae13 /src/Cache.cc
parentMigrate to mtxclient for the http calls (diff)
downloadnheko-626c68091126f84819091840a011c50e26dcbd8d.tar.xz
Add support for displaying decrypted messages
Diffstat (limited to 'src/Cache.cc')
-rw-r--r--src/Cache.cc250
1 files changed, 242 insertions, 8 deletions
diff --git a/src/Cache.cc b/src/Cache.cc

index 2a555425..150990b7 100644 --- a/src/Cache.cc +++ b/src/Cache.cc
@@ -31,25 +31,42 @@ //! Should be changed when a breaking change occurs in the cache format. //! This will reset client's data. -static const std::string CURRENT_CACHE_FORMAT_VERSION("2018.05.11"); +static const std::string CURRENT_CACHE_FORMAT_VERSION("2018.06.10"); +static const std::string SECRET("secret"); static const lmdb::val NEXT_BATCH_KEY("next_batch"); +static const lmdb::val OLM_ACCOUNT_KEY("olm_account"); static const lmdb::val CACHE_FORMAT_VERSION_KEY("cache_format_version"); //! Cache databases and their format. //! //! Contains UI information for the joined rooms. (i.e name, topic, avatar url etc). //! Format: room_id -> RoomInfo -static constexpr const char *ROOMS_DB = "rooms"; -static constexpr const char *INVITES_DB = "invites"; +constexpr auto ROOMS_DB("rooms"); +constexpr auto INVITES_DB("invites"); //! Keeps already downloaded media for reuse. //! Format: matrix_url -> binary data. -static constexpr const char *MEDIA_DB = "media"; +constexpr auto MEDIA_DB("media"); //! Information that must be kept between sync requests. -static constexpr const char *SYNC_STATE_DB = "sync_state"; +constexpr auto SYNC_STATE_DB("sync_state"); //! Read receipts per room/event. -static constexpr const char *READ_RECEIPTS_DB = "read_receipts"; -static constexpr const char *NOTIFICATIONS_DB = "sent_notifications"; +constexpr auto READ_RECEIPTS_DB("read_receipts"); +constexpr auto NOTIFICATIONS_DB("sent_notifications"); + +//! Encryption related databases. + +//! user_id -> list of devices +constexpr auto DEVICES_DB("devices"); +//! device_id -> device keys +constexpr auto DEVICE_KEYS_DB("device_keys"); +//! room_ids that have encryption enabled. +// constexpr auto ENCRYPTED_ROOMS_DB("encrypted_rooms"); + +//! MegolmSessionIndex -> pickled OlmInboundGroupSession +constexpr auto INBOUND_MEGOLM_SESSIONS_DB("inbound_megolm_sessions"); +//! MegolmSessionIndex -> pickled OlmOutboundGroupSession +constexpr auto OUTBOUND_MEGOLM_SESSIONS_DB("outbound_megolm_sessions"); +constexpr auto OUTBOUND_OLM_SESSIONS_DB("outbound_olm_sessions"); using CachedReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>; using Receipts = std::map<std::string, std::map<std::string, uint64_t>>; @@ -79,7 +96,7 @@ client() { return instance_.get(); } -} +} // namespace cache Cache::Cache(const QString &userId, QObject *parent) : QObject{parent} @@ -90,6 +107,11 @@ Cache::Cache(const QString &userId, QObject *parent) , mediaDb_{0} , readReceiptsDb_{0} , notificationsDb_{0} + , devicesDb_{0} + , deviceKeysDb_{0} + , inboundMegolmSessionDb_{0} + , outboundMegolmSessionDb_{0} + , outboundOlmSessionDb_{0} , localUserId_{userId} {} @@ -149,9 +171,221 @@ Cache::setup() mediaDb_ = lmdb::dbi::open(txn, MEDIA_DB, MDB_CREATE); readReceiptsDb_ = lmdb::dbi::open(txn, READ_RECEIPTS_DB, MDB_CREATE); notificationsDb_ = lmdb::dbi::open(txn, NOTIFICATIONS_DB, MDB_CREATE); + + // Device management + devicesDb_ = lmdb::dbi::open(txn, DEVICES_DB, MDB_CREATE); + deviceKeysDb_ = lmdb::dbi::open(txn, DEVICE_KEYS_DB, MDB_CREATE); + + // Session management + inboundMegolmSessionDb_ = lmdb::dbi::open(txn, INBOUND_MEGOLM_SESSIONS_DB, MDB_CREATE); + outboundMegolmSessionDb_ = lmdb::dbi::open(txn, OUTBOUND_MEGOLM_SESSIONS_DB, MDB_CREATE); + outboundOlmSessionDb_ = lmdb::dbi::open(txn, OUTBOUND_OLM_SESSIONS_DB, MDB_CREATE); + + txn.commit(); +} + +// +// Device Management +// + +// +// Session Management +// + +void +Cache::saveInboundMegolmSession(const MegolmSessionIndex &index, + mtx::crypto::InboundGroupSessionPtr session) +{ + using namespace mtx::crypto; + const auto key = index.to_hash(); + const auto pickled = pickle<InboundSessionObject>(session.get(), SECRET); + + auto txn = lmdb::txn::begin(env_); + lmdb::dbi_put(txn, inboundMegolmSessionDb_, lmdb::val(key), lmdb::val(pickled)); + txn.commit(); + + { + std::unique_lock<std::mutex> lock(session_storage.group_inbound_mtx); + session_storage.group_inbound_sessions[key] = std::move(session); + } +} + +OlmInboundGroupSession * +Cache::getInboundMegolmSession(const MegolmSessionIndex &index) +{ + std::unique_lock<std::mutex> lock(session_storage.group_inbound_mtx); + return session_storage.group_inbound_sessions[index.to_hash()].get(); +} + +bool +Cache::inboundMegolmSessionExists(const MegolmSessionIndex &index) noexcept +{ + std::unique_lock<std::mutex> lock(session_storage.group_inbound_mtx); + return session_storage.group_inbound_sessions.find(index.to_hash()) != + session_storage.group_inbound_sessions.end(); +} + +void +Cache::saveOutboundMegolmSession(const MegolmSessionIndex &index, + const OutboundGroupSessionData &data, + mtx::crypto::OutboundGroupSessionPtr session) +{ + using namespace mtx::crypto; + const auto key = index.to_hash(); + const auto pickled = pickle<OutboundSessionObject>(session.get(), SECRET); + + json j; + j["data"] = data; + j["session"] = pickled; + + auto txn = lmdb::txn::begin(env_); + lmdb::dbi_put(txn, outboundMegolmSessionDb_, lmdb::val(key), lmdb::val(j.dump())); txn.commit(); + + { + std::unique_lock<std::mutex> lock(session_storage.group_outbound_mtx); + session_storage.group_outbound_session_data[key] = data; + session_storage.group_outbound_sessions[key] = std::move(session); + } } +bool +Cache::outboundMegolmSessionExists(const MegolmSessionIndex &index) noexcept +{ + const auto key = index.to_hash(); + + std::unique_lock<std::mutex> lock(session_storage.group_outbound_mtx); + return (session_storage.group_outbound_sessions.find(key) != + session_storage.group_outbound_sessions.end()) && + (session_storage.group_outbound_session_data.find(key) != + session_storage.group_outbound_session_data.end()); +} + +OutboundGroupSessionDataRef +Cache::getOutboundMegolmSession(const MegolmSessionIndex &index) +{ + const auto key = index.to_hash(); + std::unique_lock<std::mutex> lock(session_storage.group_outbound_mtx); + return OutboundGroupSessionDataRef{session_storage.group_outbound_sessions[key].get(), + session_storage.group_outbound_session_data[key]}; +} + +void +Cache::saveOutboundOlmSession(const std::string &curve25519, mtx::crypto::OlmSessionPtr session) +{ + using namespace mtx::crypto; + const auto pickled = pickle<SessionObject>(session.get(), SECRET); + + auto txn = lmdb::txn::begin(env_); + lmdb::dbi_put(txn, outboundMegolmSessionDb_, lmdb::val(curve25519), lmdb::val(pickled)); + txn.commit(); + + { + std::unique_lock<std::mutex> lock(session_storage.outbound_mtx); + session_storage.outbound_sessions[curve25519] = std::move(session); + } +} + +bool +Cache::outboundOlmSessionsExists(const std::string &curve25519) noexcept +{ + std::unique_lock<std::mutex> lock(session_storage.outbound_mtx); + return session_storage.outbound_sessions.find(curve25519) != + session_storage.outbound_sessions.end(); +} + +OlmSession * +Cache::getOutboundOlmSession(const std::string &curve25519) +{ + std::unique_lock<std::mutex> lock(session_storage.outbound_mtx); + return session_storage.outbound_sessions.at(curve25519).get(); +} + +void +Cache::saveOlmAccount(const std::string &data) +{ + auto txn = lmdb::txn::begin(env_); + lmdb::dbi_put(txn, syncStateDb_, OLM_ACCOUNT_KEY, lmdb::val(data)); + txn.commit(); +} + +void +Cache::restoreSessions() +{ + using namespace mtx::crypto; + + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + std::string key, value; + + // + // Inbound Megolm Sessions + // + { + auto cursor = lmdb::cursor::open(txn, inboundMegolmSessionDb_); + while (cursor.get(key, value, MDB_NEXT)) { + auto session = unpickle<InboundSessionObject>(value, SECRET); + session_storage.group_inbound_sessions[key] = std::move(session); + } + cursor.close(); + } + + // + // Outbound Megolm Sessions + // + { + auto cursor = lmdb::cursor::open(txn, outboundMegolmSessionDb_); + while (cursor.get(key, value, MDB_NEXT)) { + json obj; + + try { + obj = json::parse(value); + + session_storage.group_outbound_session_data[key] = + obj.at("data").get<OutboundGroupSessionData>(); + + auto session = + unpickle<OutboundSessionObject>(obj.at("session"), SECRET); + session_storage.group_outbound_sessions[key] = std::move(session); + } catch (const nlohmann::json::exception &e) { + log::db()->warn("failed to parse outbound megolm session data: {}", + e.what()); + } + } + cursor.close(); + } + + // + // Outbound Olm Sessions + // + { + auto cursor = lmdb::cursor::open(txn, outboundOlmSessionDb_); + while (cursor.get(key, value, MDB_NEXT)) { + auto session = unpickle<SessionObject>(value, SECRET); + session_storage.outbound_sessions[key] = std::move(session); + } + cursor.close(); + } + + txn.commit(); + + log::db()->info("sessions restored"); +} + +std::string +Cache::restoreOlmAccount() +{ + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + lmdb::val pickled; + lmdb::dbi_get(txn, syncStateDb_, OLM_ACCOUNT_KEY, pickled); + txn.commit(); + + return std::string(pickled.data(), pickled.size()); +} + +// +// Media Management +// + void Cache::saveImage(const std::string &url, const std::string &img_data) {