diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ad8a62..2aff991 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,9 +15,6 @@ 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/TimelineView.qml b/resources/qml/TimelineView.qml index ec63487..699efc5 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -106,7 +106,7 @@ Page { } Connections { target: TimelineManager - function onNewDeviceVerificationRequest(flow) { + function onNewDeviceVerificationRequest(flow,transactionId,userId,deviceId) { flow.userId = userId; flow.sender = false; flow.deviceId = deviceId; diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index df54367..5bdccb4 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -17,6 +17,13 @@ ApplicationWindow{ Layout.alignment: Qt.AlignHCenter palette: colors + Connections{ + target: deviceVerificationList + onUpdateProfile: { + profile.fetchDeviceList(profile.userid) + } + } + Component { id: deviceVerificationDialog DeviceVerification {} @@ -139,20 +146,12 @@ ApplicationWindow{ top : 50 } ColumnLayout{ - RowLayout{ - Text{ - Layout.fillWidth: true - color: colors.text - font.bold: true - Layout.alignment: Qt.AlignLeft - text: model.deviceId - } - Text{ - Layout.fillWidth: true - color:colors.text - Layout.alignment: Qt.AlignLeft - text: (model.verificationStatus == VerificationStatus.VERIFIED?"V":(model.verificationStatus == VerificationStatus.UNVERIFIED?"NV":"B")) - } + Text{ + Layout.fillWidth: true + color: colors.text + font.bold: true + Layout.alignment: Qt.AlignLeft + text: model.deviceId } Text{ Layout.fillWidth: true @@ -161,27 +160,41 @@ ApplicationWindow{ text: model.deviceName } } - Button{ - id: verifyButton - text:"Verify" - onClicked: { - var newFlow = deviceVerificationFlow.createObject(userProfileDialog, - {userId : profile.userid, sender: true, deviceId : model.deviceID}); - deviceVerificationList.add(newFlow.tranId); - var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow}); - dialog.show(); + RowLayout{ + Image{ + Layout.preferredWidth: 20 + Layout.preferredHeight: 20 + source: ((model.verificationStatus == VerificationStatus.VERIFIED)?"image://colorimage/:/icons/icons/ui/lock.png?green": + ((model.verificationStatus == VerificationStatus.UNVERIFIED)?"image://colorimage/:/icons/icons/ui/unlock.png?yellow": + "image://colorimage/:/icons/icons/ui/unlock.png?red")) } - Layout.margins:{ - right: 10 - } - palette { - button: "white" - } - contentItem: Text { - text: verifyButton.text - color: "black" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + Button{ + id: verifyButton + text:(model.verificationStatus != VerificationStatus.VERIFIED)?"Verify":"Unverify" + onClicked: { + var newFlow = deviceVerificationFlow.createObject(userProfileDialog, + {userId : profile.userid, sender: true, deviceId : model.deviceId}); + if(model.verificationStatus == VerificationStatus.VERIFIED){ + newFlow.unverify(); + deviceVerificationList.updateProfile(newFlow.userId); + }else{ + deviceVerificationList.add(newFlow.tranId); + var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow}); + dialog.show(); + } + } + Layout.margins:{ + right: 10 + } + palette { + button: "white" + } + contentItem: Text { + text: verifyButton.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } } } } diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 15c2d7a..4d734a6 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -33,6 +33,10 @@ ApplicationWindow { case DeviceVerificationFlow.Decimal: stack.replace(digitVerification); break; case DeviceVerificationFlow.Emoji: stack.replace(emojiVerification); break; } + + onRefreshProfile: { + deviceVerificationList.updateProfile(flow.userId); + } } Component { diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index b5134a3..7829c41 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -1,4 +1,5 @@ #include "DeviceVerificationFlow.h" +#include "Cache.h" #include "ChatPage.h" #include "Logging.h" @@ -181,9 +182,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) // uncomment this in future to be compatible with the // MSC2366 this->sendVerificationDone(); and remove the // below line - if (this->isMacVerified == true) - emit this->deviceVerified(); - else + if (this->isMacVerified == true) { + this->acceptDevice(); + } else this->isMacVerified = true; } else { this->cancelVerification( @@ -208,7 +209,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - emit this->deviceVerified(); + this->acceptDevice(); } }); timeout->start(TIMEOUT); @@ -259,36 +260,22 @@ DeviceVerificationFlow::setTransactionId(QString transaction_id_) void DeviceVerificationFlow::setUserId(QString userID) { - this->userId = userID; - this->toClient = mtx::identifiers::parse(userID.toStdString()); - - mtx::responses::QueryKeys res; - 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) { - if (err) { - nhlog::net()->warn("failed to query device keys: {},{}", - err->matrix_error.errcode, - static_cast(err->status_code)); - return; - } - - for (auto x : res.device_keys) { - for (auto y : x.second) { - auto z = y.second; - if (z.user_id == user_id && - z.device_id == this->deviceId.toStdString()) { - for (auto a : z.keys) { - // TODO: Verify Signatures - this->device_keys[a.first] = a.second; - } - } - } - } - }); + this->userId = userID; + this->toClient = mtx::identifiers::parse(userID.toStdString()); + auto user_cache = cache::getUserCache(userID.toStdString()); + + if (user_cache.has_value()) { + this->callback_fn(user_cache->keys, {}, 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 @@ -482,6 +469,16 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c nhlog::net()->warn("failed to cancel verification request: {} {}", err->matrix_error.error, static_cast(err->status_code)); + auto verified_cache = cache::getVerifiedCache(this->userId.toStdString()); + if (verified_cache.has_value()) { + verified_cache->device_blocked.push_back(this->deviceId.toStdString()); + cache::setVerifiedCache(this->userId.toStdString(), + verified_cache.value()); + } else { + cache::setVerifiedCache( + this->userId.toStdString(), + DeviceVerifiedCache{{}, {this->deviceId.toStdString()}}); + } this->deleteLater(); }); } @@ -546,7 +543,7 @@ DeviceVerificationFlow::sendVerificationMac() static_cast(err->status_code)); if (this->isMacVerified == true) - emit this->deviceVerified(); + this->acceptDevice(); else this->isMacVerified = true; }); @@ -555,8 +552,69 @@ DeviceVerificationFlow::sendVerificationMac() void DeviceVerificationFlow::acceptDevice() { + auto verified_cache = cache::getVerifiedCache(this->userId.toStdString()); + if (verified_cache.has_value()) { + verified_cache->device_verified.push_back(this->deviceId.toStdString()); + for (auto it = verified_cache->device_blocked.begin(); + it != verified_cache->device_blocked.end(); + it++) { + if (*it == this->deviceId.toStdString()) { + verified_cache->device_blocked.erase(it); + } + } + cache::setVerifiedCache(this->userId.toStdString(), verified_cache.value()); + } else { + cache::setVerifiedCache(this->userId.toStdString(), + DeviceVerifiedCache{{this->deviceId.toStdString()}, {}}); + } + emit deviceVerified(); + emit refreshProfile(); this->deleteLater(); +} +//! callback function to keep track of devices +void +DeviceVerificationFlow::callback_fn(const mtx::responses::QueryKeys &res, + mtx::http::RequestErr err, + std::string user_id) +{ + if (err) { + nhlog::net()->warn("failed to query device keys: {},{}", + err->matrix_error.errcode, + static_cast(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; + } - // Yet to add send to_device message + for (auto x : res.device_keys) { + for (auto y : x.second) { + auto z = y.second; + if (z.user_id == user_id && z.device_id == this->deviceId.toStdString()) { + for (auto a : z.keys) { + // TODO: Verify Signatures + this->device_keys[a.first] = a.second; + } + } + } + } +} + +void +DeviceVerificationFlow::unverify() +{ + auto verified_cache = cache::getVerifiedCache(this->userId.toStdString()); + if (verified_cache.has_value()) { + auto it = std::remove(verified_cache->device_verified.begin(), + verified_cache->device_verified.end(), + this->deviceId.toStdString()); + verified_cache->device_verified.erase(it); + cache::setVerifiedCache(this->userId.toStdString(), verified_cache.value()); + } + + emit refreshProfile(); + this->deleteLater(); } diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index 891c6ae..edff7c8 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -51,6 +51,9 @@ public: void setDeviceId(QString deviceID); void setMethod(Method method_); void setSender(bool sender_); + void callback_fn(const mtx::responses::QueryKeys &res, + mtx::http::RequestErr err, + std::string user_id); nlohmann::json canonical_json; @@ -73,12 +76,15 @@ public slots: void sendVerificationMac(); //! Completes the verification flow void acceptDevice(); + //! unverifies a device + void unverify(); signals: void verificationRequestAccepted(Method method); void deviceVerified(); void timedout(); void verificationCanceled(); + void refreshProfile(); private: QString userId; diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index af8bc4b..a438ef5 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -29,6 +29,8 @@ public: Q_INVOKABLE void add(QString tran_id); Q_INVOKABLE void remove(QString tran_id); Q_INVOKABLE bool exist(QString tran_id); +signals: + void updateProfile(QString userId); private: QVector deviceVerificationList; diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index fde0044..b4938e8 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -1,6 +1,7 @@ #include "UserProfile.h" #include "Cache.h" #include "ChatPage.h" +#include "DeviceVerificationFlow.h" #include "Logging.h" #include "Utils.h" #include "mtx/responses/crypto.hpp" @@ -122,10 +123,10 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res, 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_.queueReset(std::move(deviceInfo)); } @@ -176,4 +177,4 @@ UserProfile::startChat() if (utils::localUser() != this->userid_) req.invite = {this->userid_.toStdString()}; emit ChatPage::instance()->createRoom(req); -} +} \ No newline at end of file diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index 38002ff..99c6a75 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -19,6 +19,8 @@ enum Status Q_ENUM_NS(Status) } +class DeviceVerificationFlow; + class DeviceInfo { public: @@ -88,7 +90,7 @@ public: QString displayName(); QString avatarUrl(); - void fetchDeviceList(const QString &userID); + Q_INVOKABLE void fetchDeviceList(const QString &userID); Q_INVOKABLE void banUser(); // Q_INVOKABLE void ignoreUser(); Q_INVOKABLE void kickUser();