From 3635c185e93a6f7bf6e2f9c11b27966c2ee665ea Mon Sep 17 00:00:00 2001 From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com> Date: Wed, 29 Jul 2020 03:25:47 +0530 Subject: [PATCH] Add Room Verification Messages --- resources/qml/TimelineView.qml | 15 +- .../DeviceVerification.qml | 7 +- src/ChatPage.h | 4 + src/DeviceVerificationFlow.cpp | 56 +++++-- src/DeviceVerificationFlow.h | 22 ++- src/timeline/TimelineModel.cpp | 145 +++++++++++++++--- src/timeline/TimelineModel.h | 5 + src/timeline/TimelineViewManager.cpp | 37 ++++- src/timeline/TimelineViewManager.h | 3 +- 9 files changed, 245 insertions(+), 49 deletions(-) diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 699efc54..c6fc3851 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -106,13 +106,20 @@ Page { } Connections { target: TimelineManager - function onNewDeviceVerificationRequest(flow,transactionId,userId,deviceId) { + function onNewDeviceVerificationRequest(flow,transactionId,userId,deviceId,isRequest) { flow.userId = userId; flow.sender = false; flow.deviceId = deviceId; - flow.tranId = transactionId; - deviceVerificationList.add(flow.tranId); - var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow}); + switch(flow.type){ + case DeviceVerificationFlow.ToDevice: + flow.tranId = transactionId; + deviceVerificationList.add(flow.tranId); + break; + case DeviceVerificationFlow.RoomMsg: + deviceVerificationList.add(flow.tranId); + break; + } + var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow,isRequest = isRequest}); dialog.show(); } } diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 4d734a68..8e74d1cb 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -23,6 +23,8 @@ ApplicationWindow { } property var flow + property bool isRequest + Connections { target: flow onVerificationCanceled: stack.replace(partnerAborted) @@ -155,7 +157,10 @@ ApplicationWindow { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } - onClicked: { stack.replace(awaitingVerificationRequestAccept); flow.acceptVerificationRequest(); } + onClicked: { + stack.replace(awaitingVerificationRequestAccept); + isRequest?flow.sendVerificationReady():flow.acceptVerificationRequest(); + } } } } diff --git a/src/ChatPage.h b/src/ChatPage.h index 0e7c889f..72adfe19 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -52,6 +52,7 @@ class TopRoomBar; class UserInfoWidget; class UserSettings; class NotificationsManager; +class TimelineModel; constexpr int CONSENSUS_TIMEOUT = 1000; constexpr int SHOW_CONTENT_TIMEOUT = 3000; @@ -171,6 +172,9 @@ signals: void recievedDeviceVerificationRequest( const mtx::events::msg::KeyVerificationRequest &message, std::string sender); + void recievedRoomDeviceVerificationRequest( + const mtx::events::RoomEvent &message, + TimelineModel *model); void recievedDeviceVerificationCancel( const mtx::events::msg::KeyVerificationCancel &message); void recievedDeviceVerificationKey(const mtx::events::msg::KeyVerificationKey &message); diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index 69de4937..0f521f92 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -1,7 +1,9 @@ #include "DeviceVerificationFlow.h" + #include "Cache.h" #include "ChatPage.h" #include "Logging.h" +#include "timeline/TimelineModel.h" #include #include @@ -12,12 +14,14 @@ static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes namespace msgs = mtx::events::msg; -DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow::Type) +DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow::Type flow_type) + : type(flow_type) { timeout = new QTimer(this); timeout->setSingleShot(true); this->sas = olm::client()->sas_init(); this->isMacVerified = false; + connect(timeout, &QTimer::timeout, this, [this]() { emit timedout(); this->cancelVerification(DeviceVerificationFlow::Error::Timeout); @@ -267,6 +271,12 @@ DeviceVerificationFlow::getMethod() return this->method; } +DeviceVerificationFlow::Type +DeviceVerificationFlow::getType() +{ + return this->type; +} + bool DeviceVerificationFlow::getSender() { @@ -279,6 +289,12 @@ DeviceVerificationFlow::getSasList() return this->sasList; } +void +DeviceVerificationFlow::setModel(TimelineModel *&model) +{ + this->model_ = model; +} + void DeviceVerificationFlow::setTransactionId(QString transaction_id_) { @@ -318,6 +334,12 @@ DeviceVerificationFlow::setMethod(DeviceVerificationFlow::Method method_) this->method = method_; } +void +DeviceVerificationFlow::setType(Type type) +{ + this->type = type; +} + void DeviceVerificationFlow::setSender(bool sender_) { @@ -328,6 +350,13 @@ DeviceVerificationFlow::setSender(bool sender_) this->relation.in_reply_to.event_id = http::client()->generate_txn_id(); } +void +DeviceVerificationFlow::setEventId(std::string event_id) +{ + this->relation.in_reply_to.event_id = event_id; + this->transaction_id = event_id; +} + //! accepts a verification void DeviceVerificationFlow::acceptVerificationRequest() @@ -361,8 +390,9 @@ DeviceVerificationFlow::acceptVerificationRequest() err->matrix_error.error, static_cast(err->status_code)); }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { req.relates_to = this->relation; + (model_.value())->sendMessage(req); } } //! responds verification request @@ -389,8 +419,9 @@ DeviceVerificationFlow::sendVerificationReady() err->matrix_error.error, static_cast(err->status_code)); }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { req.relates_to = this->relation; + (model_.value())->sendMessage(req); } } //! accepts a verification @@ -414,8 +445,9 @@ DeviceVerificationFlow::sendVerificationDone() err->matrix_error.error, static_cast(err->status_code)); }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { req.relates_to = this->relation; + (model_.value())->sendMessage(req); } } //! starts the verification flow @@ -448,8 +480,9 @@ DeviceVerificationFlow::startVerificationRequest() err->matrix_error.error, static_cast(err->status_code)); }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { req.relates_to = this->relation; + (model_.value())->sendMessage(req); } } //! sends a verification request @@ -481,8 +514,8 @@ DeviceVerificationFlow::sendVerificationRequest() err->matrix_error.error, static_cast(err->status_code)); }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { - std::cout << "lulz" << std::endl; + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { + (model_.value())->sendMessage(req); } } //! cancels a verification flow @@ -531,8 +564,9 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c this->deleteLater(); }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { req.relates_to = this->relation; + (model_.value())->sendMessage(req); } // TODO : Handle Blocking user better @@ -570,8 +604,9 @@ DeviceVerificationFlow::sendVerificationKey() err->matrix_error.error, static_cast(err->status_code)); }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { req.relates_to = this->relation; + (model_.value())->sendMessage(req); } } //! sends the mac of the keys @@ -618,8 +653,9 @@ DeviceVerificationFlow::sendVerificationMac() else this->isMacVerified = true; }); - } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) { + } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) { req.relates_to = this->relation; + (model_.value())->sendMessage(req); } } //! Completes the verification flow diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index 3f999e80..bec9f1e0 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -10,6 +10,8 @@ class QTimer; using sas_ptr = std::unique_ptr; +struct TimelineModel; + class DeviceVerificationFlow : public QObject { Q_OBJECT @@ -19,6 +21,7 @@ class DeviceVerificationFlow : public QObject Q_PROPERTY(QString userId READ getUserId WRITE setUserId) Q_PROPERTY(QString deviceId READ getDeviceId WRITE setDeviceId) Q_PROPERTY(Method method READ getMethod WRITE setMethod) + Q_PROPERTY(Type type READ getType WRITE setType) Q_PROPERTY(std::vector sasList READ getSasList CONSTANT) public: @@ -27,6 +30,7 @@ public: ToDevice, RoomMsg }; + Q_ENUM(Type) enum Method { @@ -49,17 +53,24 @@ public: DeviceVerificationFlow( QObject *parent = nullptr, DeviceVerificationFlow::Type = DeviceVerificationFlow::Type::ToDevice); + // getters QString getTransactionId(); QString getUserId(); QString getDeviceId(); Method getMethod(); + Type getType(); std::vector getSasList(); - void setTransactionId(QString transaction_id_); bool getSender(); + // setters + void setModel(TimelineModel *&model); + void setTransactionId(QString transaction_id_); void setUserId(QString userID); void setDeviceId(QString deviceID); void setMethod(Method method_); + void setType(Type type_); void setSender(bool sender_); + void setEventId(std::string event_id); + void callback_fn(const mtx::responses::QueryKeys &res, mtx::http::RequestErr err, std::string user_id); @@ -96,20 +107,25 @@ signals: void refreshProfile(); private: + // general QString userId; QString deviceId; Method method; Type type; bool sender; - QTimer *timeout = nullptr; sas_ptr sas; bool isMacVerified = false; std::string mac_method; - std::string transaction_id; std::string commitment; mtx::identifiers::User toClient; std::vector sasList; std::map device_keys; + // for to_device messages + std::string transaction_id; + // for room messages + std::optional room_id; + std::optional event_id; + std::optional model_; mtx::common::ReplyRelatesTo relation; }; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 71cc53c5..adf207ac 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -138,6 +138,11 @@ struct RoomEventType { return qml_mtx_events::EventType::KeyVerificationAccept; } + qml_mtx_events::EventType operator()( + const mtx::events::Event &) + { + return qml_mtx_events::EventType::KeyVerificationReady; + } qml_mtx_events::EventType operator()( const mtx::events::Event &) { @@ -637,30 +642,6 @@ TimelineModel::internalAddEvents( continue; } - if (std::get_if>( - &e)) { - std::cout << "got a request" << std::endl; - } - - if (auto cancelVerification = - std::get_if>( - &e)) { - std::cout<<"it is happening"<content.relates_to.has_value()) { - QString event_id = QString::fromStdString( - cancelVerification->content.relates_to.value() - .in_reply_to.event_id); - auto request = - std::find(eventOrder.begin(), eventOrder.end(), event_id); - if (request != eventOrder.end()) { - auto event = events.value(event_id); - auto e = std::get_if>(&event); - std::cout<>(&e)) { QString redacts = QString::fromStdString(redaction->redacts); @@ -728,6 +709,55 @@ TimelineModel::internalAddEvents( if (encInfo) emit newEncryptedImage(encInfo.value()); + + if (auto msg = std::get_if< + mtx::events::RoomEvent>( + &e_)) { + last_verification_request_event = *msg; + } + + if (auto msg = std::get_if< + mtx::events::RoomEvent>( + &e_)) { + last_verification_cancel_event = *msg; + ChatPage::instance()->recievedDeviceVerificationCancel( + msg->content); + } + + if (auto msg = std::get_if< + mtx::events::RoomEvent>( + &e_)) { + ChatPage::instance()->recievedDeviceVerificationAccept( + msg->content); + } + + if (auto msg = std::get_if< + mtx::events::RoomEvent>(&e_)) { + ChatPage::instance()->recievedDeviceVerificationKey(msg->content); + } + + if (auto msg = std::get_if< + mtx::events::RoomEvent>(&e_)) { + ChatPage::instance()->recievedDeviceVerificationMac(msg->content); + } + + if (auto msg = std::get_if< + mtx::events::RoomEvent>( + &e_)) { + ChatPage::instance()->recievedDeviceVerificationReady(msg->content); + } + + if (auto msg = std::get_if< + mtx::events::RoomEvent>(&e_)) { + ChatPage::instance()->recievedDeviceVerificationDone(msg->content); + } + + if (auto msg = std::get_if< + mtx::events::RoomEvent>( + &e_)) { + ChatPage::instance()->recievedDeviceVerificationStart(msg->content, + msg->sender); + } } this->events.insert(id, e); @@ -754,6 +784,13 @@ TimelineModel::internalAddEvents( }); } } + + if (last_verification_request_event.origin_server_ts > + last_verification_cancel_event.origin_server_ts) { + ChatPage::instance()->recievedRoomDeviceVerificationRequest( + last_verification_request_event, this); + } + return ids; } @@ -1263,6 +1300,20 @@ struct SendMessageVisitor TimelineModel *model_; }; +void +TimelineModel::processOnePendingMessage() +{ + if (pending.isEmpty()) + return; + + QString txn_id_qstr = pending.first(); + + auto event = events.value(txn_id_qstr); + std::cout << "Inside the process one pending message" << std::endl; + std::cout << std::visit([](auto &e) { return json(e); }, event).dump(2) << std::endl; + std::visit(SendMessageVisitor{txn_id_qstr, this}, event); +} + void TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event) { @@ -1275,7 +1326,51 @@ TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event) }, event); - std::visit(SendMessageVisitor{this}, event); + if (std::get_if>(&event)) { + std::visit( + [](auto &msg) { msg.type = mtx::events::EventType::KeyVerificationReady; }, + event); + } + if (std::get_if>(&event)) { + std::visit( + [](auto &msg) { msg.type = mtx::events::EventType::KeyVerificationStart; }, + event); + } + if (std::get_if>(&event)) { + std::visit([](auto &msg) { msg.type = mtx::events::EventType::KeyVerificationKey; }, + event); + } + if (std::get_if>(&event)) { + std::visit([](auto &msg) { msg.type = mtx::events::EventType::KeyVerificationMac; }, + event); + } + if (std::get_if>(&event)) { + std::visit( + [](auto &msg) { msg.type = mtx::events::EventType::KeyVerificationDone; }, event); + } + if (std::get_if>(&event)) { + std::visit( + [](auto &msg) { msg.type = mtx::events::EventType::KeyVerificationCancel; }, + event); + } + if (std::get_if>(&event)) { + std::visit( + [](auto &msg) { msg.type = mtx::events::EventType::KeyVerificationAccept; }, + event); + } + + internalAddEvents({event}); + + QString txn_id_qstr = QString::fromStdString(mtx::accessors::event_id(event)); + pending.push_back(txn_id_qstr); + if (!std::get_if>(&event)) { + beginInsertRows(QModelIndex(), 0, 0); + this->eventOrder.insert(this->eventOrder.begin(), txn_id_qstr); + endInsertRows(); + } + updateLastMessage(); + + emit nextPendingMessage(); } bool diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 708ed38e..1b6f999e 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -297,6 +297,11 @@ private: std::vector typingUsers_; TimelineViewManager *manager_; + // probably not the best way to do + mtx::events::RoomEvent + last_verification_request_event; + mtx::events::RoomEvent + last_verification_cancel_event; friend struct SendMessageVisitor; }; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 02b74d20..c16e09d1 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -17,6 +17,8 @@ #include "emoji/EmojiModel.h" #include "emoji/Provider.h" +#include //only for debugging + Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) Q_DECLARE_METATYPE(std::vector) @@ -185,18 +187,44 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin &ChatPage::decryptSidebarChanged, this, &TimelineViewManager::updateEncryptedDescriptions); + connect( + dynamic_cast(parent), + &ChatPage::recievedRoomDeviceVerificationRequest, + this, + [this](const mtx::events::RoomEvent &message, + TimelineModel *model) { + if (!(this->dvList->exist(QString::fromStdString(message.event_id)))) { + auto flow = + new DeviceVerificationFlow(this, DeviceVerificationFlow::Type::RoomMsg); + if (std::find(message.content.methods.begin(), + message.content.methods.end(), + mtx::events::msg::VerificationMethods::SASv1) != + message.content.methods.end()) { + flow->setModel(model); + flow->setEventId(message.event_id); + emit newDeviceVerificationRequest( + std::move(flow), + QString::fromStdString(message.event_id), + QString::fromStdString(message.sender), + QString::fromStdString(message.content.from_device), + true); + } else { + flow->cancelVerification( + DeviceVerificationFlow::Error::UnknownMethod); + } + } + }); connect( dynamic_cast(parent), &ChatPage::recievedDeviceVerificationRequest, this, [this](const mtx::events::msg::KeyVerificationRequest &msg, std::string sender) { - auto flow = new DeviceVerificationFlow(this); if (!(this->dvList->exist(QString::fromStdString(msg.transaction_id.value())))) { + auto flow = new DeviceVerificationFlow(this); if (std::find(msg.methods.begin(), msg.methods.end(), mtx::events::msg::VerificationMethods::SASv1) != msg.methods.end()) { - // flow->sendVerificationReady(); emit newDeviceVerificationRequest( std::move(flow), QString::fromStdString(msg.transaction_id.value()), @@ -213,9 +241,9 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin &ChatPage::recievedDeviceVerificationStart, this, [this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) { - auto flow = new DeviceVerificationFlow(this); - flow->canonical_json = nlohmann::json(msg); if (!(this->dvList->exist(QString::fromStdString(msg.transaction_id.value())))) { + auto flow = new DeviceVerificationFlow(this); + flow->canonical_json = nlohmann::json(msg); if ((std::find(msg.key_agreement_protocols.begin(), msg.key_agreement_protocols.end(), "curve25519-hkdf-sha256") != @@ -246,7 +274,6 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin QString::fromStdString(msg.transaction_id.value()), QString::fromStdString(sender), QString::fromStdString(msg.from_device)); - flow->canonical_json = nlohmann::json(msg); } else { flow->cancelVerification( DeviceVerificationFlow::Error::UnknownMethod); diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 71aee5ef..031d07cc 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -72,7 +72,8 @@ signals: void newDeviceVerificationRequest(DeviceVerificationFlow *flow, QString transactionId, QString userId, - QString deviceId); + QString deviceId, + bool isRequest = false); public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids);