summary refs log tree commit diff
diff options
context:
space:
mode:
authorCH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>2020-06-28 21:01:34 +0530
committerCH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>2020-07-30 22:10:27 +0530
commit6fae36abc404ffb7e6ae29c9edceda5231400f0a (patch)
treebce50b744fd917e393848813d8206668f48bd190
parentError Handling and some fixes (diff)
downloadnheko-6fae36abc404ffb7e6ae29c9edceda5231400f0a.tar.xz
[WIP] Add Caching for users
-rw-r--r--resources/qml/TimelineView.qml18
-rw-r--r--resources/qml/UserProfile.qml11
-rw-r--r--src/Cache.cpp138
-rw-r--r--src/Cache.h17
-rw-r--r--src/CacheCryptoStructs.h30
-rw-r--r--src/Cache_p.h19
-rw-r--r--src/ui/UserProfile.cpp106
-rw-r--r--src/ui/UserProfile.h4
8 files changed, 283 insertions, 60 deletions
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index d9302ed7..3618140a 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -21,6 +21,7 @@ Page {
 	property real highlightHue: colors.highlight.hslHue
 	property real highlightSat: colors.highlight.hslSaturation
 	property real highlightLight: colors.highlight.hslLightness
+	property variant userProfile
 
 	palette: colors
 
@@ -238,6 +239,11 @@ Page {
 				}
 			}
 
+			Component{
+				id: userProfileComponent
+				UserProfile{}
+			}
+
 			section {
 				property: "section"
 			}
@@ -274,8 +280,6 @@ Page {
 						}
 					}
 
-					property variant userProfile
-
 					Row {
 						height: userName.height
 						spacing: 8
@@ -290,9 +294,7 @@ Page {
 							MouseArea {
 								anchors.fill: parent
                                 onClicked: {
-									if(userProfile) userProfile.destroy()
-									var component = Qt.createComponent("UserProfile.qml");
-									userProfile = component.createObject(timelineRoot,{user_data : modelData});
+									userProfile = userProfileComponent.createObject(timelineRoot,{user_data: modelData,avatarUrl:chat.model.avatarUrl(modelData.userId)});
 									userProfile.show();
                                 }
 								cursorShape: Qt.PointingHandCursor
@@ -310,10 +312,8 @@ Page {
 								anchors.fill: parent
 								Layout.alignment: Qt.AlignHCenter
                                 onClicked: {
-									if(userProfile) userProfile.destroy()
-									var component = Qt.createComponent("UserProfile.qml")
-									userProfile = component.createObject(timelineRoot,{user_data : modelData})
-									userProfile.show()
+									userProfile = userProfileComponent.createObject(timelineRoot,{user_data: modelData,avatarUrl:chat.model.avatarUrl(modelData.userId)});
+									userProfile.show();
                                 }
 								cursorShape: Qt.PointingHandCursor
 								propagateComposedEvents: true
diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index 6ef75031..a0b0f993 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -9,6 +9,7 @@ import "./device-verification"
 
 ApplicationWindow{
     property var user_data
+    property var avatarUrl
     property var colors: currentActivePalette
 
     id:userProfileDialog
@@ -52,11 +53,11 @@ ApplicationWindow{
 
             Avatar{
                 id: userProfileAvatar
-                url:chat.model.avatarUrl(user_data.userId).replace("mxc://", "image://MxcImage/")
+                url: avatarUrl.replace("mxc://", "image://MxcImage/")
                 height: 130
                 width: 130
-                displayName: modelData.userName
-		        userid: modelData.userId
+                displayName: user_data.userName
+		        userid: user_data.userId
                 Layout.alignment: Qt.AlignHCenter
                 Layout.margins : {
                     top: 10
@@ -68,7 +69,7 @@ ApplicationWindow{
                 text: user_data.userName
                 fontSizeMode: Text.HorizontalFit
                 font.pixelSize: 20
-                color:TimelineManager.userColor(modelData.userId, colors.window)
+                color:TimelineManager.userColor(user_data.userId, colors.window)
                 font.bold: true
                 Layout.alignment: Qt.AlignHCenter
             }
@@ -207,7 +208,7 @@ ApplicationWindow{
 
                 Layout.margins : {
                     right : 10
-                    bottom : 10
+                    bottom: 5
                 }
 
                 palette {
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 0c692d07..5afeab06 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -2883,6 +2883,115 @@ Cache::statusMessage(const std::string &user_id)
 }
 
 void
+to_json(json &j, const UserCache &info)
+{
+        j["user_id"]          = info.user_id;
+        j["is_user_verified"] = info.is_user_verified;
+        j["cross_verified"]   = info.cross_verified;
+        j["keys"]             = info.keys;
+}
+
+void
+from_json(const json &j, UserCache &info)
+{
+        info.user_id          = j.at("user_id");
+        info.is_user_verified = j.at("is_user_verified");
+        info.cross_verified   = j.at("cross_verified").get<std::vector<std::string>>();
+        info.keys             = j.at("keys").get<mtx::responses::QueryKeys>();
+}
+
+UserCache
+Cache::getUserCache(const std::string &user_id)
+{
+        lmdb::val verifiedVal;
+
+        auto txn = lmdb::txn::begin(env_);
+        auto db  = getUserCacheDb(txn);
+        auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal);
+
+        UserCache verified_state;
+        if (res) {
+                verified_state = json::parse(std::string(verifiedVal.data(), verifiedVal.size()));
+        }
+
+        txn.commit();
+
+        return verified_state;
+}
+
+//! be careful when using make sure is_user_verified is not changed
+int
+Cache::setUserCache(const std::string &user_id, const UserCache &body)
+{
+        auto txn = lmdb::txn::begin(env_);
+        auto db  = getUserCacheDb(txn);
+
+        auto res = lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(body).dump()));
+
+        txn.commit();
+
+        return res;
+}
+
+int
+Cache::deleteUserCache(const std::string &user_id)
+{
+        auto txn = lmdb::txn::begin(env_);
+        auto db  = getUserCacheDb(txn);
+        auto res = lmdb::dbi_del(txn, db, lmdb::val(user_id), nullptr);
+
+        txn.commit();
+
+        return res;
+}
+
+void
+to_json(json &j, const DeviceVerifiedCache &info)
+{
+        j["user_id"]         = info.user_id;
+        j["device_verified"] = info.device_verified;
+}
+
+void
+from_json(const json &j, DeviceVerifiedCache &info)
+{
+        info.user_id         = j.at("user_id");
+        info.device_verified = j.at("device_verified").get<std::vector<std::string>>();
+}
+
+DeviceVerifiedCache
+Cache::getVerifiedCache(const std::string &user_id)
+{
+        lmdb::val verifiedVal;
+
+        auto txn = lmdb::txn::begin(env_);
+        auto db  = getDeviceVerifiedDb(txn);
+        auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal);
+
+        DeviceVerifiedCache verified_state;
+        if (res) {
+                verified_state = json::parse(std::string(verifiedVal.data(), verifiedVal.size()));
+        }
+
+        txn.commit();
+
+        return verified_state;
+}
+
+int
+Cache::setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body)
+{
+        auto txn = lmdb::txn::begin(env_);
+        auto db  = getDeviceVerifiedDb(txn);
+
+        auto res = lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(body).dump()));
+
+        txn.commit();
+
+        return res;
+}
+
+void
 to_json(json &j, const RoomInfo &info)
 {
         j["name"]         = info.name;
@@ -3063,6 +3172,35 @@ statusMessage(const std::string &user_id)
 {
         return instance_->statusMessage(user_id);
 }
+UserCache
+getUserCache(const std::string &user_id)
+{
+        return instance_->getUserCache(user_id);
+}
+
+int
+setUserCache(const std::string &user_id, const UserCache &body)
+{
+        return instance_->setUserCache(user_id, body);
+}
+
+int
+deleteUserCache(const std::string &user_id)
+{
+        return instance_->deleteUserCache(user_id);
+}
+
+DeviceVerifiedCache
+getVerifiedCache(const std::string &user_id)
+{
+        return instance_->getVerifiedCache(user_id);
+}
+
+int
+setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body)
+{
+        return instance_->setVerifiedCache(user_id, body);
+}
 
 //! Load saved data for the display names & avatars.
 void
diff --git a/src/Cache.h b/src/Cache.h
index b5275623..34e79ab5 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -60,6 +60,23 @@ presenceState(const std::string &user_id);
 std::string
 statusMessage(const std::string &user_id);
 
+//! user Cache
+UserCache
+getUserCache(const std::string &user_id);
+
+int
+setUserCache(const std::string &user_id, const UserCache &body);
+
+int
+deleteUserCache(const std::string &user_id);
+
+//! verified Cache
+DeviceVerifiedCache
+getVerifiedCache(const std::string &user_id);
+
+int
+setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body);
+
 //! Load saved data for the display names & avatars.
 void
 populateMembers();
diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h
index 14c9c86b..7344aef9 100644
--- a/src/CacheCryptoStructs.h
+++ b/src/CacheCryptoStructs.h
@@ -65,3 +65,33 @@ struct OlmSessionStorage
         std::mutex group_outbound_mtx;
         std::mutex group_inbound_mtx;
 };
+
+struct UserCache
+{
+        //! user_id of the user
+        std::string user_id;
+        //! this stores if the user is verified (with cross-signing)
+        bool is_user_verified = false;
+        //! list of verified device_ids with cross-signing
+        std::vector<std::string> cross_verified;
+        //! map of public key key_ids and their public_key
+        mtx::responses::QueryKeys keys;
+};
+
+void
+to_json(nlohmann::json &j, const UserCache &info);
+void
+from_json(const nlohmann::json &j, UserCache &info);
+
+struct DeviceVerifiedCache
+{
+        //! user_id of the user
+        std::string user_id;
+        //! list of verified device_ids with device-verification
+        std::vector<std::string> device_verified;
+};
+
+void
+to_json(nlohmann::json &j, const DeviceVerifiedCache &info);
+void
+from_json(const nlohmann::json &j, DeviceVerifiedCache &info);
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 61d91b0c..cf4416ce 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -54,6 +54,15 @@ public:
         mtx::presence::PresenceState presenceState(const std::string &user_id);
         std::string statusMessage(const std::string &user_id);
 
+        // user cache stores user keys
+        UserCache getUserCache(const std::string &user_id);
+        int setUserCache(const std::string &user_id, const UserCache &body);
+        int deleteUserCache(const std::string &user_id);
+
+        // device verified cache
+        DeviceVerifiedCache getVerifiedCache(const std::string &user_id);
+        int setVerifiedCache(const std::string &user_id, const DeviceVerifiedCache &body);
+
         static void removeDisplayName(const QString &room_id, const QString &user_id);
         static void removeAvatarUrl(const QString &room_id, const QString &user_id);
 
@@ -510,6 +519,16 @@ private:
                 return lmdb::dbi::open(txn, "presence", MDB_CREATE);
         }
 
+        lmdb::dbi getUserCacheDb(lmdb::txn &txn)
+        {
+                return lmdb::dbi::open(txn, std::string("user_cache").c_str(), MDB_CREATE);
+        }
+
+        lmdb::dbi getDeviceVerifiedDb(lmdb::txn &txn)
+        {
+                return lmdb::dbi::open(txn, std::string("verified").c_str(), MDB_CREATE);
+        }
+
         //! Retrieves or creates the database that stores the open OLM sessions between our device
         //! and the given curve25519 key which represents another device.
         //!
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 6aa4deff..c637280b 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -1,9 +1,12 @@
 #include "UserProfile.h"
+#include "Cache.h"
 #include "ChatPage.h"
 #include "Logging.h"
 #include "Utils.h"
 #include "mtx/responses/crypto.hpp"
 
+#include <iostream> // only for debugging
+
 UserProfile::UserProfile(QObject *parent)
   : QObject(parent)
 {}
@@ -32,54 +35,65 @@ UserProfile::setUserId(const QString &user_id)
 }
 
 void
-UserProfile::fetchDeviceList(const QString &userID)
+UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
+                         mtx::http::RequestErr err,
+                         std::string user_id)
 {
-        auto localUser = utils::localUser();
-        mtx::requests::QueryKeys req;
-        mtx::responses::QueryKeys res;
-        req.device_keys[userID.toStdString()] = {};
-
-        http::client()->query_keys(
-          req,
-          [user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res,
-                                                 mtx::http::RequestErr err) {
-                  if (err) {
-                          nhlog::net()->warn("failed to query device keys: {},{}",
-                                             err->matrix_error.errcode,
-                                             static_cast<int>(err->status_code));
-                          return;
-                  }
-
-                  if (res.device_keys.empty() ||
-                      (res.device_keys.find(user_id) == res.device_keys.end())) {
-                          nhlog::net()->warn("no devices retrieved {}", user_id);
-                          return;
-                  }
-
-                  auto devices = res.device_keys.at(user_id);
-                  QVector<DeviceInfo> deviceInfo;
-
-                  for (const auto &d : devices) {
-                          auto device = d.second;
-
-                          // TODO: Verify signatures and ignore those that don't pass.
-                          DeviceInfo newdevice(
-                            QString::fromStdString(d.first),
-                            QString::fromStdString(device.unsigned_info.device_display_name));
-                          QString::fromStdString(device.unsigned_info.device_display_name);
-
-                          deviceInfo.append(std::move(newdevice));
-                  }
-
-                  std::sort(deviceInfo.begin(),
-                            deviceInfo.end(),
-                            [](const DeviceInfo &a, const DeviceInfo &b) {
-                                    return a.device_id > b.device_id;
-                            });
-
-                  this->deviceList = std::move(deviceInfo);
-                  emit UserProfile::deviceListUpdated();
+        if (err) {
+                nhlog::net()->warn("failed to query device keys: {},{}",
+                                   err->matrix_error.errcode,
+                                   static_cast<int>(err->status_code));
+                return;
+        }
+
+        if (res.device_keys.empty() || (res.device_keys.find(user_id) == res.device_keys.end())) {
+                nhlog::net()->warn("no devices retrieved {}", user_id);
+                return;
+        }
+
+        auto devices = res.device_keys.at(user_id);
+        QVector<DeviceInfo> deviceInfo;
+
+        for (const auto &d : devices) {
+                auto device = d.second;
+
+                // TODO: Verify signatures and ignore those that don't pass.
+                DeviceInfo newdevice(
+                  QString::fromStdString(d.first),
+                  QString::fromStdString(device.unsigned_info.device_display_name));
+                QString::fromStdString(device.unsigned_info.device_display_name);
+
+                deviceInfo.append(std::move(newdevice));
+        }
+
+        std::sort(
+          deviceInfo.begin(), deviceInfo.end(), [](const DeviceInfo &a, const DeviceInfo &b) {
+                  return a.device_id > b.device_id;
           });
+
+        this->deviceList = std::move(deviceInfo);
+        emit UserProfile::deviceListUpdated();
+}
+
+void
+UserProfile::fetchDeviceList(const QString &userID)
+{
+        auto localUser  = utils::localUser();
+        auto user_cache = cache::getUserCache(userID.toStdString());
+
+        if (user_cache.user_id == userID.toStdString()) {
+                mtx::http::ClientError error;
+                this->callback_fn(user_cache.keys, std::move(error), userID.toStdString());
+        } else {
+                mtx::requests::QueryKeys req;
+                req.device_keys[userID.toStdString()] = {};
+                http::client()->query_keys(
+                  req,
+                  [user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res,
+                                                         mtx::http::RequestErr err) {
+                          this->callback_fn(res, err, user_id);
+                  });
+        }
 }
 
 void
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index ad92d182..befd82ec 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -47,4 +47,8 @@ signals:
 private:
         QVector<DeviceInfo> deviceList;
         QString userId;
+
+        void callback_fn(const mtx::responses::QueryKeys &res,
+                         mtx::http::RequestErr err,
+                         std::string user_id);
 };
\ No newline at end of file