diff --git a/CMakeLists.txt b/CMakeLists.txt index d71ba001c..f69b98e93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,9 @@ set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard") set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Require C++ standard to be supported") set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "compile as PIC by default") +# set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") +# set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") + option(HUNTER_ENABLED "Enable Hunter package manager" OFF) include("cmake/HunterGate.cmake") HunterGate( diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index a0b0f9936..db44ec159 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -19,17 +19,6 @@ ApplicationWindow{ Layout.alignment: Qt.AlignHCenter palette: colors - UserProfileList{ - id: userProfileList - userId: user_data.userId - onUserIdChanged : { - userProfileList.updateDeviceList() - } - onDeviceListUpdated : { - modelDeviceList.deviceList = userProfileList - } - } - Component { id: deviceVerificationDialog DeviceVerification {} @@ -94,7 +83,7 @@ ApplicationWindow{ ToolTip.visible: hovered ToolTip.text: qsTr("Ban the user") onClicked : { - userProfileList.banUser() + modelDeviceList.deviceList.banUser() } } // ImageButton{ @@ -106,7 +95,7 @@ ApplicationWindow{ // ToolTip.visible: hovered // ToolTip.text: qsTr("Ignore messages from this user") // onClicked : { - // userProfileList.ignoreUser() + // modelDeviceList.deviceList.ignoreUser() // } // } ImageButton{ @@ -118,7 +107,7 @@ ApplicationWindow{ ToolTip.visible: hovered ToolTip.text: qsTr("Start a private chat") onClicked : { - userProfileList.startChat() + modelDeviceList.deviceList.startChat() } } ImageButton{ @@ -130,7 +119,7 @@ ApplicationWindow{ ToolTip.visible: hovered ToolTip.text: qsTr("Kick the user") onClicked : { - userProfileList.kickUser() + modelDeviceList.deviceList.kickUser() } } } @@ -142,14 +131,15 @@ ApplicationWindow{ Layout.alignment: Qt.AlignHCenter ListView{ - id: deviceList + id: devicelist anchors.fill: parent clip: true spacing: 4 model: UserProfileModel{ id: modelDeviceList - } + deviceList.userId : user_data.userId + } delegate: RowLayout{ width: parent.width @@ -157,12 +147,20 @@ ApplicationWindow{ top : 50 } ColumnLayout{ - Text{ - Layout.fillWidth: true - color: colors.text - font.bold: true - Layout.alignment: Qt.AlignRight - text: deviceID + RowLayout{ + Text{ + Layout.fillWidth: true + color: colors.text + font.bold: true + Layout.alignment: Qt.AlignLeft + text: deviceID + } + Text{ + Layout.fillWidth: true + color:colors.text + Layout.alignment: Qt.AlignLeft + text: (verified_status == UserProfileList.VERIFIED?"V":(verified_status == UserProfileList.UNVERIFIED?"NV":"B")) + } } Text{ Layout.fillWidth: true diff --git a/src/Cache.cpp b/src/Cache.cpp index d89973769..5761cfe12 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -2318,7 +2318,6 @@ 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; @@ -2327,13 +2326,12 @@ to_json(json &j, const UserCache &info) 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>(); info.keys = j.at("keys").get(); } -UserCache +std::optional Cache::getUserCache(const std::string &user_id) { lmdb::val verifiedVal; @@ -2342,14 +2340,15 @@ Cache::getUserCache(const std::string &user_id) auto db = getUserCacheDb(txn); auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal); + txn.commit(); + UserCache verified_state; if (res) { verified_state = json::parse(std::string(verifiedVal.data(), verifiedVal.size())); + return verified_state; + } else { + return {}; } - - txn.commit(); - - return verified_state; } //! be careful when using make sure is_user_verified is not changed @@ -2381,18 +2380,18 @@ Cache::deleteUserCache(const std::string &user_id) void to_json(json &j, const DeviceVerifiedCache &info) { - j["user_id"] = info.user_id; j["device_verified"] = info.device_verified; + j["device_blocked"] = info.device_blocked; } void from_json(const json &j, DeviceVerifiedCache &info) { - info.user_id = j.at("user_id"); info.device_verified = j.at("device_verified").get>(); + info.device_blocked = j.at("device_blocked").get>(); } -DeviceVerifiedCache +std::optional Cache::getVerifiedCache(const std::string &user_id) { lmdb::val verifiedVal; @@ -2401,14 +2400,15 @@ Cache::getVerifiedCache(const std::string &user_id) auto db = getDeviceVerifiedDb(txn); auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal); + txn.commit(); + DeviceVerifiedCache verified_state; if (res) { verified_state = json::parse(std::string(verifiedVal.data(), verifiedVal.size())); + return verified_state; + } else { + return {}; } - - txn.commit(); - - return verified_state; } int @@ -2605,7 +2605,7 @@ statusMessage(const std::string &user_id) { return instance_->statusMessage(user_id); } -UserCache +std::optional getUserCache(const std::string &user_id) { return instance_->getUserCache(user_id); @@ -2623,7 +2623,7 @@ deleteUserCache(const std::string &user_id) return instance_->deleteUserCache(user_id); } -DeviceVerifiedCache +std::optional getVerifiedCache(const std::string &user_id) { return instance_->getVerifiedCache(user_id); diff --git a/src/Cache.h b/src/Cache.h index 34e79ab57..0c955c926 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -61,7 +61,7 @@ std::string statusMessage(const std::string &user_id); //! user Cache -UserCache +std::optional getUserCache(const std::string &user_id); int @@ -71,7 +71,7 @@ int deleteUserCache(const std::string &user_id); //! verified Cache -DeviceVerifiedCache +std::optional getVerifiedCache(const std::string &user_id); int diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h index 7344aef97..241cac764 100644 --- a/src/CacheCryptoStructs.h +++ b/src/CacheCryptoStructs.h @@ -68,8 +68,6 @@ struct OlmSessionStorage 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 @@ -85,10 +83,9 @@ 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 device_verified; + std::vector device_blocked; }; void diff --git a/src/Cache_p.h b/src/Cache_p.h index fdc9ff860..4af332200 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -57,12 +57,12 @@ class Cache : public QObject std::string statusMessage(const std::string &user_id); // user cache stores user keys - UserCache getUserCache(const std::string &user_id); + std::optional 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); + std::optional 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); diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index c637280b8..8c6fb8e40 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -7,11 +7,25 @@ #include // only for debugging +Q_DECLARE_METATYPE(UserProfile::Status) + UserProfile::UserProfile(QObject *parent) : QObject(parent) -{} +{ + qRegisterMetaType(); + connect( + this, &UserProfile::updateDeviceList, this, [this]() { fetchDeviceList(this->userId); }); + connect( + this, + &UserProfile::appendDeviceList, + this, + [this](QString device_id, QString device_name, UserProfile::Status verification_status) { + this->deviceList.push_back( + DeviceInfo{device_id, device_name, verification_status}); + }); +} -QVector +std::vector UserProfile::getDeviceList() { return this->deviceList; @@ -37,7 +51,8 @@ UserProfile::setUserId(const QString &user_id) void UserProfile::callback_fn(const mtx::responses::QueryKeys &res, mtx::http::RequestErr err, - std::string user_id) + std::string user_id, + std::optional> cross_verified) { if (err) { nhlog::net()->warn("failed to query device keys: {},{}", @@ -52,24 +67,40 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res, } auto devices = res.device_keys.at(user_id); - QVector deviceInfo; + std::vector deviceInfo; + auto device_verified = cache::getVerifiedCache(user_id); for (const auto &d : devices) { auto device = d.second; // TODO: Verify signatures and ignore those that don't pass. - DeviceInfo newdevice( + UserProfile::Status verified = UserProfile::Status::UNVERIFIED; + if (cross_verified.has_value()) { + if (std::find(cross_verified->begin(), cross_verified->end(), d.first) != + cross_verified->end()) + verified = UserProfile::Status::VERIFIED; + } else if (device_verified.has_value()) { + if (std::find(device_verified->device_verified.begin(), + device_verified->device_verified.end(), + d.first) != device_verified->device_verified.end()) + verified = UserProfile::Status::VERIFIED; + } else if (device_verified.has_value()) { + if (std::find(device_verified->device_blocked.begin(), + device_verified->device_blocked.end(), + d.first) != device_verified->device_blocked.end()) + verified = UserProfile::Status::BLOCKED; + } + + emit UserProfile::appendDeviceList( 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)); + QString::fromStdString(device.unsigned_info.device_display_name), + verified); } - std::sort( - deviceInfo.begin(), deviceInfo.end(), [](const DeviceInfo &a, const DeviceInfo &b) { - return a.device_id > b.device_id; - }); + // 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(); @@ -81,9 +112,9 @@ 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()); + if (user_cache.has_value()) { + this->callback_fn( + user_cache->keys, {}, userID.toStdString(), user_cache->cross_verified); } else { mtx::requests::QueryKeys req; req.device_keys[userID.toStdString()] = {}; @@ -91,17 +122,11 @@ UserProfile::fetchDeviceList(const QString &userID) req, [user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res, mtx::http::RequestErr err) { - this->callback_fn(res, err, user_id); + this->callback_fn(res, err, user_id, {}); }); } } -void -UserProfile::updateDeviceList() -{ - fetchDeviceList(this->userId); -} - void UserProfile::banUser() { diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index befd82ec7..1725b961b 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -5,36 +5,32 @@ #include #include "MatrixClient.h" -class DeviceInfo -{ -public: - DeviceInfo(const QString deviceID, const QString displayName) - : device_id(deviceID) - , display_name(displayName) - {} - DeviceInfo() {} - - QString device_id; - QString display_name; -}; +class DeviceInfo; class UserProfile : public QObject { Q_OBJECT Q_PROPERTY(QString userId READ getUserId WRITE setUserId NOTIFY userIdChanged) - Q_PROPERTY(QVector deviceList READ getDeviceList NOTIFY deviceListUpdated) + Q_PROPERTY(std::vector deviceList READ getDeviceList NOTIFY deviceListUpdated) public: // constructor explicit UserProfile(QObject *parent = 0); // getters - QVector getDeviceList(); + std::vector getDeviceList(); QString getUserId(); // setters void setUserId(const QString &userId); - Q_INVOKABLE void fetchDeviceList(const QString &userID); - Q_INVOKABLE void updateDeviceList(); + enum Status + { + VERIFIED, + UNVERIFIED, + BLOCKED + }; + Q_ENUM(Status) + + void fetchDeviceList(const QString &userID); Q_INVOKABLE void banUser(); // Q_INVOKABLE void ignoreUser(); Q_INVOKABLE void kickUser(); @@ -43,12 +39,34 @@ class UserProfile : public QObject signals: void userIdChanged(); void deviceListUpdated(); + void updateDeviceList(); + void appendDeviceList(const QString device_id, + const QString device_naem, + const UserProfile::Status verification_status); private: - QVector deviceList; + std::vector deviceList; QString userId; + std::optional cross_verified; void callback_fn(const mtx::responses::QueryKeys &res, mtx::http::RequestErr err, - std::string user_id); + std::string user_id, + std::optional> cross_verified); +}; + +class DeviceInfo +{ +public: + DeviceInfo(const QString deviceID, + const QString displayName, + UserProfile::Status verification_status_) + : device_id(deviceID) + , display_name(displayName) + , verification_status(verification_status_) + {} + + QString device_id; + QString display_name; + UserProfile::Status verification_status; }; \ No newline at end of file diff --git a/src/ui/UserProfileModel.cpp b/src/ui/UserProfileModel.cpp index ec0456cd9..3fa8fe2d8 100644 --- a/src/ui/UserProfileModel.cpp +++ b/src/ui/UserProfileModel.cpp @@ -1,11 +1,23 @@ #include "UserProfileModel.h" -#include "UserProfile.h" #include UserProfileModel::UserProfileModel(QObject *parent) : QAbstractListModel(parent) , deviceList(nullptr) -{} +{ + this->deviceList = new UserProfile(this); + + connect(this->deviceList, &UserProfile::userIdChanged, this, [this]() { + emit this->deviceList->updateDeviceList(); + }); + connect(this->deviceList, &UserProfile::deviceListUpdated, this, [this]() { + beginResetModel(); + this->beginInsertRows( + QModelIndex(), 0, this->deviceList->getDeviceList().size() - 1); + this->endInsertRows(); + endResetModel(); + }); +} int UserProfileModel::rowCount(const QModelIndex &parent) const @@ -18,7 +30,8 @@ UserProfileModel::rowCount(const QModelIndex &parent) const QVariant UserProfileModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || !this->deviceList) + if (!index.isValid() && + static_cast(this->deviceList->getDeviceList().size()) <= index.row()) return QVariant(); const DeviceInfo device = this->deviceList->getDeviceList().at(index.row()); @@ -27,6 +40,8 @@ UserProfileModel::data(const QModelIndex &index, int role) const return QVariant(device.device_id); case DISPLAYNAME: return QVariant(device.display_name); + case VERIFIED_STATUS: + return device.verification_status; } return QVariant(); } @@ -35,8 +50,9 @@ QHash UserProfileModel::roleNames() const { QHash names; - names[DEVICEID] = "deviceID"; - names[DISPLAYNAME] = "displayName"; + names[DEVICEID] = "deviceID"; + names[DISPLAYNAME] = "displayName"; + names[VERIFIED_STATUS] = "verified_status"; return names; } @@ -45,22 +61,3 @@ UserProfileModel::getList() const { return (this->deviceList); } - -void -UserProfileModel::setList(UserProfile *devices) -{ - beginResetModel(); - - if (devices) - devices->disconnect(this); - - if (this->deviceList) { - const int index = this->deviceList->getDeviceList().size(); - beginInsertRows(QModelIndex(), index, index); - endInsertRows(); - } - - this->deviceList = devices; - - endResetModel(); -} \ No newline at end of file diff --git a/src/ui/UserProfileModel.h b/src/ui/UserProfileModel.h index c21a806dd..ba7a25255 100644 --- a/src/ui/UserProfileModel.h +++ b/src/ui/UserProfileModel.h @@ -1,5 +1,6 @@ #pragma once +#include "UserProfile.h" #include class UserProfile; // forward declaration of the class UserProfile @@ -7,7 +8,7 @@ class UserProfile; // forward declaration of the class UserProfile class UserProfileModel : public QAbstractListModel { Q_OBJECT - Q_PROPERTY(UserProfile *deviceList READ getList WRITE setList) + Q_PROPERTY(UserProfile *deviceList READ getList) public: explicit UserProfileModel(QObject *parent = nullptr); @@ -15,10 +16,10 @@ class UserProfileModel : public QAbstractListModel enum { DEVICEID, - DISPLAYNAME + DISPLAYNAME, + VERIFIED_STATUS }; UserProfile *getList() const; - void setList(UserProfile *devices); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override;