From 2088053d26fc124058fafb434d41b7c9516f0da0 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 13 Mar 2020 21:05:18 +0100 Subject: Add DeviceVerificationFlow dummy and verification test button --- src/timeline/TimelineViewManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 975dd5fb..8447619a 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -85,6 +85,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin "Can't instantiate enum!"); qmlRegisterType("im.nheko", 1, 0, "DelegateChoice"); qmlRegisterType("im.nheko", 1, 0, "DelegateChooser"); + qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow"); qRegisterMetaType(); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiModel"); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel"); @@ -460,3 +461,9 @@ TimelineViewManager::queueVideoMessage(const QString &roomid, model->sendMessage(video); } + +void +TimelineViewManager::startDummyVerification() +{ + emit deviceVerificationRequest(new DeviceVerificationFlow(this)); +} -- cgit 1.5.1 From 707248fea39eafdfc4ce6b69987ab144ab781110 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 13 Mar 2020 21:05:18 +0100 Subject: Add DeviceVerificationFlow dummy and verification test button --- resources/qml/device-verification/DeviceVerification.qml | 8 ++++++++ src/timeline/TimelineViewManager.cpp | 6 ++++++ 2 files changed, 14 insertions(+) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 19e0c7dd..2c9486ae 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -267,7 +267,11 @@ ApplicationWindow { model: 7 delegate: Rectangle { color: "transparent" +<<<<<<< HEAD implicitHeight: Qt.application.font.pixelSize * 3 +======= + implicitHeight: Qt.application.font.pixelSize * 8 +>>>>>>> Add DeviceVerificationFlow dummy and verification test button implicitWidth: col.width ColumnLayout { id: col @@ -410,7 +414,11 @@ ApplicationWindow { property string title: "Verification timed out" ColumnLayout { spacing: 16 +<<<<<<< HEAD Label { +======= + Text { +>>>>>>> Add DeviceVerificationFlow dummy and verification test button Layout.maximumWidth: 400 Layout.fillHeight: true Layout.fillWidth: true diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 8447619a..afd1acb6 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -467,3 +467,9 @@ TimelineViewManager::startDummyVerification() { emit deviceVerificationRequest(new DeviceVerificationFlow(this)); } + +void +TimelineViewManager::startDummyVerification() +{ + emit deviceVerificationRequest(new DeviceVerificationFlow(this)); +} -- cgit 1.5.1 From a54a973ad6be4a1e71be6d8f993600fb02601574 Mon Sep 17 00:00:00 2001 From: Chethan2k1 <40890937+Chethan2k1@users.noreply.github.com> Date: Fri, 22 May 2020 11:17:02 +0530 Subject: Adding DeviceList for userprofile --- resources/qml/UserProfile.qml | 18 ++++++++- .../qml/device-verification/DeviceVerification.qml | 8 ---- src/timeline/TimelineViewManager.cpp | 9 ++--- src/ui/UserProfile.cpp | 44 ++++++++++++++++------ src/ui/UserProfile.h | 32 +++++++++++++--- 5 files changed, 79 insertions(+), 32 deletions(-) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index f019ee25..ae91abc4 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -3,6 +3,8 @@ import QtQuick.Controls 2.3 import QtQuick.Layouts 1.2 import QtQuick.Window 2.3 +import im.nheko 1.0 + ApplicationWindow{ property var user_data property var colors: currentActivePalette @@ -18,7 +20,21 @@ ApplicationWindow{ userProfileAvatar.url = chat.model.avatarUrl(user_data.userId).replace("mxc://", "image://MxcImage/") userProfileName.text = user_data.userName matrixUserID.text = user_data.userId - console.log("this is happening"); + userProfile.userId = user_data.userId + log_devices() + } + + function log_devices() + { + console.log(userProfile.deviceList); + userProfile.deviceList.forEach((item,index)=>{ + console.log(item.device_id) + console.log(item.display_name) + }) + } + + UserProfileContent{ + id: userProfile } background: Item{ diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 2c9486ae..dd637e59 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -267,11 +267,7 @@ ApplicationWindow { model: 7 delegate: Rectangle { color: "transparent" -<<<<<<< HEAD - implicitHeight: Qt.application.font.pixelSize * 3 -======= implicitHeight: Qt.application.font.pixelSize * 8 ->>>>>>> Add DeviceVerificationFlow dummy and verification test button implicitWidth: col.width ColumnLayout { id: col @@ -414,11 +410,7 @@ ApplicationWindow { property string title: "Verification timed out" ColumnLayout { spacing: 16 -<<<<<<< HEAD - Label { -======= Text { ->>>>>>> Add DeviceVerificationFlow dummy and verification test button Layout.maximumWidth: 400 Layout.fillHeight: true Layout.fillWidth: true diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index afd1acb6..227b410f 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -15,6 +15,7 @@ #include "dialogs/ImageOverlay.h" #include "emoji/EmojiModel.h" #include "emoji/Provider.h" +#include "../ui/UserProfile.h" Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) @@ -86,6 +87,8 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin qmlRegisterType("im.nheko", 1, 0, "DelegateChoice"); qmlRegisterType("im.nheko", 1, 0, "DelegateChooser"); qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow"); + qmlRegisterType("im.nheko",1,0,"UserProfileContent"); + qRegisterMetaType(); qRegisterMetaType(); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiModel"); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel"); @@ -467,9 +470,3 @@ TimelineViewManager::startDummyVerification() { emit deviceVerificationRequest(new DeviceVerificationFlow(this)); } - -void -TimelineViewManager::startDummyVerification() -{ - emit deviceVerificationRequest(new DeviceVerificationFlow(this)); -} diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index ac35f1d4..30785699 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -1,28 +1,43 @@ #include "UserProfile.h" #include "Logging.h" -#include "MatrixClient.h" #include "Utils.h" +#include "mtx/responses/crypto.hpp" +#include UserProfile::UserProfile(QObject *parent) : QObject(parent) {} -QMap -UserProfile::getDeviceList() -{ +QVector +UserProfile::getDeviceList(){ + UserProfile::fetchDeviceList(this->userId); return this->deviceList; } +QString +UserProfile::getUserId (){ + return this->userId; +} + +void +UserProfile::setUserId (const QString &user_id){ + if(this->userId != userId) + return; + else + this->userId = user_id; +} + void -UserProfile::fetchDeviceList(const QString &userId) +UserProfile::fetchDeviceList(const QString &userID) { auto localUser = utils::localUser(); mtx::requests::QueryKeys req; - req.device_keys[userId.toStdString()] = {}; + mtx::responses::QueryKeys res; + req.device_keys[userID.toStdString()] = {}; http::client()->query_keys( req, - [user_id = userId.toStdString()](const mtx::responses::QueryKeys &res, + [user_id = userID.toStdString(),this](const mtx::responses::QueryKeys &res, mtx::http::RequestErr err) { if (err) { nhlog::net()->warn("failed to query device keys: {} {}", @@ -39,14 +54,18 @@ UserProfile::fetchDeviceList(const QString &userId) auto devices = res.device_keys.at(user_id); - std::vector deviceInfo; + QVector deviceInfo; for (const auto &d : devices) { auto device = d.second; // TODO: Verify signatures and ignore those that don't pass. - deviceInfo.emplace_back(DeviceInfo{ - QString::fromStdString(d.first), - QString::fromStdString(device.unsigned_info.device_display_name)}); + // std::cout<device_id = QString::fromStdString(d.first); + newdevice->display_name = QString::fromStdString(device.unsigned_info.device_display_name) + + deviceInfo.append(std::move(newdevice)); } std::sort(deviceInfo.begin(), @@ -54,5 +73,8 @@ UserProfile::fetchDeviceList(const QString &userId) [](const DeviceInfo &a, const DeviceInfo &b) { return a.device_id > b.device_id; }); + + this->deviceList = deviceInfo; + emit UserProfile::deviceListUpdated(); }); } diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index d003e6ca..bbf57c7b 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -1,29 +1,49 @@ #pragma once -#include #include #include -struct DeviceInfo +#include "MatrixClient.h" + +class DeviceInfo { +public: + explicit DeviceInfo(QString device_id,QString display_name){ + this->device_id = device_id; + this->display_name = display_name; + } + ~DeviceInfo() = default; + DeviceInfo(const DeviceInfo &device){ + this->device_id = device.device_id; + this->display_name = device.display_name; + } + QString device_id; QString display_name; }; +Q_DECLARE_METATYPE(DeviceInfo); class UserProfile : public QObject { Q_OBJECT - Q_PROPERTY(QMap deviceList READ getDeviceList NOTIFY DeviceListUpdated) + Q_PROPERTY(QVector deviceList READ getDeviceList NOTIFY deviceListUpdated) + Q_PROPERTY(QString userId READ getUserId WRITE setUserId) public: + // constructor explicit UserProfile(QObject *parent = 0); - QMap getDeviceList(); + // getters + QVector getDeviceList(); + QString getUserId(); + // setters + void setUserId(const QString &userId); Q_INVOKABLE void fetchDeviceList(const QString &userID); signals: - void DeviceListUpdated(); + void deviceListUpdated(); private: - QMap deviceList; + QVector deviceList; + QString userId; }; \ No newline at end of file -- cgit 1.5.1 From f9c0f4dd5410621a8427e2ef21496b7791d44d2f Mon Sep 17 00:00:00 2001 From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com> Date: Wed, 27 May 2020 14:19:26 +0530 Subject: Add C++ Model for DeviceList --- CMakeLists.txt | 2 ++ resources/qml/TimelineView.qml | 28 +++++++-------- resources/qml/UserProfile.qml | 58 +++++++++++++++++++------------ src/Olm.cpp | 2 -- src/timeline/TimelineViewManager.cpp | 8 +++-- src/ui/UserProfile.cpp | 46 ++++++++++++++----------- src/ui/UserProfile.h | 22 ++++++------ src/ui/UserProfileModel.cpp | 66 ++++++++++++++++++++++++++++++++++++ src/ui/UserProfileModel.h | 29 ++++++++++++++++ 9 files changed, 188 insertions(+), 73 deletions(-) create mode 100644 src/ui/UserProfileModel.cpp create mode 100644 src/ui/UserProfileModel.h (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index e170495a..654eae37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,6 +277,7 @@ set(SRC_FILES src/ui/Theme.cpp src/ui/ThemeManager.cpp src/ui/UserProfile.cpp + src/ui/UserProfileModel.cpp src/AvatarProvider.cpp src/BlurhashProvider.cpp @@ -482,6 +483,7 @@ qt5_wrap_cpp(MOC_HEADERS src/ui/Theme.h src/ui/ThemeManager.h src/ui/UserProfile.h + src/ui/UserProfileModel.h src/notifications/Manager.h diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index ed403aa9..e4c820f8 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -273,6 +273,9 @@ Page { color: colors.base } } + + property variant userProfile + Row { height: userName.height spacing: 8 @@ -287,8 +290,10 @@ Page { MouseArea { anchors.fill: parent onClicked: { - userProfile.user_data = modelData - userProfile.show() + if(userProfile) userProfile.destroy() + var component = Qt.createComponent("UserProfile.qml"); + userProfile = component.createObject(timelineRoot,{user_data : modelData}); + userProfile.show(); } cursorShape: Qt.PointingHandCursor propagateComposedEvents: true @@ -303,26 +308,17 @@ Page { MouseArea { anchors.fill: parent + Layout.alignment: Qt.AlignHCenter onClicked: { - userProfile.user_data = modelData - userProfile.show() + if(userProfile) userProfile.destroy() + var component = Qt.createComponent("UserProfile.qml") + userProfile = component.createObject(timelineRoot,{user_data : modelData}) + userProfile.show() } cursorShape: Qt.PointingHandCursor propagateComposedEvents: true } } - - Label { - color: colors.buttonText - text: timelineManager.userStatus(modelData.userId) - textFormat: Text.PlainText - elide: Text.ElideRight - width: chat.delegateMaxWidth - parent.spacing*2 - userName.implicitWidth - avatarSize - font.italic: true - } - UserProfile{ - id: userProfile - } } } } diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index ae91abc4..f29fb4c1 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -16,25 +16,16 @@ ApplicationWindow{ Layout.alignment: Qt.AlignHCenter palette: colors - onAfterRendering: { - userProfileAvatar.url = chat.model.avatarUrl(user_data.userId).replace("mxc://", "image://MxcImage/") - userProfileName.text = user_data.userName - matrixUserID.text = user_data.userId - userProfile.userId = user_data.userId - log_devices() - } - - function log_devices() - { - console.log(userProfile.deviceList); - userProfile.deviceList.forEach((item,index)=>{ - console.log(item.device_id) - console.log(item.display_name) - }) - } - - UserProfileContent{ - id: userProfile + UserProfileList{ + id: userProfileList + userId: user_data.userId + onUserIdChanged : { + console.log(userId) + userProfileList.updateDeviceList() + } + onDeviceListUpdated : { + modelDeviceList.deviceList = userProfileList + } } background: Item{ @@ -52,6 +43,7 @@ ApplicationWindow{ Avatar{ id: userProfileAvatar + url:chat.model.avatarUrl(user_data.userId).replace("mxc://", "image://MxcImage/") height: 130 width: 130 displayName: modelData.userName @@ -60,12 +52,14 @@ ApplicationWindow{ Label{ id: userProfileName + text: user_data.userName fontSizeMode: Text.HorizontalFit Layout.alignment: Qt.AlignHCenter } Label{ id: matrixUserID + text: user_data.userId fontSizeMode: Text.HorizontalFit Layout.alignment: Qt.AlignHCenter } @@ -78,9 +72,29 @@ ApplicationWindow{ ScrollBar.horizontal.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn - Label { - text: "ABC" - font.pixelSize: 700 + ListView{ + id: deviceList + anchors.fill: parent + clip: true + spacing: 10 + + model: UserProfileModel{ + id: modelDeviceList + } + + delegate: RowLayout{ + width: parent.width + Text{ + Layout.fillWidth: true + color: colors.text + text: deviceID + } + Text{ + Layout.fillWidth: true + color:colors.text + text: displayName + } + } } } diff --git a/src/Olm.cpp b/src/Olm.cpp index 494bc201..74fbac9a 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -56,7 +56,6 @@ handle_to_device_messages(const std::vectorwarn("validation error for olm message: {} {}", e.what(), j_msg.dump(2)); - } } else if (msg_type == to_string(mtx::events::EventType::RoomKeyRequest)) { @@ -399,7 +398,6 @@ handle_key_request_message(const mtx::events::DeviceEventdebug("ignoring all key requests for room {}", req.content.room_id); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 227b410f..f4d1c00e 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "BlurhashProvider.h" #include "ChatPage.h" @@ -16,6 +17,8 @@ #include "emoji/EmojiModel.h" #include "emoji/Provider.h" #include "../ui/UserProfile.h" +#include "src/ui/UserProfile.h" +#include "src/ui/UserProfileModel.h" Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) @@ -87,8 +90,9 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin qmlRegisterType("im.nheko", 1, 0, "DelegateChoice"); qmlRegisterType("im.nheko", 1, 0, "DelegateChooser"); qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow"); - qmlRegisterType("im.nheko",1,0,"UserProfileContent"); - qRegisterMetaType(); + qmlRegisterType("im.nheko", 1, 0, "UserProfileModel"); + qmlRegisterType("im.nheko", 1, 0, "UserProfileList"); + qRegisterMetaType(); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiModel"); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel"); diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index 30785699..588d6969 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -2,29 +2,32 @@ #include "Logging.h" #include "Utils.h" #include "mtx/responses/crypto.hpp" -#include UserProfile::UserProfile(QObject *parent) : QObject(parent) {} QVector -UserProfile::getDeviceList(){ - UserProfile::fetchDeviceList(this->userId); +UserProfile::getDeviceList() +{ return this->deviceList; } QString -UserProfile::getUserId (){ +UserProfile::getUserId() +{ return this->userId; } void -UserProfile::setUserId (const QString &user_id){ - if(this->userId != userId) +UserProfile::setUserId(const QString &user_id) +{ + if (this->userId != userId) return; - else + else { this->userId = user_id; + emit UserProfile::userIdChanged(); + } } void @@ -37,11 +40,11 @@ UserProfile::fetchDeviceList(const QString &userID) http::client()->query_keys( req, - [user_id = userID.toStdString(),this](const mtx::responses::QueryKeys &res, - mtx::http::RequestErr err) { + [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.error, + nhlog::net()->warn("failed to query device keys: {},{}", + err->matrix_error.errcode, static_cast(err->status_code)); return; } @@ -53,17 +56,16 @@ UserProfile::fetchDeviceList(const QString &userID) } auto devices = res.device_keys.at(user_id); - QVector deviceInfo; + for (const auto &d : devices) { auto device = d.second; // TODO: Verify signatures and ignore those that don't pass. - // std::cout<device_id = QString::fromStdString(d.first); - newdevice->display_name = QString::fromStdString(device.unsigned_info.device_display_name) + 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)); } @@ -74,7 +76,13 @@ UserProfile::fetchDeviceList(const QString &userID) return a.device_id > b.device_id; }); - this->deviceList = deviceInfo; - emit UserProfile::deviceListUpdated(); + this->deviceList = std::move(deviceInfo); + emit UserProfile::deviceListUpdated(); }); } + +void +UserProfile::updateDeviceList() +{ + fetchDeviceList(this->userId); +} diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index bbf57c7b..c37e23ae 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -2,33 +2,29 @@ #include #include +#include #include "MatrixClient.h" class DeviceInfo { public: - explicit DeviceInfo(QString device_id,QString display_name){ - this->device_id = device_id; - this->display_name = display_name; - } - ~DeviceInfo() = default; - DeviceInfo(const DeviceInfo &device){ - this->device_id = device.device_id; - this->display_name = device.display_name; - } + DeviceInfo(const QString deviceID, const QString displayName) + : device_id(deviceID) + , display_name(displayName) + {} + + DeviceInfo() {} QString device_id; QString display_name; }; -Q_DECLARE_METATYPE(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(QString userId READ getUserId WRITE setUserId) - public: // constructor explicit UserProfile(QObject *parent = 0); @@ -39,8 +35,10 @@ public: void setUserId(const QString &userId); Q_INVOKABLE void fetchDeviceList(const QString &userID); + Q_INVOKABLE void updateDeviceList(); signals: + void userIdChanged(); void deviceListUpdated(); private: diff --git a/src/ui/UserProfileModel.cpp b/src/ui/UserProfileModel.cpp new file mode 100644 index 00000000..ec0456cd --- /dev/null +++ b/src/ui/UserProfileModel.cpp @@ -0,0 +1,66 @@ +#include "UserProfileModel.h" +#include "UserProfile.h" +#include + +UserProfileModel::UserProfileModel(QObject *parent) + : QAbstractListModel(parent) + , deviceList(nullptr) +{} + +int +UserProfileModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid() || !this->deviceList) + return 0; + return this->deviceList->getDeviceList().size(); +} + +QVariant +UserProfileModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || !this->deviceList) + return QVariant(); + + const DeviceInfo device = this->deviceList->getDeviceList().at(index.row()); + switch (role) { + case DEVICEID: + return QVariant(device.device_id); + case DISPLAYNAME: + return QVariant(device.display_name); + } + return QVariant(); +} + +QHash +UserProfileModel::roleNames() const +{ + QHash names; + names[DEVICEID] = "deviceID"; + names[DISPLAYNAME] = "displayName"; + return names; +} + +UserProfile * +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 new file mode 100644 index 00000000..c21a806d --- /dev/null +++ b/src/ui/UserProfileModel.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +class UserProfile; // forward declaration of the class UserProfile + +class UserProfileModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(UserProfile *deviceList READ getList WRITE setList) + +public: + explicit UserProfileModel(QObject *parent = nullptr); + + enum + { + DEVICEID, + DISPLAYNAME + }; + UserProfile *getList() const; + void setList(UserProfile *devices); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + virtual QHash roleNames() const override; + +private: + UserProfile *deviceList; +}; \ No newline at end of file -- cgit 1.5.1 From 41b6ef0c32877384d4157a87aee01f67090b15a3 Mon Sep 17 00:00:00 2001 From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com> Date: Wed, 17 Jun 2020 23:58:35 +0530 Subject: Add DeviceVerificationList to keep track of all flows and Popup on recieving start or request --- resources/qml/TimelineView.qml | 18 +++--- resources/qml/UserProfile.qml | 10 +-- .../qml/device-verification/DeviceVerification.qml | 60 ++++++++++++++--- src/ChatPage.cpp | 2 +- src/DeviceVerificationFlow.cpp | 69 +++++++++++++------- src/DeviceVerificationFlow.h | 10 ++- src/emoji/EmojiModel.h | 1 - src/timeline/TimelineViewManager.cpp | 75 ++++++++++++++++++---- src/timeline/TimelineViewManager.h | 20 +++++- 9 files changed, 203 insertions(+), 62 deletions(-) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index e4c820f8..5170a41a 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -103,20 +103,22 @@ Page { id: deviceVerificationDialog DeviceVerification {} } + Component{ + id: deviceVerificationFlow + DeviceVerificationFlow {} + } Connections { target: timelineManager - onDeviceVerificationRequest: { - var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: deviceVerificationFlow}); + onNewDeviceVerificationRequest: { + var newFlow = deviceVerificationFlow.createObject(timelineRoot, + {userId : userId,sender: false,deviceId : deviceId,tranId:transactionId}); + deviceVerificationList.add(newFlow.tranId); + var dialog = deviceVerificationDialog.createObject(timelineRoot, + {flow: newFlow,sender: false}); dialog.show(); } } - Button { - text: "test device verification" - onClicked: timelineManager.startDummyVerification() - z: 5 - } - Label { visible: !timelineManager.timeline && !timelineManager.isInitialSync anchors.centerIn: parent diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index c40e6765..80415a29 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -33,8 +33,9 @@ ApplicationWindow{ id: deviceVerificationDialog DeviceVerification {} } - DeviceVerificationFlow { + Component{ id: deviceVerificationFlow + DeviceVerificationFlow {} } background: Item{ @@ -111,10 +112,11 @@ ApplicationWindow{ id: verifyButton text:"Verify" onClicked: { - deviceVerificationFlow.userId = user_data.userId - deviceVerificationFlow.deviceId = model.deviceID + var newFlow = deviceVerificationFlow.createObject(userProfileDialog, + {userId : user_data.userId,sender: true,deviceId : model.deviceID}); + deviceVerificationList.add(newFlow.tranId); var dialog = deviceVerificationDialog.createObject(userProfileDialog, - {flow: deviceVerificationFlow,sender: true}); + {flow: newFlow,sender: true}); dialog.show(); } contentItem: Text { diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index fca360f7..ad0edeb7 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -75,7 +75,12 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignLeft text: "Cancel" - onClicked: { dialog.close(); flow.cancelVerification(); } + onClicked: { + dialog.close(); + flow.cancelVerification(); + deviceVerificationList.remove(flow.tranId); + delete flow; + } } Item { Layout.fillWidth: true @@ -127,7 +132,12 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignLeft text: "Deny" - onClicked: { dialog.close(); flow.cancelVerification(); } + onClicked: { + dialog.close(); + flow.cancelVerification(); + deviceVerificationList.remove(flow.tranId); + delete flow; + } } Item { Layout.fillWidth: true @@ -166,7 +176,12 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignLeft text: "Cancel" - onClicked: { dialog.close(); flow.cancelVerification(); } + onClicked: { + dialog.close(); + flow.cancelVerification(); + deviceVerificationList.remove(flow.tranId); + delete flow; + } } Item { Layout.fillWidth: true @@ -212,7 +227,12 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignLeft text: "They do not match!" - onClicked: { dialog.close(); flow.cancelVerification(); } + onClicked: { + dialog.close(); + flow.cancelVerification(); + deviceVerificationList.remove(flow.tranId); + delete flow; + } } Item { Layout.fillWidth: true @@ -346,7 +366,12 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignLeft text: "They do not match!" - onClicked: { dialog.close(); flow.cancelVerification(); } + onClicked: { + dialog.close(); + flow.cancelVerification(); + deviceVerificationList.remove(flow.tranId); + delete flow; + } } Item { Layout.fillWidth: true @@ -385,7 +410,12 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignLeft text: "Cancel" - onClicked: { dialog.close(); flow.cancelVerification(); } + onClicked: { + dialog.close(); + flow.cancelVerification(); + deviceVerificationList.remove(flow.tranId); + delete flow; + } } Item { Layout.fillWidth: true @@ -419,7 +449,11 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "Close" - onClicked: dialog.close() + onClicked: { + dialog.close() + deviceVerificationList.remove(flow.tranId); + delete flow; + } } } } @@ -450,7 +484,11 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "Close" - onClicked: dialog.close() + onClicked: { + dialog.close() + deviceVerificationList.remove(flow.tranId); + delete flow; + } } } } @@ -481,7 +519,11 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "Close" - onClicked: dialog.close() + onClicked: { + dialog.close() + deviceVerificationList.remove(flow.tranId); + delete flow; + } } } } diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 17ea2551..aba1f75d 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -26,8 +26,8 @@ #include "Cache.h" #include "Cache_p.h" #include "ChatPage.h" -#include "EventAccessors.h" #include "DeviceVerificationFlow.h" +#include "EventAccessors.h" #include "Logging.h" #include "MainWindow.h" #include "MatrixClient.h" diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index c6652d03..efb9882b 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -1,7 +1,7 @@ #include "DeviceVerificationFlow.h" #include "ChatPage.h" - #include "Logging.h" + #include #include // only for debugging #include @@ -13,9 +13,10 @@ namespace msgs = mtx::events::msg; DeviceVerificationFlow::DeviceVerificationFlow(QObject *) { - qRegisterMetaType(); timeout = new QTimer(this); timeout->setSingleShot(true); + if (this->sender == true) + this->transaction_id = http::client()->generate_txn_id(); connect(timeout, &QTimer::timeout, this, [this]() { emit timedout(); this->deleteLater(); @@ -73,6 +74,12 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) timeout->start(TIMEOUT); } +QString +DeviceVerificationFlow::getTransactionId() +{ + return QString::fromStdString(this->transaction_id); +} + QString DeviceVerificationFlow::getUserId() { @@ -91,10 +98,22 @@ DeviceVerificationFlow::getMethod() return this->method; } +bool +DeviceVerificationFlow::getSender() +{ + return this->sender; +} + +void +DeviceVerificationFlow::setTransactionId(QString transaction_id_) +{ + this->transaction_id = transaction_id_.toStdString(); +} + void DeviceVerificationFlow::setUserId(QString userID) { - this->userId = userID; + this->userId = userID; this->toClient = mtx::identifiers::parse(userID.toStdString()); } @@ -110,6 +129,12 @@ DeviceVerificationFlow::setMethod(DeviceVerificationFlow::Method method_) this->method = method_; } +void +DeviceVerificationFlow::setSender(bool sender_) +{ + this->sender = sender_; +} + //! accepts a verification void DeviceVerificationFlow::acceptVerificationRequest() @@ -119,11 +144,12 @@ DeviceVerificationFlow::acceptVerificationRequest() req.transaction_id = this->transaction_id; req.method = mtx::events::msg::VerificationMethods::SASv1; - req.key_agreement_protocol = "curve25519"; + req.key_agreement_protocol = "curve25519-hkdf-sha256"; req.hash = "sha256"; - req.message_authentication_code = ""; - // req.short_authentication_string = ""; - req.commitment = ""; + req.message_authentication_code = "hkdf-hmac-sha256"; + req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal, + mtx::events::msg::SASMethods::Emoji}; + req.commitment = ""; emit this->verificationRequestAccepted(this->method); @@ -132,12 +158,12 @@ DeviceVerificationFlow::acceptVerificationRequest() http::client() ->send_to_device( - "m.key.verification.accept", body, [](mtx::http::RequestErr err) { + this->transaction_id, body, [this](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to accept verification request: {} {}", err->matrix_error.error, static_cast(err->status_code)); - // emit this->verificationRequestAccepted(rand() % 2 ? Emoji : Decimal); + emit this->verificationRequestAccepted(rand() % 2 ? Emoji : Decimal); }); } //! starts the verification flow @@ -150,22 +176,23 @@ DeviceVerificationFlow::startVerificationRequest() req.from_device = http::client()->device_id(); req.transaction_id = this->transaction_id; req.method = mtx::events::msg::VerificationMethods::SASv1; - req.key_agreement_protocols = {}; - req.hashes = {}; - req.message_authentication_codes = {}; - // req.short_authentication_string = ""; - qDebug()<<"Inside Start Verification"; - qDebug()<userId; + req.key_agreement_protocols = {"curve25519-hkdf-sha256"}; + req.hashes = {"sha256"}; + req.message_authentication_codes = {"hkdf-hmac-sha256", "hmac-sha256"}; + req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal, + mtx::events::msg::SASMethods::Emoji}; + body[this->toClient][this->deviceId.toStdString()] = req; http::client() ->send_to_device( - "m.key.verification.start", body, [](mtx::http::RequestErr err) { + this->transaction_id, body, [body](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to start verification request: {} {}", err->matrix_error.error, static_cast(err->status_code)); + std::cout << nlohmann::json(body).dump(2) << std::endl; }); } //! sends a verification request @@ -177,8 +204,6 @@ DeviceVerificationFlow::sendVerificationRequest() mtx::requests::ToDeviceMessages body; mtx::events::msg::KeyVerificationRequest req; - this->transaction_id = http::client()->generate_txn_id(); - req.from_device = http::client()->device_id(); req.transaction_id = this->transaction_id; req.methods.resize(1); @@ -190,7 +215,7 @@ DeviceVerificationFlow::sendVerificationRequest() http::client() ->send_to_device( - "m.key.verification.request", body, [](mtx::http::RequestErr err) { + this->transaction_id, body, [](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to send verification request: {} {}", err->matrix_error.error, @@ -214,7 +239,7 @@ DeviceVerificationFlow::cancelVerification() http::client() ->send_to_device( - "m.key.verification.cancel", body, [this](mtx::http::RequestErr err) { + this->transaction_id, body, [this](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to cancel verification request: {} {}", err->matrix_error.error, @@ -237,7 +262,7 @@ DeviceVerificationFlow::sendVerificationKey() http::client() ->send_to_device( - "m.key.verification.cancel", body, [](mtx::http::RequestErr err) { + this->transaction_id, body, [](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to send verification key: {} {}", err->matrix_error.error, @@ -260,7 +285,7 @@ DeviceVerificationFlow::sendVerificationMac() http::client() ->send_to_device( - "m.key.verification.cancel", body, [](mtx::http::RequestErr err) { + this->transaction_id, body, [](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to send verification MAC: {} {}", err->matrix_error.error, diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index 561a3717..b651394b 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -1,5 +1,7 @@ #pragma once +#include "Olm.h" + #include #include @@ -9,6 +11,8 @@ class DeviceVerificationFlow : public QObject { Q_OBJECT // Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") + Q_PROPERTY(QString tranId READ getTransactionId WRITE setTransactionId) + Q_PROPERTY(bool sender READ getSender WRITE setSender) Q_PROPERTY(QString userId READ getUserId WRITE setUserId) Q_PROPERTY(QString deviceId READ getDeviceId WRITE setDeviceId) Q_PROPERTY(Method method READ getMethod WRITE setMethod) @@ -22,12 +26,16 @@ public: Q_ENUM(Method) DeviceVerificationFlow(QObject *parent = nullptr); + QString getTransactionId(); QString getUserId(); QString getDeviceId(); Method getMethod(); + void setTransactionId(QString transaction_id_); + bool getSender(); void setUserId(QString userID); void setDeviceId(QString deviceID); void setMethod(Method method_); + void setSender(bool sender_); public slots: //! sends a verification request @@ -55,9 +63,9 @@ private: QString userId; QString deviceId; Method method; + bool sender; QTimer *timeout = nullptr; std::string transaction_id; mtx::identifiers::User toClient; }; -Q_DECLARE_METATYPE(mtx::events::collections::DeviceEvents) \ No newline at end of file diff --git a/src/emoji/EmojiModel.h b/src/emoji/EmojiModel.h index 8d43e000..88bacdee 100644 --- a/src/emoji/EmojiModel.h +++ b/src/emoji/EmojiModel.h @@ -60,5 +60,4 @@ private: EmojiCategory category_ = EmojiCategory::Search; emoji::Provider emoji_provider_; }; - } \ No newline at end of file diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index f4d1c00e..22fe4d6d 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -16,12 +16,38 @@ #include "dialogs/ImageOverlay.h" #include "emoji/EmojiModel.h" #include "emoji/Provider.h" -#include "../ui/UserProfile.h" #include "src/ui/UserProfile.h" #include "src/ui/UserProfileModel.h" Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) +namespace msgs = mtx::events::msg; + +void +DeviceVerificationList::add(QString tran_id) +{ + this->dv_list.push_back(tran_id); +} +void +DeviceVerificationList::remove(QString tran_id) +{ + for (QVector::iterator it = 0; it != (this->dv_list).end(); ++it) { + if (*it == tran_id) { + this->dv_list.erase(it); + break; + } + } +} +bool +DeviceVerificationList::exist(QString tran_id) +{ + for (int i = 0; i < (this->dv_list).size(); ++i) { + if (dv_list[i] == tran_id) + return true; + } + return false; +} + void TimelineViewManager::updateEncryptedDescriptions() { @@ -63,12 +89,12 @@ TimelineViewManager::userColor(QString id, QColor background) return userColors.value(id); } -QString -TimelineViewManager::userPresence(QString id) const -{ - return QString::fromStdString( - mtx::presence::to_string(cache::presenceState(id.toStdString()))); -} +// QString +// TimelineViewManager::userPresence(QString id) const +// { +// return QString::fromStdString( +// mtx::presence::to_string(cache::presenceState(id.toStdString()))); +// } QString TimelineViewManager::userStatus(QString id) const { @@ -81,6 +107,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin , blurhashProvider(new BlurhashProvider()) , settings(userSettings) { + qRegisterMetaType(); qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject, "im.nheko", 1, @@ -106,6 +133,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin 0, "EmojiCategory", "Error: Only enums"); + this->dvList = new DeviceVerificationList; #ifdef USE_QUICK_VIEW view = new QQuickView(); @@ -127,6 +155,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin container->setMinimumSize(200, 200); view->rootContext()->setContextProperty("timelineManager", this); view->rootContext()->setContextProperty("settings", settings.data()); + view->rootContext()->setContextProperty("deviceVerificationList", this->dvList); updateColorPalette(); view->engine()->addImageProvider("MxcImage", imgProvider); view->engine()->addImageProvider("colorimage", colorImgProvider); @@ -141,6 +170,32 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin &ChatPage::decryptSidebarChanged, this, &TimelineViewManager::updateEncryptedDescriptions); + connect(dynamic_cast(parent), + &ChatPage::recievedDeviceVerificationRequest, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + QString tranID = QString::fromStdString(msg.content.transaction_id); + QString deviceId = QString::fromStdString(msg.content.from_device); + QString userId = QString::fromStdString(msg.sender); + if (!(this->dvList->exist(tranID))) { + emit newDeviceVerificationRequest(tranID, userId, deviceId); + } + }); + connect(dynamic_cast(parent), + &ChatPage::recievedDeviceVerificationStart, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + QString tranID = QString::fromStdString(msg.content.transaction_id); + QString deviceId = QString::fromStdString(msg.content.from_device); + QString userId = QString::fromStdString(msg.sender); + if (!(this->dvList->exist(tranID))) { + emit newDeviceVerificationRequest(tranID, userId, deviceId); + } + }); } void @@ -468,9 +523,3 @@ TimelineViewManager::queueVideoMessage(const QString &roomid, model->sendMessage(video); } - -void -TimelineViewManager::startDummyVerification() -{ - emit deviceVerificationRequest(new DeviceVerificationFlow(this)); -} diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 583a9e4c..70912715 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -22,6 +22,18 @@ class BlurhashProvider; class ColorImageProvider; class UserSettings; +class DeviceVerificationList : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE void add(QString tran_id); + Q_INVOKABLE void remove(QString tran_id); + Q_INVOKABLE bool exist(QString tran_id); + +private: + QVector dv_list; +}; + class TimelineViewManager : public QObject { Q_OBJECT @@ -44,9 +56,8 @@ public: Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; } Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const; Q_INVOKABLE QColor userColor(QString id, QColor background); - Q_INVOKABLE void startDummyVerification(); - Q_INVOKABLE QString userPresence(QString id) const; + // Q_INVOKABLE QString userPresence(QString id) const; Q_INVOKABLE QString userStatus(QString id) const; signals: @@ -56,7 +67,7 @@ signals: void initialSyncChanged(bool isInitialSync); void replyingEventChanged(QString replyingEvent); void replyClosed(); - void deviceVerificationRequest(DeviceVerificationFlow *deviceVerificationFlow); + void newDeviceVerificationRequest(QString transactionId, QString userId, QString deviceId); public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids); @@ -114,4 +125,7 @@ private: QSharedPointer settings; QHash userColors; + + DeviceVerificationList *dvList; }; +Q_DECLARE_METATYPE(mtx::events::collections::DeviceEvents) \ No newline at end of file -- cgit 1.5.1 From 67367d0004abe54445c9c6ca354c787fc0af8a79 Mon Sep 17 00:00:00 2001 From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com> Date: Sat, 20 Jun 2020 17:50:43 +0530 Subject: Shared secret with decimal and emoji works! --- resources/qml/TimelineView.qml | 13 +- .../qml/device-verification/DeviceVerification.qml | 26 ++-- src/DeviceVerificationFlow.cpp | 167 ++++++++++++++++----- src/DeviceVerificationFlow.h | 10 ++ src/timeline/TimelineViewManager.cpp | 64 ++++---- src/timeline/TimelineViewManager.h | 5 +- 6 files changed, 202 insertions(+), 83 deletions(-) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 5170a41a..99d14685 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -103,18 +103,15 @@ Page { id: deviceVerificationDialog DeviceVerification {} } - Component{ - id: deviceVerificationFlow - DeviceVerificationFlow {} - } Connections { target: timelineManager onNewDeviceVerificationRequest: { - var newFlow = deviceVerificationFlow.createObject(timelineRoot, - {userId : userId,sender: false,deviceId : deviceId,tranId:transactionId}); - deviceVerificationList.add(newFlow.tranId); + flow.userId = userId; + flow.sender = false; + flow.deviceId = deviceId; + flow.tranId = transactionId; var dialog = deviceVerificationDialog.createObject(timelineRoot, - {flow: newFlow,sender: false}); + {flow: flow,sender: false}); dialog.show(); } } diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index ad0edeb7..316fbe40 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -78,7 +78,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -135,7 +135,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -179,7 +179,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -211,15 +211,15 @@ ApplicationWindow { Layout.alignment: Qt.AlignHCenter Label { font.pixelSize: Qt.application.font.pixelSize * 2 - text: "1234" + text: flow.sasList[0] } Label { font.pixelSize: Qt.application.font.pixelSize * 2 - text: "1234" + text: flow.sasList[1] } Label { font.pixelSize: Qt.application.font.pixelSize * 2 - text: "1234" + text: flow.sasList[2] } } @@ -230,7 +230,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -345,7 +345,7 @@ ApplicationWindow { ColumnLayout { id: col anchors.bottom: parent.bottom - property var emoji: emojis.mapping[Math.floor(Math.random()*64)] + property var emoji: emojis.mapping[flow.sasList[index]] Label { //height: font.pixelSize * 2 Layout.alignment: Qt.AlignHCenter @@ -369,7 +369,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -413,7 +413,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -451,7 +451,7 @@ ApplicationWindow { text: "Close" onClicked: { dialog.close() - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -486,7 +486,7 @@ ApplicationWindow { text: "Close" onClicked: { dialog.close() - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -521,7 +521,7 @@ ApplicationWindow { text: "Close" onClicked: { dialog.close() - deviceVerificationList.remove(flow.tranId); + // deviceVerificationList.remove(flow.tranId); delete flow; } } diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index efb9882b..607cc279 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -15,32 +15,80 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) { timeout = new QTimer(this); timeout->setSingleShot(true); - if (this->sender == true) - this->transaction_id = http::client()->generate_txn_id(); + this->sas = olm::client()->sas_init(); connect(timeout, &QTimer::timeout, this, [this]() { emit timedout(); this->deleteLater(); }); + connect(ChatPage::instance(), - &ChatPage::recievedDeviceVerificationAccept, - this, - [this](const mtx::events::collections::DeviceEvents &message) { - auto msg = - std::get>(message); - if (msg.content.transaction_id == this->transaction_id) { - std::cout << "Recieved Event Accept" << std::endl; - } - }); - connect(ChatPage::instance(), - &ChatPage::recievedDeviceVerificationRequest, + &ChatPage::recievedDeviceVerificationStart, this, [this](const mtx::events::collections::DeviceEvents &message) { auto msg = - std::get>(message); + std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - std::cout << "Recieved Event Request" << std::endl; + if (std::find(msg.content.key_agreement_protocols.begin(), + msg.content.key_agreement_protocols.end(), + "curve25519-hkdf-sha256") != + msg.content.key_agreement_protocols.end() && + std::find(msg.content.hashes.begin(), + msg.content.hashes.end(), + "sha256") != msg.content.hashes.end() && + (std::find(msg.content.message_authentication_codes.begin(), + msg.content.message_authentication_codes.end(), + "hmac-sha256") != + msg.content.message_authentication_codes.end() || + std::find(msg.content.message_authentication_codes.begin(), + msg.content.message_authentication_codes.end(), + "hkdf-hmac-sha256") != + msg.content.message_authentication_codes.end()) && + (std::find(msg.content.short_authentication_string.begin(), + msg.content.short_authentication_string.end(), + mtx::events::msg::SASMethods::Decimal) != + msg.content.short_authentication_string.end() || + std::find(msg.content.short_authentication_string.begin(), + msg.content.short_authentication_string.end(), + mtx::events::msg::SASMethods::Emoji) != + msg.content.short_authentication_string.end())) { + this->sendVerificationKey(); // Not sure about this maybe + // those optional methods + this->canonical_json = nlohmann::json(msg); + } else { + this->cancelVerification(); + } } }); + connect( + ChatPage::instance(), + &ChatPage::recievedDeviceVerificationAccept, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + if (msg.content.transaction_id == this->transaction_id) { + if ((msg.content.method == + mtx::events::msg::VerificationMethods::SASv1) && + (msg.content.key_agreement_protocol == "curve25519-hkdf-sha256") && + (msg.content.hash == "sha256") && + ((msg.content.message_authentication_code == "hkdf-hmac-sha256") || + (msg.content.message_authentication_code == "hmac-sha256"))) { + this->commitment = msg.content.commitment; + if (std::find(msg.content.short_authentication_string.begin(), + msg.content.short_authentication_string.end(), + mtx::events::msg::SASMethods::Emoji) != + msg.content.short_authentication_string.end()) { + this->method = DeviceVerificationFlow::Method::Emoji; + } else { + this->method = DeviceVerificationFlow::Method::Decimal; + } + this->mac_method = msg.content.message_authentication_code; + this->sendVerificationKey(); + } else { + this->cancelVerification(); + } + } + }); connect(ChatPage::instance(), &ChatPage::recievedDeviceVerificationCancel, this, @@ -48,19 +96,55 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - std::cout << "Recieved Event Cancel" << std::endl; - } - }); - connect(ChatPage::instance(), - &ChatPage::recievedDeviceVerificationKey, - this, - [this](const mtx::events::collections::DeviceEvents &message) { - auto msg = - std::get>(message); - if (msg.content.transaction_id == this->transaction_id) { - std::cout << "Recieved Event Key" << std::endl; + emit verificationCanceled(); } }); + connect( + ChatPage::instance(), + &ChatPage::recievedDeviceVerificationKey, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = std::get>(message); + if (msg.content.transaction_id == this->transaction_id) { + this->sas->set_their_key(msg.content.key); + std::string info; + if (this->sender == true) { + info = "MATRIX_KEY_VERIFICATION_SAS|" + + http::client()->user_id().to_string() + "|" + + http::client()->device_id() + "|" + + this->sas->public_key() + "|" + + this->toClient.to_string() + "|" + + this->deviceId.toStdString() + "|" + msg.content.key + + "|" + this->transaction_id; + } else { + info = "MATRIX_KEY_VERIFICATION_SAS|" + + this->toClient.to_string() + "|" + + this->deviceId.toStdString() + "|" + msg.content.key + + "|" + http::client()->user_id().to_string() + "|" + + http::client()->device_id() + "|" + + this->sas->public_key() + "|" + this->transaction_id; + } + + if (this->method == DeviceVerificationFlow::Method::Emoji) { + this->sasList = this->sas->generate_bytes_emoji(info); + } else if (this->method == DeviceVerificationFlow::Method::Decimal) { + this->sasList = this->sas->generate_bytes_decimal(info); + } + if (this->sender == false) { + emit this->verificationRequestAccepted(this->method); + this->sendVerificationKey(); + } else { + if (this->commitment == + mtx::crypto::bin2base64_unpadded(mtx::crypto::sha256( + msg.content.key + + this->canonical_json["content"].dump()))) { + emit this->verificationRequestAccepted(this->method); + } else { + this->cancelVerification(); + } + } + } + }); connect(ChatPage::instance(), &ChatPage::recievedDeviceVerificationMac, this, @@ -104,6 +188,12 @@ DeviceVerificationFlow::getSender() return this->sender; } +std::vector +DeviceVerificationFlow::getSasList() +{ + return this->sasList; +} + void DeviceVerificationFlow::setTransactionId(QString transaction_id_) { @@ -133,6 +223,8 @@ void DeviceVerificationFlow::setSender(bool sender_) { this->sender = sender_; + if (this->sender == true) + this->transaction_id = http::client()->generate_txn_id(); } //! accepts a verification @@ -147,23 +239,26 @@ DeviceVerificationFlow::acceptVerificationRequest() req.key_agreement_protocol = "curve25519-hkdf-sha256"; req.hash = "sha256"; req.message_authentication_code = "hkdf-hmac-sha256"; - req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal, - mtx::events::msg::SASMethods::Emoji}; - req.commitment = ""; - - emit this->verificationRequestAccepted(this->method); + if (this->method == DeviceVerificationFlow::Method::Emoji) + req.short_authentication_string = {mtx::events::msg::SASMethods::Emoji}; + else if (this->method == DeviceVerificationFlow::Method::Decimal) + req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal}; + req.commitment = mtx::crypto::bin2base64_unpadded( + mtx::crypto::sha256(this->sas->public_key() + this->canonical_json.dump())); body[this->toClient][this->deviceId.toStdString()] = req; + std::cout << "Accepting the Verification" << std::endl; + std::cout << json(body) << std::endl; + http::client() ->send_to_device( - this->transaction_id, body, [this](mtx::http::RequestErr err) { + this->transaction_id, body, [](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to accept verification request: {} {}", err->matrix_error.error, static_cast(err->status_code)); - emit this->verificationRequestAccepted(rand() % 2 ? Emoji : Decimal); }); } //! starts the verification flow @@ -183,6 +278,7 @@ DeviceVerificationFlow::startVerificationRequest() mtx::events::msg::SASMethods::Emoji}; body[this->toClient][this->deviceId.toStdString()] = req; + this->canonical_json = nlohmann::json(req); http::client() ->send_to_devicewarn("failed to start verification request: {} {}", err->matrix_error.error, static_cast(err->status_code)); - std::cout << nlohmann::json(body).dump(2) << std::endl; }); } //! sends a verification request @@ -236,6 +331,8 @@ DeviceVerificationFlow::cancelVerification() body[this->toClient][deviceId.toStdString()] = req; + emit this->verificationCanceled(); + http::client() ->send_to_device( @@ -254,7 +351,7 @@ DeviceVerificationFlow::sendVerificationKey() mtx::requests::ToDeviceMessages body; mtx::events::msg::KeyVerificationKey req; - req.key = ""; + req.key = this->sas->public_key(); req.transaction_id = this->transaction_id; body[this->toClient][deviceId.toStdString()] = req; diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index b651394b..bddf8edd 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -7,6 +7,8 @@ class QTimer; +using sas_ptr = std::unique_ptr; + class DeviceVerificationFlow : public QObject { Q_OBJECT @@ -16,6 +18,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(std::vector sasList READ getSasList) public: enum Method @@ -30,6 +33,7 @@ public: QString getUserId(); QString getDeviceId(); Method getMethod(); + std::vector getSasList(); void setTransactionId(QString transaction_id_); bool getSender(); void setUserId(QString userID); @@ -37,6 +41,8 @@ public: void setMethod(Method method_); void setSender(bool sender_); + nlohmann::json canonical_json; + public slots: //! sends a verification request void sendVerificationRequest(); @@ -66,6 +72,10 @@ private: bool sender; QTimer *timeout = nullptr; + sas_ptr sas; + std::string mac_method; std::string transaction_id; + std::string commitment; mtx::identifiers::User toClient; + std::vector sasList; }; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 22fe4d6d..aaefaed4 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -170,32 +170,44 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin &ChatPage::decryptSidebarChanged, this, &TimelineViewManager::updateEncryptedDescriptions); - connect(dynamic_cast(parent), - &ChatPage::recievedDeviceVerificationRequest, - this, - [this](const mtx::events::collections::DeviceEvents &message) { - auto msg = - std::get>(message); - QString tranID = QString::fromStdString(msg.content.transaction_id); - QString deviceId = QString::fromStdString(msg.content.from_device); - QString userId = QString::fromStdString(msg.sender); - if (!(this->dvList->exist(tranID))) { - emit newDeviceVerificationRequest(tranID, userId, deviceId); - } - }); - connect(dynamic_cast(parent), - &ChatPage::recievedDeviceVerificationStart, - this, - [this](const mtx::events::collections::DeviceEvents &message) { - auto msg = - std::get>(message); - QString tranID = QString::fromStdString(msg.content.transaction_id); - QString deviceId = QString::fromStdString(msg.content.from_device); - QString userId = QString::fromStdString(msg.sender); - if (!(this->dvList->exist(tranID))) { - emit newDeviceVerificationRequest(tranID, userId, deviceId); - } - }); + connect( + dynamic_cast(parent), + &ChatPage::recievedDeviceVerificationRequest, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + auto flow = new DeviceVerificationFlow(this); + if (!(this->dvList->exist(QString::fromStdString(msg.content.transaction_id)))) { + if (std::find(msg.content.methods.begin(), + msg.content.methods.end(), + mtx::events::msg::VerificationMethods::SASv1) != + msg.content.methods.end()) { + emit newDeviceVerificationRequest( + std::move(flow), + QString::fromStdString(msg.content.transaction_id), + QString::fromStdString(msg.sender), + QString::fromStdString(msg.content.from_device)); + } + } + }); + connect( + dynamic_cast(parent), + &ChatPage::recievedDeviceVerificationStart, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + auto flow = new DeviceVerificationFlow(this); + flow->canonical_json = nlohmann::json(msg.content); + if (!(this->dvList->exist(QString::fromStdString(msg.content.transaction_id)))) { + emit newDeviceVerificationRequest( + std::move(flow), + QString::fromStdString(msg.content.transaction_id), + QString::fromStdString(msg.sender), + QString::fromStdString(msg.content.from_device)); + } + }); } void diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 70912715..946461f9 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -67,7 +67,10 @@ signals: void initialSyncChanged(bool isInitialSync); void replyingEventChanged(QString replyingEvent); void replyClosed(); - void newDeviceVerificationRequest(QString transactionId, QString userId, QString deviceId); + void newDeviceVerificationRequest(DeviceVerificationFlow *flow, + QString transactionId, + QString userId, + QString deviceId); public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids); -- cgit 1.5.1 From ce013e67a63edf10b0b0357cd1318ce622a74e97 Mon Sep 17 00:00:00 2001 From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com> Date: Tue, 23 Jun 2020 03:35:56 +0530 Subject: Add some more slots and mac --- .../qml/device-verification/DeviceVerification.qml | 4 +- src/ChatPage.h | 2 + src/DeviceVerificationFlow.cpp | 195 +++++++++++++++++---- src/DeviceVerificationFlow.h | 6 + src/Olm.cpp | 11 +- src/timeline/TimelineViewManager.cpp | 1 + 6 files changed, 172 insertions(+), 47 deletions(-) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 316fbe40..1a3d1432 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -240,7 +240,7 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "They match." - onClicked: { stack.replace(awaitingVerificationConfirmation); flow.acceptDevice(); } + onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); } } } } @@ -379,7 +379,7 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "They match." - onClicked: { stack.replace(awaitingVerificationConfirmation); flow.acceptDevice(); } + onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); } } } } diff --git a/src/ChatPage.h b/src/ChatPage.h index b05a388d..172f74fe 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -175,6 +175,8 @@ signals: void recievedDeviceVerificationKey(const mtx::events::collections::DeviceEvents &message); void recievedDeviceVerificationMac(const mtx::events::collections::DeviceEvents &message); void recievedDeviceVerificationStart(const mtx::events::collections::DeviceEvents &message); + void recievedDeviceVerificationReady(const mtx::events::collections::DeviceEvents &message); + void recievedDeviceVerificationDone(const mtx::events::collections::DeviceEvents &message); private slots: void showUnreadMessageNotification(int count); diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index 607cc279..0de94c50 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -1,11 +1,10 @@ #include "DeviceVerificationFlow.h" #include "ChatPage.h" #include "Logging.h" +#include "Utils.h" #include -#include // only for debugging #include -#include // only for debugging static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes @@ -28,32 +27,27 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - if (std::find(msg.content.key_agreement_protocols.begin(), - msg.content.key_agreement_protocols.end(), - "curve25519-hkdf-sha256") != - msg.content.key_agreement_protocols.end() && - std::find(msg.content.hashes.begin(), - msg.content.hashes.end(), - "sha256") != msg.content.hashes.end() && + if ((std::find(msg.content.key_agreement_protocols.begin(), + msg.content.key_agreement_protocols.end(), + "curve25519-hkdf-sha256") != + msg.content.key_agreement_protocols.end()) && + (std::find(msg.content.hashes.begin(), + msg.content.hashes.end(), + "sha256") != msg.content.hashes.end()) && (std::find(msg.content.message_authentication_codes.begin(), msg.content.message_authentication_codes.end(), "hmac-sha256") != - msg.content.message_authentication_codes.end() || - std::find(msg.content.message_authentication_codes.begin(), - msg.content.message_authentication_codes.end(), - "hkdf-hmac-sha256") != - msg.content.message_authentication_codes.end()) && - (std::find(msg.content.short_authentication_string.begin(), - msg.content.short_authentication_string.end(), - mtx::events::msg::SASMethods::Decimal) != - msg.content.short_authentication_string.end() || - std::find(msg.content.short_authentication_string.begin(), - msg.content.short_authentication_string.end(), - mtx::events::msg::SASMethods::Emoji) != - msg.content.short_authentication_string.end())) { - this->sendVerificationKey(); // Not sure about this maybe - // those optional methods - this->canonical_json = nlohmann::json(msg); + msg.content.message_authentication_codes.end()) && + ((std::find(msg.content.short_authentication_string.begin(), + msg.content.short_authentication_string.end(), + mtx::events::msg::SASMethods::Decimal) != + msg.content.short_authentication_string.end()) || + (std::find(msg.content.short_authentication_string.begin(), + msg.content.short_authentication_string.end(), + mtx::events::msg::SASMethods::Emoji) != + msg.content.short_authentication_string.end()))) { + this->acceptVerificationRequest(); + this->canonical_json = nlohmann::json(msg.content); } else { this->cancelVerification(); } @@ -67,12 +61,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - if ((msg.content.method == - mtx::events::msg::VerificationMethods::SASv1) && - (msg.content.key_agreement_protocol == "curve25519-hkdf-sha256") && + if ((msg.content.key_agreement_protocol == "curve25519-hkdf-sha256") && (msg.content.hash == "sha256") && - ((msg.content.message_authentication_code == "hkdf-hmac-sha256") || - (msg.content.message_authentication_code == "hmac-sha256"))) { + (msg.content.message_authentication_code == "hkdf-hmac-sha256")) { this->commitment = msg.content.commitment; if (std::find(msg.content.short_authentication_string.begin(), msg.content.short_authentication_string.end(), @@ -136,8 +127,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) } else { if (this->commitment == mtx::crypto::bin2base64_unpadded(mtx::crypto::sha256( - msg.content.key + - this->canonical_json["content"].dump()))) { + msg.content.key + this->canonical_json.dump()))) { emit this->verificationRequestAccepted(this->method); } else { this->cancelVerification(); @@ -152,7 +142,51 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - std::cout << "Recieved Event Mac" << std::endl; + std::string info = + "MATRIX_KEY_VERIFICATION_MAC" + this->toClient.to_string() + + this->deviceId.toStdString() + + http::client()->user_id().to_string() + + http::client()->device_id() + this->transaction_id; + + std::vector key_list; + std::string key_string; + for (auto mac : msg.content.mac) { + if (mac.second == + this->sas->calculate_mac(this->device_keys[mac.first], + info + mac.first)) { + key_string += mac.first; + } else { + this->cancelVerification(); + return; + } + } + if (msg.content.keys == + this->sas->calculate_mac(key_string, info + "KEY_IDS")) { + this->sendVerificationDone(); + } else { + this->cancelVerification(); + } + } + }); + connect(ChatPage::instance(), + &ChatPage::recievedDeviceVerificationReady, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + if (msg.content.transaction_id == this->transaction_id) { + this->startVerificationRequest(); + } + }); + connect(ChatPage::instance(), + &ChatPage::recievedDeviceVerificationDone, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + if (msg.content.transaction_id == this->transaction_id) { + this->startVerificationRequest(); + emit this->deviceVerified(); } }); timeout->start(TIMEOUT); @@ -205,6 +239,34 @@ 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; + } + } + } + } + }); } void @@ -248,9 +310,6 @@ DeviceVerificationFlow::acceptVerificationRequest() body[this->toClient][this->deviceId.toStdString()] = req; - std::cout << "Accepting the Verification" << std::endl; - std::cout << json(body) << std::endl; - http::client() ->send_to_device( @@ -261,6 +320,50 @@ DeviceVerificationFlow::acceptVerificationRequest() static_cast(err->status_code)); }); } +//! responds verification request +void +DeviceVerificationFlow::sendVerificationReady() +{ + mtx::requests::ToDeviceMessages body; + mtx::events::msg::KeyVerificationReady req; + + req.from_device = http::client()->device_id(); + req.transaction_id = this->transaction_id; + req.methods = {mtx::events::msg::VerificationMethods::SASv1}; + + body[this->toClient][this->deviceId.toStdString()] = req; + + http::client() + ->send_to_device( + this->transaction_id, body, [](mtx::http::RequestErr err) { + if (err) + nhlog::net()->warn("failed to send verification ready: {} {}", + err->matrix_error.error, + static_cast(err->status_code)); + }); +} +//! accepts a verification +void +DeviceVerificationFlow::sendVerificationDone() +{ + mtx::requests::ToDeviceMessages body; + mtx::events::msg::KeyVerificationDone req; + + req.transaction_id = this->transaction_id; + + body[this->toClient][this->deviceId.toStdString()] = req; + + http::client() + ->send_to_device( + this->transaction_id, body, [](mtx::http::RequestErr err) { + if (err) + nhlog::net()->warn("failed to send verification done: {} {}", + err->matrix_error.error, + static_cast(err->status_code)); + }); +} //! starts the verification flow void DeviceVerificationFlow::startVerificationRequest() @@ -373,9 +476,25 @@ DeviceVerificationFlow::sendVerificationMac() mtx::requests::ToDeviceMessages body; mtx::events::msg::KeyVerificationMac req; + std::string info = "MATRIX_KEY_VERIFICATION_MAC" + http::client()->user_id().to_string() + + http::client()->device_id() + this->toClient.to_string() + + this->deviceId.toStdString() + this->transaction_id; + req.transaction_id = this->transaction_id; - // req.mac = ""; - req.keys = ""; + //! this vector stores the type of the key and the key + std::vector> key_list; + key_list.push_back(make_pair("ed25519", olm::client()->identity_keys().ed25519)); + std::sort(key_list.begin(), key_list.end()); + for (auto x : key_list) { + req.mac.insert( + std::make_pair(x.first + ":" + http::client()->device_id(), + this->sas->calculate_mac( + x.second, info + x.first + ":" + http::client()->device_id()))); + req.keys += x.first + ":" + http::client()->device_id() + ","; + } + + req.keys = + this->sas->calculate_mac(req.keys.substr(0, req.keys.size() - 1), info + "KEY_IDS"); body[this->toClient][deviceId.toStdString()] = req; diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index bddf8edd..81ab9c99 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -2,6 +2,7 @@ #include "Olm.h" +#include "mtx/responses/crypto.hpp" #include #include @@ -46,6 +47,10 @@ public: public slots: //! sends a verification request void sendVerificationRequest(); + //! accepts a verification request + void sendVerificationReady(); + //! completes the verification flow(); + void sendVerificationDone(); //! accepts a verification void acceptVerificationRequest(); //! starts the verification flow @@ -78,4 +83,5 @@ private: std::string commitment; mtx::identifiers::User toClient; std::vector sasList; + std::map device_keys; }; diff --git a/src/Olm.cpp b/src/Olm.cpp index 6c1d3fdc..7d7037c9 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -9,7 +9,6 @@ #include "MatrixClient.h" #include "Utils.h" #include -#include // only for debugging static const std::string STORAGE_SECRET_KEY("secret"); constexpr auto MEGOLM_ALGO = "m.megolm.v1.aes-sha2"; @@ -79,22 +78,20 @@ handle_to_device_messages(const std::vectorrecievedDeviceVerificationAccept(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationRequest)) { ChatPage::instance()->recievedDeviceVerificationRequest(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationCancel)) { ChatPage::instance()->recievedDeviceVerificationCancel(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationKey)) { ChatPage::instance()->recievedDeviceVerificationKey(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationMac)) { ChatPage::instance()->recievedDeviceVerificationMac(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationStart)) { ChatPage::instance()->recievedDeviceVerificationStart(msg); - std::cout << j_msg.dump(2) << std::endl; + } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationReady)) { + ChatPage::instance()->recievedDeviceVerificationReady(msg); + } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationDone)) { + ChatPage::instance()->recievedDeviceVerificationDone(msg); } else { nhlog::crypto()->warn("unhandled event: {}", j_msg.dump(2)); } diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index aaefaed4..7d016cbd 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -183,6 +183,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin msg.content.methods.end(), mtx::events::msg::VerificationMethods::SASv1) != msg.content.methods.end()) { + flow->sendVerificationReady(); emit newDeviceVerificationRequest( std::move(flow), QString::fromStdString(msg.content.transaction_id), -- cgit 1.5.1 From d49ab156569f4f963a2306ff8074b6a22f28a31c Mon Sep 17 00:00:00 2001 From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com> Date: Tue, 23 Jun 2020 23:29:00 +0530 Subject: Some Improvements - DeviceVerificationList change to LinkedList to improve time complexity while deleting - Downgrade the flow to not use key.verification.done and key.verification.ready --- resources/qml/TimelineView.qml | 1 + .../qml/device-verification/DeviceVerification.qml | 26 +++++++++++++--------- src/DeviceVerificationFlow.cpp | 6 +++-- src/timeline/TimelineViewManager.cpp | 17 ++++---------- src/timeline/TimelineViewManager.h | 3 ++- 5 files changed, 26 insertions(+), 27 deletions(-) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 99d14685..7ece08e2 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -110,6 +110,7 @@ Page { flow.sender = false; flow.deviceId = deviceId; flow.tranId = transactionId; + deviceVerificationList.add(flow.tranId); var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow,sender: false}); dialog.show(); diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 1a3d1432..03fc5055 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -30,7 +30,11 @@ ApplicationWindow { implicitHeight: currentItem.implicitHeight } - onClosing: stack.replace(newVerificationRequest) + onClosing: { + flow.cancelVerification(); + deviceVerificationList.remove(flow.tranId); + delete flow; + } property var flow Connections { @@ -78,7 +82,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -135,7 +139,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -179,7 +183,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -230,7 +234,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -369,7 +373,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -413,7 +417,7 @@ ApplicationWindow { onClicked: { dialog.close(); flow.cancelVerification(); - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -451,7 +455,7 @@ ApplicationWindow { text: "Close" onClicked: { dialog.close() - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -485,8 +489,8 @@ ApplicationWindow { Layout.alignment: Qt.AlignRight text: "Close" onClicked: { - dialog.close() - // deviceVerificationList.remove(flow.tranId); + dialog.close(); + deviceVerificationList.remove(flow.tranId); delete flow; } } @@ -521,7 +525,7 @@ ApplicationWindow { text: "Close" onClicked: { dialog.close() - // deviceVerificationList.remove(flow.tranId); + deviceVerificationList.remove(flow.tranId); delete flow; } } diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index 0de94c50..db76aeb1 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -1,7 +1,6 @@ #include "DeviceVerificationFlow.h" #include "ChatPage.h" #include "Logging.h" -#include "Utils.h" #include #include @@ -162,7 +161,10 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) } if (msg.content.keys == this->sas->calculate_mac(key_string, info + "KEY_IDS")) { - this->sendVerificationDone(); + // uncomment this in future to be compatible with the + // MSC2366 this->sendVerificationDone(); and remoeve the + // below line + emit this->deviceVerified(); } else { this->cancelVerification(); } diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 7d016cbd..234b0bb6 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -26,26 +26,17 @@ namespace msgs = mtx::events::msg; void DeviceVerificationList::add(QString tran_id) { - this->dv_list.push_back(tran_id); + this->dv_list.append(tran_id); } void DeviceVerificationList::remove(QString tran_id) { - for (QVector::iterator it = 0; it != (this->dv_list).end(); ++it) { - if (*it == tran_id) { - this->dv_list.erase(it); - break; - } - } + this->dv_list.removeOne(tran_id); } bool DeviceVerificationList::exist(QString tran_id) { - for (int i = 0; i < (this->dv_list).size(); ++i) { - if (dv_list[i] == tran_id) - return true; - } - return false; + return this->dv_list.contains(tran_id); } void @@ -183,7 +174,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin msg.content.methods.end(), mtx::events::msg::VerificationMethods::SASv1) != msg.content.methods.end()) { - flow->sendVerificationReady(); + // flow->sendVerificationReady(); emit newDeviceVerificationRequest( std::move(flow), QString::fromStdString(msg.content.transaction_id), diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 946461f9..8af6d137 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -31,7 +32,7 @@ public: Q_INVOKABLE bool exist(QString tran_id); private: - QVector dv_list; + QLinkedList dv_list; }; class TimelineViewManager : public QObject -- cgit 1.5.1 From 1633650303e2129ae1e255f4e17a0fbff13638b1 Mon Sep 17 00:00:00 2001 From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com> Date: Wed, 24 Jun 2020 23:05:32 +0530 Subject: Some more changes - remove unnecessary field sender in userprofile.qml - cover user facing string with qsTr to get picked by translations - add spacing and fix theming issue - increase and add color to username - change back to QVector from QLinkedList cause I have mistaken better time complexity to give better benchmark red --- resources/qml/TimelineView.qml | 2 +- resources/qml/UserProfile.qml | 36 ++-- .../qml/device-verification/DeviceVerification.qml | 209 ++++++++++++++++----- src/timeline/TimelineViewManager.cpp | 6 +- src/timeline/TimelineViewManager.h | 3 +- 5 files changed, 193 insertions(+), 63 deletions(-) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 7ece08e2..e52d588c 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -112,7 +112,7 @@ Page { flow.tranId = transactionId; deviceVerificationList.add(flow.tranId); var dialog = deviceVerificationDialog.createObject(timelineRoot, - {flow: flow,sender: false}); + {flow: flow}); dialog.show(); } } diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index 80415a29..f060b0e3 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -13,7 +13,7 @@ ApplicationWindow{ id:userProfileDialog height: 500 - width: 500 + width: 400 modality:Qt.WindowModal Layout.alignment: Qt.AlignHCenter palette: colors @@ -64,6 +64,9 @@ ApplicationWindow{ id: userProfileName text: user_data.userName fontSizeMode: Text.HorizontalFit + font.pixelSize: 16 + color:timelineManager.userColor(modelData.userId, colors.window) + font.bold: true Layout.alignment: Qt.AlignHCenter } @@ -71,6 +74,8 @@ ApplicationWindow{ id: matrixUserID text: user_data.userId fontSizeMode: Text.HorizontalFit + font.pixelSize: 16 + color:colors.text Layout.alignment: Qt.AlignHCenter } @@ -79,8 +84,6 @@ ApplicationWindow{ implicitWidth: userProfileDialog.width-20 clip: true Layout.alignment: Qt.AlignHCenter - ScrollBar.horizontal.policy: ScrollBar.AlwaysOn - ScrollBar.vertical.policy: ScrollBar.AlwaysOn ListView{ id: deviceList @@ -98,6 +101,7 @@ ApplicationWindow{ Text{ Layout.fillWidth: true color: colors.text + font.bold: true Layout.alignment: Qt.AlignRight text: deviceID } @@ -116,12 +120,15 @@ ApplicationWindow{ {userId : user_data.userId,sender: true,deviceId : model.deviceID}); deviceVerificationList.add(newFlow.tranId); var dialog = deviceVerificationDialog.createObject(userProfileDialog, - {flow: newFlow,sender: true}); + {flow: newFlow}); dialog.show(); } + palette { + button: "white" + } contentItem: Text { text: verifyButton.text - color: colors.background + color: "black" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } @@ -134,19 +141,26 @@ ApplicationWindow{ id: okbutton text:"OK" onClicked: userProfileDialog.close() - anchors.margins: { - right:10 - bottom:10 + anchors { + right: parent.right + bottom: parent.bottom + } + + anchors.margins : { + right : 10 + bottom : 10 + } + + palette { + button: "white" } contentItem: Text { text: okbutton.text - color: colors.background + color: "black" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } - - Layout.alignment: Qt.AlignRight | Qt.AlignBottom } } diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 03fc5055..12e38f29 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -7,7 +7,6 @@ import Qt.labs.settings 1.0 import im.nheko 1.0 ApplicationWindow { - property bool sender: true title: stack.currentItem.title id: dialog @@ -25,7 +24,7 @@ ApplicationWindow { width: stack.implicitWidth StackView { id: stack - initialItem: sender == true?newVerificationRequest:acceptNewVerificationRequest + initialItem: flow.sender == true?newVerificationRequest:acceptNewVerificationRequest implicitWidth: currentItem.implicitWidth implicitHeight: currentItem.implicitHeight } @@ -52,7 +51,7 @@ ApplicationWindow { Component { id: newVerificationRequest Pane { - property string title: "Sending Device Verification Request" + property string title: qsTr("Sending Device Verification Request") ColumnLayout { spacing: 16 Label { @@ -60,8 +59,8 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true wrapMode: Text.Wrap - text: "A new device was added." - + text: qsTr("A new device was added.") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -70,15 +69,24 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true wrapMode: Text.Wrap - text: "The device may have been added by you signing in from another client or physical device. To ensure that no malicious user can eavesdrop on your encrypted communications, you should verify the new device." - + text: qsTr("The device may have been added by you signing in from another client or physical device. To ensure that no malicious user can eavesdrop on your encrypted communications, you should verify the new device.") + color:colors.text verticalAlignment: Text.AlignVCenter } RowLayout { Button { Layout.alignment: Qt.AlignLeft - text: "Cancel" + text: qsTr("Cancel") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close(); flow.cancelVerification(); @@ -91,7 +99,16 @@ ApplicationWindow { } Button { Layout.alignment: Qt.AlignRight - text: "Start verification" + text: qsTr("Start verification") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { stack.replace(awaitingVerificationRequestAccept); flow.startVerificationRequest(); } } } @@ -102,7 +119,7 @@ ApplicationWindow { Component { id: acceptNewVerificationRequest Pane { - property string title: "Recieving Device Verification Request" + property string title: qsTr("Recieving Device Verification Request") ColumnLayout { spacing: 16 @@ -111,15 +128,15 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true wrapMode: Text.Wrap - text: "The device was requested to be verified" - + text: qsTr("The device was requested to be verified") + color:colors.text verticalAlignment: Text.AlignVCenter } RowLayout { RadioButton { Layout.alignment: Qt.AlignLeft - text: "Decimal" + text: qsTr("Decimal") onClicked: { flow.method = DeviceVerificationFlow.Decimal } } Item { @@ -127,7 +144,7 @@ ApplicationWindow { } RadioButton { Layout.alignment: Qt.AlignRight - text: "Emoji" + text: qsTr("Emoji") onClicked: { flow.method = DeviceVerificationFlow.Emoji } } } @@ -135,7 +152,16 @@ ApplicationWindow { RowLayout { Button { Layout.alignment: Qt.AlignLeft - text: "Deny" + text: qsTr("Deny") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close(); flow.cancelVerification(); @@ -148,7 +174,16 @@ ApplicationWindow { } Button { Layout.alignment: Qt.AlignRight - text: "Accept" + text: qsTr("Accept") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { stack.replace(awaitingVerificationRequestAccept); flow.acceptVerificationRequest(); } } } @@ -159,7 +194,7 @@ ApplicationWindow { Component { id: awaitingVerificationRequestAccept Pane { - property string title: "Waiting for other party" + property string title: qsTr("Waiting for other party") ColumnLayout { spacing: 16 Label { @@ -168,8 +203,8 @@ ApplicationWindow { Layout.fillWidth: true wrapMode: Text.Wrap id: content - text: "Waiting for other side to accept the verification request." - + text: qsTr("Waiting for other side to accept the verification request.") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -179,7 +214,16 @@ ApplicationWindow { RowLayout { Button { Layout.alignment: Qt.AlignLeft - text: "Cancel" + text: qsTr("Cancel") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close(); flow.cancelVerification(); @@ -198,7 +242,7 @@ ApplicationWindow { Component { id: digitVerification Pane { - property string title: "Verification Code" + property string title: qsTr("Verification Code") ColumnLayout { spacing: 16 Label { @@ -206,8 +250,8 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true wrapMode: Text.Wrap - text: "Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification!" - + text: qsTr("Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification!") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -230,7 +274,16 @@ ApplicationWindow { RowLayout { Button { Layout.alignment: Qt.AlignLeft - text: "They do not match!" + text: qsTr("They do not match!") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close(); flow.cancelVerification(); @@ -243,7 +296,16 @@ ApplicationWindow { } Button { Layout.alignment: Qt.AlignRight - text: "They match." + text: qsTr("They match!") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); } } } @@ -254,7 +316,7 @@ ApplicationWindow { Component { id: emojiVerification Pane { - property string title: "Verification Code" + property string title: qsTr("Verification Code") ColumnLayout { spacing: 16 Label { @@ -262,8 +324,8 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true wrapMode: Text.Wrap - text: "Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification!" - + text: qsTr("Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification!") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -369,7 +431,16 @@ ApplicationWindow { RowLayout { Button { Layout.alignment: Qt.AlignLeft - text: "They do not match!" + text: qsTr("They do not match!") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close(); flow.cancelVerification(); @@ -382,7 +453,16 @@ ApplicationWindow { } Button { Layout.alignment: Qt.AlignRight - text: "They match." + text: qsTr("They match!") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); } } } @@ -393,7 +473,7 @@ ApplicationWindow { Component { id: awaitingVerificationConfirmation Pane { - property string title: "Awaiting Confirmation" + property string title: qsTr("Awaiting Confirmation") ColumnLayout { spacing: 16 Label { @@ -402,8 +482,8 @@ ApplicationWindow { Layout.fillWidth: true wrapMode: Text.Wrap id: content - text: "Waiting for other side to complete verification." - + text: qsTr("Waiting for other side to complete verification.") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -413,7 +493,16 @@ ApplicationWindow { RowLayout { Button { Layout.alignment: Qt.AlignLeft - text: "Cancel" + text: qsTr("Cancel") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close(); flow.cancelVerification(); @@ -432,7 +521,7 @@ ApplicationWindow { Component { id: verificationSuccess Pane { - property string title: "Successful Verification" + property string title: qsTr("Successful Verification") ColumnLayout { spacing: 16 Label { @@ -441,8 +530,8 @@ ApplicationWindow { Layout.fillWidth: true wrapMode: Text.Wrap id: content - text: "Verification successful! Both sides verified their devices!" - + text: qsTr("Verification successful! Both sides verified their devices!") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -452,7 +541,16 @@ ApplicationWindow { } Button { Layout.alignment: Qt.AlignRight - text: "Close" + text: qsTr("Close") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close() deviceVerificationList.remove(flow.tranId); @@ -467,7 +565,7 @@ ApplicationWindow { Component { id: partnerAborted Pane { - property string title: "Verification aborted!" + property string title: qsTr("Verification aborted!") ColumnLayout { spacing: 16 Label { @@ -476,8 +574,8 @@ ApplicationWindow { Layout.fillWidth: true wrapMode: Text.Wrap id: content - text: "Verification canceled by the other party!" - + text: qsTr("Verification canceled by the other party!") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -487,7 +585,16 @@ ApplicationWindow { } Button { Layout.alignment: Qt.AlignRight - text: "Close" + text: qsTr("Close") + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } onClicked: { dialog.close(); deviceVerificationList.remove(flow.tranId); @@ -502,7 +609,7 @@ ApplicationWindow { Component { id: timedout Pane { - property string title: "Verification timed out" + property string title: qsTr("Verification timed out") ColumnLayout { spacing: 16 Text { @@ -511,8 +618,8 @@ ApplicationWindow { Layout.fillWidth: true wrapMode: Text.Wrap id: content - text: "Device verification timed out." - + text: qsTr("Device verification timed out.") + color:colors.text verticalAlignment: Text.AlignVCenter } @@ -521,8 +628,18 @@ ApplicationWindow { Layout.fillWidth: true } Button { + id: timedOutCancel Layout.alignment: Qt.AlignRight - text: "Close" + palette { + button: "white" + } + contentItem: Text { + text: parent.text + color: "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + text: qsTr("Close") onClicked: { dialog.close() deviceVerificationList.remove(flow.tranId); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 234b0bb6..a36a5bda 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -26,17 +26,17 @@ namespace msgs = mtx::events::msg; void DeviceVerificationList::add(QString tran_id) { - this->dv_list.append(tran_id); + this->deviceVerificationList.push_back(tran_id); } void DeviceVerificationList::remove(QString tran_id) { - this->dv_list.removeOne(tran_id); + this->deviceVerificationList.removeOne(tran_id); } bool DeviceVerificationList::exist(QString tran_id) { - return this->dv_list.contains(tran_id); + return this->deviceVerificationList.contains(tran_id); } void diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 8af6d137..38aba021 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -32,7 +31,7 @@ public: Q_INVOKABLE bool exist(QString tran_id); private: - QLinkedList dv_list; + QVector deviceVerificationList; }; class TimelineViewManager : public QObject -- cgit 1.5.1 From 4862be06be6e32c1f4963feabfde010a9f64616c Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Wed, 24 Jun 2020 16:24:22 +0200 Subject: Fix presence indicator --- resources/qml/Avatar.qml | 10 ++++++---- resources/qml/MatrixText.qml | 6 ++++-- resources/qml/Reactions.qml | 13 ++++++++++--- resources/qml/TimelineRow.qml | 12 ++++++------ resources/qml/TimelineView.qml | 21 +++++++++++++-------- resources/qml/UserProfile.qml | 3 ++- resources/qml/delegates/FileMessage.qml | 4 +++- resources/qml/delegates/ImageMessage.qml | 2 +- resources/qml/delegates/MessageDelegate.qml | 12 ++++++------ resources/qml/delegates/PlayableMediaMessage.qml | 4 ++-- resources/qml/delegates/Reply.qml | 4 +++- resources/qml/delegates/TextMessage.qml | 4 +++- .../qml/device-verification/DeviceVerification.qml | 9 +-------- resources/qml/emoji/EmojiPicker.qml | 4 ++-- src/timeline/TimelineViewManager.cpp | 20 ++++++++++++-------- src/timeline/TimelineViewManager.h | 4 ++-- 16 files changed, 76 insertions(+), 56 deletions(-) (limited to 'src/timeline/TimelineViewManager.cpp') diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml index f934e2f6..e687e170 100644 --- a/resources/qml/Avatar.qml +++ b/resources/qml/Avatar.qml @@ -2,11 +2,13 @@ import QtQuick 2.6 import QtQuick.Controls 2.3 import QtGraphicalEffects 1.0 +import im.nheko 1.0 + Rectangle { id: avatar width: 48 height: 48 - radius: settings.avatarCircles ? height/2 : 3 + radius: Settings.avatarCircles ? height/2 : 3 property alias url: img.source property string userid @@ -40,7 +42,7 @@ Rectangle { anchors.fill: parent width: avatar.width height: avatar.height - radius: settings.avatarCircles ? height/2 : 3 + radius: Settings.avatarCircles ? height/2 : 3 } } @@ -52,8 +54,8 @@ Rectangle { height: avatar.height / 6 width: height - radius: settings.avatarCircles ? height / 2 : height / 4 - color: switch (timelineManager.userPresence(userid)) { + radius: Settings.avatarCircles ? height / 2 : height / 4 + color: switch (TimelineManager.userPresence(userid)) { case "online": return "#00cc66" case "unavailable": return "#ff9933" case "offline": // return "#a82353" don't show anything if offline, since it is confusing, if presence is disabled diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml index cbb55bea..d0910045 100644 --- a/resources/qml/MatrixText.qml +++ b/resources/qml/MatrixText.qml @@ -1,6 +1,8 @@ import QtQuick 2.5 import QtQuick.Controls 2.3 +import im.nheko 1.0 + TextEdit { textFormat: TextEdit.RichText readOnly: true @@ -10,10 +12,10 @@ TextEdit { onLinkActivated: { if (/^https:\/\/matrix.to\/#\/(@.*)$/.test(link)) chat.model.openUserProfile(/^https:\/\/matrix.to\/#\/(@.*)$/.exec(link)[1]) - else if (/^https:\/\/matrix.to\/#\/(![^\/]*)$/.test(link)) timelineManager.setHistoryView(/^https:\/\/matrix.to\/#\/(!.*)$/.exec(link)[1]) + else if (/^https:\/\/matrix.to\/#\/(![^\/]*)$/.test(link)) TimelineManager.setHistoryView(/^https:\/\/matrix.to\/#\/(!.*)$/.exec(link)[1]) else if (/^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.test(link)) { var match = /^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.exec(link) - timelineManager.setHistoryView(match[1]) + TimelineManager.setHistoryView(match[1]) chat.positionViewAtIndex(chat.model.idToIndex(match[2]), ListView.Contain) } else Qt.openUrlExternally(link) diff --git a/resources/qml/Reactions.qml b/resources/qml/Reactions.qml index c1091756..11109d7f 100644 --- a/resources/qml/Reactions.qml +++ b/resources/qml/Reactions.qml @@ -1,6 +1,8 @@ import QtQuick 2.6 import QtQuick.Controls 2.2 +import im.nheko 1.0 + // This class is for showing Reactions in the timeline row, not for // adding new reactions via the emoji picker Flow { @@ -33,8 +35,13 @@ Flow { ToolTip.text: modelData.users onClicked: { +<<<<<<< HEAD console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + " in room " + reactionFlow.roomId + ". selfReactedEvent: " + modelData.selfReactedEvent) timelineManager.queueReactionMessage(reactionFlow.eventId, modelData.key) +======= + console.debug("Picked " + model.key + "in response to " + reactionFlow.eventId + " in room " + reactionFlow.roomId + ". selfReactedEvent: " + model.selfReactedEvent) + TimelineManager.reactToMessage(reactionFlow.roomId, reactionFlow.eventId, model.key, model.selfReactedEvent) +>>>>>>> Fix presence indicator } @@ -46,7 +53,7 @@ Flow { TextMetrics { id: textMetrics - font.family: settings.emojiFont + font.family: Settings.emojiFont elide: Text.ElideRight elideWidth: 150 text: modelData.key @@ -55,8 +62,8 @@ Flow { Text { anchors.baseline: reactionCounter.baseline id: reactionText - text: textMetrics.elidedText + (textMetrics.elidedText == modelData.key ? "" : "…") - font.family: settings.emojiFont + text: textMetrics.elidedText + (textMetrics.elidedText == model.key ? "" : "…") + font.family: Settings.emojiFont color: reaction.hovered ? colors.highlight : colors.text maximumLineCount: 1 } diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index d1c20278..db58eb22 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -29,7 +29,7 @@ Item { } } Rectangle { - color: (settings.messageHoverHighlight && parent.containsMouse) ? colors.base : "transparent" + color: (Settings.messageHoverHighlight && parent.containsMouse) ? colors.base : "transparent" anchors.fill: row } RowLayout { @@ -48,8 +48,8 @@ Item { // fancy reply, if this is a reply Reply { visible: model.replyTo - modelData: chat.model.getDump(model.replyTo, model.id) - userColor: timelineManager.userColor(modelData.userId, colors.window) + modelData: chat.model.getDump(model.replyTo) + userColor: TimelineManager.userColor(modelData.userId, colors.window) } // actual message content @@ -84,7 +84,7 @@ Item { width: 16 } EmojiButton { - visible: settings.buttonsInTimeline + visible: Settings.buttonsInTimeline Layout.alignment: Qt.AlignRight | Qt.AlignTop Layout.preferredHeight: 16 width: 16 @@ -96,7 +96,7 @@ Item { event_id: model.id } ImageButton { - visible: settings.buttonsInTimeline + visible: Settings.buttonsInTimeline Layout.alignment: Qt.AlignRight | Qt.AlignTop Layout.preferredHeight: 16 width: 16 @@ -112,7 +112,7 @@ Item { onClicked: chat.model.replyAction(model.id) } ImageButton { - visible: settings.buttonsInTimeline + visible: Settings.buttonsInTimeline Layout.alignment: Qt.AlignRight | Qt.AlignTop Layout.preferredHeight: 16 width: 16 diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index e52d588c..d9302ed7 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -91,7 +91,7 @@ Page { visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker height: visible ? implicitHeight : 0 text: qsTr("Save as") - onTriggered: timelineManager.timeline.saveMedia(messageContextMenu.eventId) + onTriggered: TimelineManager.timeline.saveMedia(messageContextMenu.eventId) } } @@ -104,7 +104,7 @@ Page { DeviceVerification {} } Connections { - target: timelineManager + target: TimelineManager onNewDeviceVerificationRequest: { flow.userId = userId; flow.sender = false; @@ -118,7 +118,7 @@ Page { } Label { - visible: !timelineManager.timeline && !timelineManager.isInitialSync + visible: !TimelineManager.timeline && !TimelineManager.isInitialSync anchors.centerIn: parent text: qsTr("No room open") font.pointSize: 24 @@ -128,7 +128,7 @@ Page { BusyIndicator { visible: running anchors.centerIn: parent - running: timelineManager.isInitialSync + running: TimelineManager.isInitialSync height: 200 width: 200 z: 3 @@ -137,7 +137,7 @@ Page { ListView { id: chat - visible: !!timelineManager.timeline + visible: TimelineManager.timeline != null cacheBuffer: 400 @@ -149,7 +149,7 @@ Page { anchors.leftMargin: 4 anchors.rightMargin: scrollbar.width - model: timelineManager.timeline + model: TimelineManager.timeline boundsBehavior: Flickable.StopAtBounds @@ -197,7 +197,7 @@ Page { onCountChanged: if (atYEnd) model.currentIndex = 0 // Mark last event as read, since we are at the bottom - property int delegateMaxWidth: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > 32) ? settings.timelineMaxWidth : (parent.width - 32) + property int delegateMaxWidth: (Settings.timelineMaxWidth > 100 && (parent.width - Settings.timelineMaxWidth) > 32) ? Settings.timelineMaxWidth : (parent.width - 32) delegate: Rectangle { // This would normally be previousSection, but our model's order is inverted. @@ -303,7 +303,7 @@ Page { Label { id: userName text: chat.model.escapeEmoji(modelData.userName) - color: timelineManager.userColor(modelData.userId, colors.window) + color: TimelineManager.userColor(modelData.userId, colors.window) textFormat: Text.RichText MouseArea { @@ -381,8 +381,13 @@ Page { anchors.rightMargin: 20 anchors.bottom: parent.bottom +<<<<<<< HEAD modelData: chat.model ? chat.model.getDump(chat.model.reply, chat.model.id) : {} userColor: timelineManager.userColor(modelData.userId, colors.window) +======= + modelData: chat.model ? chat.model.getDump(chat.model.reply) : {} + userColor: TimelineManager.userColor(modelData.userId, colors.window) +>>>>>>> Fix presence indicator } ImageButton { diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index f060b0e3..a7ff8a35 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -57,6 +57,7 @@ ApplicationWindow{ height: 130 width: 130 displayName: modelData.userName + userid: modelData.userId Layout.alignment: Qt.AlignHCenter } @@ -65,7 +66,7 @@ ApplicationWindow{ text: user_data.userName fontSizeMode: Text.HorizontalFit font.pixelSize: 16 - color:timelineManager.userColor(modelData.userId, colors.window) + color:TimelineManager.userColor(modelData.userId, colors.window) font.bold: true Layout.alignment: Qt.AlignHCenter } diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml index d8e4215f..158daf45 100644 --- a/resources/qml/delegates/FileMessage.qml +++ b/resources/qml/delegates/FileMessage.qml @@ -1,6 +1,8 @@ import QtQuick 2.6 import QtQuick.Layouts 1.2 +import im.nheko 1.0 + Item { height: row.height + 24 width: parent ? parent.width : undefined @@ -29,7 +31,7 @@ Item { } MouseArea { anchors.fill: parent - onClicked: timelineManager.timeline.saveMedia(model.data.id) + onClicked: TimelineManager.timeline.saveMedia(model.data.id) cursorShape: Qt.PointingHandCursor } } diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml index 3885ddae..b5c51c2c 100644 --- a/resources/qml/delegates/ImageMessage.qml +++ b/resources/qml/delegates/ImageMessage.qml @@ -36,7 +36,7 @@ Item { MouseArea { enabled: model.data.type == MtxEvent.ImageMessage && img.status == Image.Ready anchors.fill: parent - onClicked: timelineManager.openImageOverlay(model.data.url, model.data.id) + onClicked: TimelineManager.openImageOverlay(model.data.url, model.data.id) } } } diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index 9630ae3a..6f69f026 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -37,7 +37,7 @@ Item { roleValue: MtxEvent.EmoteMessage NoticeMessage { formatted: chat.model.escapeEmoji(modelData.userName) + " " + model.data.formattedBody - color: timelineManager.userColor(modelData.userId, colors.window) + color: TimelineManager.userColor(modelData.userId, colors.window) } } DelegateChoice { @@ -100,31 +100,31 @@ Item { // TODO: make a more complex formatter for the power levels. roleValue: MtxEvent.PowerLevels NoticeMessage { - text: timelineManager.timeline.formatPowerLevelEvent(model.data.id) + text: TimelineManager.timeline.formatPowerLevelEvent(model.data.id) } } DelegateChoice { roleValue: MtxEvent.RoomJoinRules NoticeMessage { - text: timelineManager.timeline.formatJoinRuleEvent(model.data.id) + text: TimelineManager.timeline.formatJoinRuleEvent(model.data.id) } } DelegateChoice { roleValue: MtxEvent.RoomHistoryVisibility NoticeMessage { - text: timelineManager.timeline.formatHistoryVisibilityEvent(model.data.id) + text: TimelineManager.timeline.formatHistoryVisibilityEvent(model.data.id) } } DelegateChoice { roleValue: MtxEvent.RoomGuestAccess NoticeMessage { - text: timelineManager.timeline.formatGuestAccessEvent(model.data.id) + text: TimelineManager.timeline.formatGuestAccessEvent(model.data.id) } } DelegateChoice { roleValue: MtxEvent.Member NoticeMessage { - text: timelineManager.timeline.formatMemberEvent(model.data.id); + text: TimelineManager.timeline.formatMemberEvent(model.data.id); } } DelegateChoice { diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 8d2fa8a8..893325b6 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -106,7 +106,7 @@ Rectangle { anchors.fill: parent onClicked: { switch (button.state) { - case "": timelineManager.timeline.cacheMedia(model.data.id); break; + case "": TimelineManager.timeline.cacheMedia(model.data.id); break; case "stopped": media.play(); console.log("play"); button.state = "playing" @@ -127,7 +127,7 @@ Rectangle { } Connections { - target: timelineManager.timeline + target: TimelineManager.timeline onMediaCached: { if (mxcUrl == model.data.url) { media.source = "file://" + cacheUrl diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml index f9fd3f11..d4fffb06 100644 --- a/resources/qml/delegates/Reply.qml +++ b/resources/qml/delegates/Reply.qml @@ -3,6 +3,8 @@ import QtQuick.Controls 2.3 import QtQuick.Layouts 1.2 import QtQuick.Window 2.2 +import im.nheko 1.0 + Item { id: replyComponent @@ -26,7 +28,7 @@ Item { anchors.bottom: replyContainer.bottom width: 4 - color: timelineManager.userColor(reply.modelData.userId, colors.window) + color: TimelineManager.userColor(reply.modelData.userId, colors.window) } Column { diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index cc2d2da0..99ff9329 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -1,10 +1,12 @@ import ".." +import im.nheko 1.0 + MatrixText { property string formatted: model.data.formattedBody text: "" + formatted.replace("
", "
")
 	width: parent ? parent.width : undefined
 	height: isReply ? Math.round(Math.min(timelineRoot.height / 8, implicitHeight)) : undefined
 	clip: true
-	font.pointSize: (settings.enlargeEmojiOnlyMessages && model.data.isOnlyEmoji > 0 && model.data.isOnlyEmoji < 4) ? settings.fontSize * 3 : settings.fontSize
+	font.pointSize: (Settings.enlargeEmojiOnlyMessages && model.data.isOnlyEmoji > 0 && model.data.isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize
 }
diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index 12e38f29..516bc74a 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -2,7 +2,6 @@ import QtQuick 2.3
 import QtQuick.Controls 2.10
 import QtQuick.Window 2.2
 import QtQuick.Layouts 1.10
-import Qt.labs.settings 1.0
 
 import im.nheko 1.0
 
@@ -14,12 +13,6 @@ ApplicationWindow {
 
 	palette: colors
 
-	Settings {
-		id: settings
-		category: "user"
-		property bool emoji_font_family: true
-	}
-
 	height: stack.implicitHeight
 	width: stack.implicitWidth
 	StackView {
@@ -417,7 +410,7 @@ ApplicationWindow {
 									Layout.alignment: Qt.AlignHCenter
 									text: col.emoji.emoji
 									font.pixelSize: Qt.application.font.pixelSize * 2
-									font.family: settings.emoji_font_family
+									font.family: Settings.emojiFont
 								}
 								Label {
 									Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
diff --git a/resources/qml/emoji/EmojiPicker.qml b/resources/qml/emoji/EmojiPicker.qml
index f75221d5..d2ca4da3 100644
--- a/resources/qml/emoji/EmojiPicker.qml
+++ b/resources/qml/emoji/EmojiPicker.qml
@@ -73,7 +73,7 @@ Popup {
                 contentItem: Text {
                     horizontalAlignment: Text.AlignHCenter
                     verticalAlignment: Text.AlignVCenter
-                    font.family: settings.emojiFont
+                    font.family: Settings.emojiFont
                     
                     font.pixelSize: 36
                     text: model.unicode
@@ -104,7 +104,7 @@ Popup {
                 onClicked: {
                     console.debug("Picked " + model.unicode + "in response to " + emojiPopup.event_id)
                     emojiPopup.close()
-                    timelineManager.queueReactionMessage(emojiPopup.event_id, model.unicode)
+                    TimelineManager.queueReactionMessage(emojiPopup.room_id, emojiPopup.event_id, model.unicode)
                 }
             }
 
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index a36a5bda..14c66951 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -80,12 +80,16 @@ TimelineViewManager::userColor(QString id, QColor background)
         return userColors.value(id);
 }
 
-// QString
-// TimelineViewManager::userPresence(QString id) const
-// {
-//         return QString::fromStdString(
-//           mtx::presence::to_string(cache::presenceState(id.toStdString())));
-// }
+QString
+TimelineViewManager::userPresence(QString id) const
+{
+        if (id.isEmpty())
+                return "";
+        else
+                return QString::fromStdString(
+                  mtx::presence::to_string(cache::presenceState(id.toStdString())));
+}
+
 QString
 TimelineViewManager::userStatus(QString id) const
 {
@@ -110,6 +114,8 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
         qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow");
         qmlRegisterType("im.nheko", 1, 0, "UserProfileModel");
         qmlRegisterType("im.nheko", 1, 0, "UserProfileList");
+        qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", this);
+        qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", settings.data());
 
         qRegisterMetaType();
         qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiModel");
@@ -144,8 +150,6 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
         });
 #endif
         container->setMinimumSize(200, 200);
-        view->rootContext()->setContextProperty("timelineManager", this);
-        view->rootContext()->setContextProperty("settings", settings.data());
         view->rootContext()->setContextProperty("deviceVerificationList", this->dvList);
         updateColorPalette();
         view->engine()->addImageProvider("MxcImage", imgProvider);
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 38aba021..af8bc4b6 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -57,7 +57,7 @@ public:
         Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const;
         Q_INVOKABLE QColor userColor(QString id, QColor background);
 
-        // Q_INVOKABLE QString userPresence(QString id) const;
+        Q_INVOKABLE QString userPresence(QString id) const;
         Q_INVOKABLE QString userStatus(QString id) const;
 
 signals:
@@ -131,4 +131,4 @@ private:
 
         DeviceVerificationList *dvList;
 };
-Q_DECLARE_METATYPE(mtx::events::collections::DeviceEvents)
\ No newline at end of file
+Q_DECLARE_METATYPE(mtx::events::collections::DeviceEvents)
-- 
cgit 1.5.1


From ffa61095b8be7c61c3b4cdd693e59239ab668516 Mon Sep 17 00:00:00 2001
From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>
Date: Fri, 26 Jun 2020 15:10:37 +0530
Subject: Error Handling and some fixes

---
 resources/qml/UserProfile.qml                      |  16 ++-
 .../qml/device-verification/DeviceVerification.qml |  52 ++--------
 src/DeviceVerificationFlow.cpp                     | 109 +++++++++++++--------
 src/DeviceVerificationFlow.h                       |  12 ++-
 src/timeline/TimelineViewManager.cpp               |  45 ++++++++-
 5 files changed, 138 insertions(+), 96 deletions(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index 36c8586d..6ef75031 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -108,30 +108,28 @@ ApplicationWindow{
                 //         userProfileList.ignoreUser()
                 //     }
                 // }
-
                 ImageButton{
-                    image:":/icons/icons/ui/round-remove-button.png"
+                    image:":/icons/icons/ui/black-bubble-speech.png"
                     Layout.margins: {
                         left: 5
                         right: 5
                     }
                     ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Kick the user")
+			        ToolTip.text: qsTr("Start a private chat")
                     onClicked : {
-                        userProfileList.kickUser()
+                        userProfileList.startChat()
                     }
                 }
-
                 ImageButton{
-                    image:":/icons/icons/ui/black-bubble-speech.png"
+                    image:":/icons/icons/ui/round-remove-button.png"
                     Layout.margins: {
                         left: 5
                         right: 5
                     }
                     ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Start a conversation")
+			        ToolTip.text: qsTr("Kick the user")
                     onClicked : {
-                        userProfileList.startChat()
+                        userProfileList.kickUser()
                     }
                 }
             }
@@ -205,7 +203,7 @@ ApplicationWindow{
                 text:"OK"
                 onClicked: userProfileDialog.close()
                 
-                Layout.alignment: Qt.AlignRight
+                Layout.alignment: Qt.AlignRight | Qt.AlignBottom
 
                 Layout.margins : {
                     right : 10
diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index ca21f484..15c2d7a2 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -22,12 +22,6 @@ ApplicationWindow {
 		implicitHeight: currentItem.implicitHeight
 	}
 
-	onClosing: {
-		flow.cancelVerification();
-		deviceVerificationList.remove(flow.tranId);
-		delete flow; 
-	}
-
 	property var flow
 	Connections {
 		target: flow
@@ -123,33 +117,6 @@ ApplicationWindow {
 					color:colors.text
 					verticalAlignment: Text.AlignVCenter
 				}
-
-				RowLayout {
-					RadioButton {
-						id: decimalRadio
-						Layout.alignment: Qt.AlignLeft
-						text: qsTr("Decimal")
-						contentItem: Text {
-    					    text: decimalRadio.text
-    					    color: colors.text
-    					}
-						onClicked: { flow.method = DeviceVerificationFlow.Decimal }
-					}
-					Item {
-						Layout.fillWidth: true
-					}
-					RadioButton {
-						id: emojiRadio
-						Layout.alignment: Qt.AlignRight
-						text: qsTr("Emoji")
-						contentItem: Text {
-    					    text: emojiRadio.text
-    					    color: colors.text
-    					}
-						onClicked: { flow.method = DeviceVerificationFlow.Emoji }
-					}
-				}
-
 				RowLayout {
 					Button {
 						Layout.alignment: Qt.AlignLeft
@@ -165,9 +132,8 @@ ApplicationWindow {
                         }
 						onClicked: { 
 							dialog.close();
-							flow.cancelVerification();
+							flow.cancelVerification(DeviceVerificationFlow.User);
 							deviceVerificationList.remove(flow.tranId);
-							delete flow; 
 						}
 					}
 					Item {
@@ -227,9 +193,8 @@ ApplicationWindow {
                         }
 						onClicked: { 
 							dialog.close(); 
-							flow.cancelVerification();
+							flow.cancelVerification(DeviceVerificationFlow.User);
 							deviceVerificationList.remove(flow.tranId);
-							delete flow; 
 						}
 					}
 					Item {
@@ -261,14 +226,17 @@ ApplicationWindow {
 					Label {
 						font.pixelSize: Qt.application.font.pixelSize * 2
 						text: flow.sasList[0]
+						color:colors.text
 					}
 					Label {
 						font.pixelSize: Qt.application.font.pixelSize * 2
 						text: flow.sasList[1]
+						color:colors.text
 					}
 					Label {
 						font.pixelSize: Qt.application.font.pixelSize * 2
 						text: flow.sasList[2]
+						color:colors.text
 					}
 				}
 
@@ -287,9 +255,8 @@ ApplicationWindow {
                         }
 						onClicked: { 
 							dialog.close(); 
-							flow.cancelVerification();
+							flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
 							deviceVerificationList.remove(flow.tranId);
-							delete flow; 
 						}
 					}
 					Item {
@@ -411,6 +378,7 @@ ApplicationWindow {
 							implicitWidth: col.width
 							ColumnLayout {
 								id: col
+								Layout.fillWidth: true
 								anchors.bottom: parent.bottom
 								property var emoji: emojis.mapping[flow.sasList[index]]
 								Label {
@@ -424,6 +392,7 @@ ApplicationWindow {
 								Label {
 									Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
 									text: col.emoji.description
+									color:colors.text
 								}
 							}
 						}
@@ -445,9 +414,8 @@ ApplicationWindow {
                         }
 						onClicked: { 
 							dialog.close(); 
-							flow.cancelVerification();
+							flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
 							deviceVerificationList.remove(flow.tranId);
-							delete flow; 
 						}
 					}
 					Item {
@@ -507,7 +475,7 @@ ApplicationWindow {
                         }
 						onClicked: { 
 							dialog.close(); 
-							flow.cancelVerification(); 
+							flow.cancelVerification(DeviceVerificationFlow.User); 
 							deviceVerificationList.remove(flow.tranId);
 							delete flow;
 						}
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index 2c6e9c1e..b5134a3b 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -17,42 +17,53 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
         this->isMacVerified = false;
         connect(timeout, &QTimer::timeout, this, [this]() {
                 emit timedout();
+                this->cancelVerification(DeviceVerificationFlow::Error::Timeout);
                 this->deleteLater();
         });
 
-        connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationStart,
-                this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get>(message);
-                        if (msg.content.transaction_id == this->transaction_id) {
-                                if ((std::find(msg.content.key_agreement_protocols.begin(),
-                                               msg.content.key_agreement_protocols.end(),
-                                               "curve25519-hkdf-sha256") !=
-                                     msg.content.key_agreement_protocols.end()) &&
-                                    (std::find(msg.content.hashes.begin(),
-                                               msg.content.hashes.end(),
-                                               "sha256") != msg.content.hashes.end()) &&
-                                    (std::find(msg.content.message_authentication_codes.begin(),
-                                               msg.content.message_authentication_codes.end(),
-                                               "hmac-sha256") !=
-                                     msg.content.message_authentication_codes.end()) &&
-                                    ((std::find(msg.content.short_authentication_string.begin(),
+        connect(
+          ChatPage::instance(),
+          &ChatPage::recievedDeviceVerificationStart,
+          this,
+          [this](const mtx::events::collections::DeviceEvents &message) {
+                  auto msg =
+                    std::get>(message);
+                  if (msg.content.transaction_id == this->transaction_id) {
+                          if ((std::find(msg.content.key_agreement_protocols.begin(),
+                                         msg.content.key_agreement_protocols.end(),
+                                         "curve25519-hkdf-sha256") !=
+                               msg.content.key_agreement_protocols.end()) &&
+                              (std::find(msg.content.hashes.begin(),
+                                         msg.content.hashes.end(),
+                                         "sha256") != msg.content.hashes.end()) &&
+                              (std::find(msg.content.message_authentication_codes.begin(),
+                                         msg.content.message_authentication_codes.end(),
+                                         "hmac-sha256") !=
+                               msg.content.message_authentication_codes.end())) {
+                                  if (std::find(msg.content.short_authentication_string.begin(),
                                                 msg.content.short_authentication_string.end(),
                                                 mtx::events::msg::SASMethods::Decimal) !=
-                                      msg.content.short_authentication_string.end()) ||
-                                     (std::find(msg.content.short_authentication_string.begin(),
-                                                msg.content.short_authentication_string.end(),
-                                                mtx::events::msg::SASMethods::Emoji) !=
-                                      msg.content.short_authentication_string.end()))) {
-                                        this->acceptVerificationRequest();
-                                        this->canonical_json = nlohmann::json(msg.content);
-                                } else {
-                                        this->cancelVerification();
-                                }
-                        }
-                });
+                                      msg.content.short_authentication_string.end()) {
+                                          this->method = DeviceVerificationFlow::Method::Emoji;
+                                  } else if (std::find(
+                                               msg.content.short_authentication_string.begin(),
+                                               msg.content.short_authentication_string.end(),
+                                               mtx::events::msg::SASMethods::Emoji) !=
+                                             msg.content.short_authentication_string.end()) {
+                                          this->method = DeviceVerificationFlow::Method::Decimal;
+                                  } else {
+                                          this->cancelVerification(
+                                            DeviceVerificationFlow::Error::UnknownMethod);
+                                          return;
+                                  }
+                                  this->acceptVerificationRequest();
+                                  this->canonical_json = nlohmann::json(msg.content);
+                          } else {
+                                  this->cancelVerification(
+                                    DeviceVerificationFlow::Error::UnknownMethod);
+                          }
+                  }
+          });
         connect(
           ChatPage::instance(),
           &ChatPage::recievedDeviceVerificationAccept,
@@ -76,7 +87,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
                                   this->mac_method = msg.content.message_authentication_code;
                                   this->sendVerificationKey();
                           } else {
-                                  this->cancelVerification();
+                                  this->cancelVerification(
+                                    DeviceVerificationFlow::Error::UnknownMethod);
                           }
                   }
           });
@@ -130,7 +142,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
                                         msg.content.key + this->canonical_json.dump()))) {
                                           emit this->verificationRequestAccepted(this->method);
                                   } else {
-                                          this->cancelVerification();
+                                          this->cancelVerification(
+                                            DeviceVerificationFlow::Error::MismatchedCommitment);
                                   }
                           }
                   }
@@ -156,7 +169,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
                                               this->sas->calculate_mac(this->device_keys[mac.first],
                                                                        info + mac.first)) {
                                           } else {
-                                                  this->cancelVerification();
+                                                  this->cancelVerification(
+                                                    DeviceVerificationFlow::Error::KeyMismatch);
                                                   return;
                                           }
                                   }
@@ -172,7 +186,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
                                   else
                                           this->isMacVerified = true;
                           } else {
-                                  this->cancelVerification();
+                                  this->cancelVerification(
+                                    DeviceVerificationFlow::Error::KeyMismatch);
                           }
                   }
           });
@@ -429,15 +444,31 @@ DeviceVerificationFlow::sendVerificationRequest()
 }
 //! cancels a verification flow
 void
-DeviceVerificationFlow::cancelVerification()
+DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_code)
 {
         mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationCancel req;
 
         req.transaction_id = this->transaction_id;
-        // TODO: Add Proper Error Messages and Code
-        req.reason = "Device Verification Cancelled";
-        req.code   = "400";
+        if (error_code == DeviceVerificationFlow::Error::UnknownMethod) {
+                req.code   = "m.unknown_method";
+                req.reason = "unknown method recieved";
+        } else if (error_code == DeviceVerificationFlow::Error::MismatchedCommitment) {
+                req.code   = "m.mismatched_commitment";
+                req.reason = "commitment didn't match";
+        } else if (error_code == DeviceVerificationFlow::Error::MismatchedSAS) {
+                req.code   = "m.mismatched_sas";
+                req.reason = "sas didn't match";
+        } else if (error_code == DeviceVerificationFlow::Error::KeyMismatch) {
+                req.code   = "m.key_match";
+                req.reason = "keys did not match";
+        } else if (error_code == DeviceVerificationFlow::Error::Timeout) {
+                req.code   = "m.timeout";
+                req.reason = "timed out";
+        } else if (error_code == DeviceVerificationFlow::Error::User) {
+                req.code   = "m.user";
+                req.reason = "user cancelled the verification";
+        }
 
         body[this->toClient][deviceId.toStdString()] = req;
 
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index ea86a10b..891c6aea 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -28,6 +28,16 @@ public:
                 Emoji
         };
         Q_ENUM(Method)
+        enum Error
+        {
+                UnknownMethod,
+                MismatchedCommitment,
+                MismatchedSAS,
+                KeyMismatch,
+                Timeout,
+                User
+        };
+        Q_ENUM(Error)
 
         DeviceVerificationFlow(QObject *parent = nullptr);
         QString getTransactionId();
@@ -56,7 +66,7 @@ public slots:
         //! starts the verification flow
         void startVerificationRequest();
         //! cancels a verification flow
-        void cancelVerification();
+        void cancelVerification(DeviceVerificationFlow::Error error_code);
         //! sends the verification key
         void sendVerificationKey();
         //! sends the mac of the keys
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 14c66951..0b732232 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -184,6 +184,9 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
                                     QString::fromStdString(msg.content.transaction_id),
                                     QString::fromStdString(msg.sender),
                                     QString::fromStdString(msg.content.from_device));
+                          } else {
+                                  flow->cancelVerification(
+                                    DeviceVerificationFlow::Error::UnknownMethod);
                           }
                   }
           });
@@ -197,11 +200,43 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
                   auto flow            = new DeviceVerificationFlow(this);
                   flow->canonical_json = nlohmann::json(msg.content);
                   if (!(this->dvList->exist(QString::fromStdString(msg.content.transaction_id)))) {
-                          emit newDeviceVerificationRequest(
-                            std::move(flow),
-                            QString::fromStdString(msg.content.transaction_id),
-                            QString::fromStdString(msg.sender),
-                            QString::fromStdString(msg.content.from_device));
+                          if ((std::find(msg.content.key_agreement_protocols.begin(),
+                                         msg.content.key_agreement_protocols.end(),
+                                         "curve25519-hkdf-sha256") !=
+                               msg.content.key_agreement_protocols.end()) &&
+                              (std::find(msg.content.hashes.begin(),
+                                         msg.content.hashes.end(),
+                                         "sha256") != msg.content.hashes.end()) &&
+                              (std::find(msg.content.message_authentication_codes.begin(),
+                                         msg.content.message_authentication_codes.end(),
+                                         "hmac-sha256") !=
+                               msg.content.message_authentication_codes.end())) {
+                                  if (std::find(msg.content.short_authentication_string.begin(),
+                                                msg.content.short_authentication_string.end(),
+                                                mtx::events::msg::SASMethods::Emoji) !=
+                                      msg.content.short_authentication_string.end()) {
+                                          flow->setMethod(DeviceVerificationFlow::Method::Emoji);
+                                  } else if (std::find(
+                                               msg.content.short_authentication_string.begin(),
+                                               msg.content.short_authentication_string.end(),
+                                               mtx::events::msg::SASMethods::Decimal) !=
+                                             msg.content.short_authentication_string.end()) {
+                                          flow->setMethod(DeviceVerificationFlow::Method::Decimal);
+                                  } else {
+                                          flow->cancelVerification(
+                                            DeviceVerificationFlow::Error::UnknownMethod);
+                                          return;
+                                  }
+                                  emit newDeviceVerificationRequest(
+                                    std::move(flow),
+                                    QString::fromStdString(msg.content.transaction_id),
+                                    QString::fromStdString(msg.sender),
+                                    QString::fromStdString(msg.content.from_device));
+                                  flow->canonical_json = nlohmann::json(msg.content);
+                          } else {
+                                  flow->cancelVerification(
+                                    DeviceVerificationFlow::Error::UnknownMethod);
+                          }
                   }
           });
 }
-- 
cgit 1.5.1


From 08028d5c57d134fb3d0ca9004730f0b2c99e5e67 Mon Sep 17 00:00:00 2001
From: Nicolas Werner 
Date: Sat, 4 Jul 2020 04:24:28 +0200
Subject: Refactor UserProfile

---
 CMakeLists.txt                       |   4 -
 resources/qml/TimelineView.qml       |  22 +-
 resources/qml/UserProfile.qml        | 417 +++++++++++++++++------------------
 src/MainWindow.cpp                   |   9 -
 src/MainWindow.h                     |   2 -
 src/dialogs/UserProfile.cpp          | 305 -------------------------
 src/dialogs/UserProfile.h            |  69 ------
 src/timeline/TimelineModel.cpp       |   4 +-
 src/timeline/TimelineModel.h         |  10 +-
 src/timeline/TimelineViewManager.cpp |  20 +-
 src/ui/UserProfile.cpp               | 108 +++++----
 src/ui/UserProfile.h                 | 120 ++++++----
 src/ui/UserProfileModel.cpp          |  63 ------
 src/ui/UserProfileModel.h            |  30 ---
 14 files changed, 383 insertions(+), 800 deletions(-)
 delete mode 100644 src/dialogs/UserProfile.cpp
 delete mode 100644 src/dialogs/UserProfile.h
 delete mode 100644 src/ui/UserProfileModel.cpp
 delete mode 100644 src/ui/UserProfileModel.h

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c39ff3af..5ad8a625 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -240,7 +240,6 @@ set(SRC_FILES
 	src/dialogs/ReCaptcha.cpp
 	src/dialogs/ReadReceipts.cpp
 	src/dialogs/RoomSettings.cpp
-	src/dialogs/UserProfile.cpp
 
 	# Emoji
 	src/emoji/Category.cpp
@@ -280,7 +279,6 @@ set(SRC_FILES
 	src/ui/Theme.cpp
 	src/ui/ThemeManager.cpp
 	src/ui/UserProfile.cpp
-	src/ui/UserProfileModel.cpp
 
 	src/AvatarProvider.cpp
 	src/BlurhashProvider.cpp
@@ -449,7 +447,6 @@ qt5_wrap_cpp(MOC_HEADERS
 	src/dialogs/ReCaptcha.h
 	src/dialogs/ReadReceipts.h
 	src/dialogs/RoomSettings.h
-	src/dialogs/UserProfile.h
 
 	# Emoji
 	src/emoji/Category.h
@@ -486,7 +483,6 @@ qt5_wrap_cpp(MOC_HEADERS
 	src/ui/Theme.h
 	src/ui/ThemeManager.h
 	src/ui/UserProfile.h
-	src/ui/UserProfileModel.h
 
 	src/notifications/Manager.h
 
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index 3618140a..ec634878 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -106,17 +106,23 @@ Page {
 		}
 		Connections {
 			target: TimelineManager
-			onNewDeviceVerificationRequest: {
+			function onNewDeviceVerificationRequest(flow) {
 				flow.userId = userId;
 				flow.sender = false;
 				flow.deviceId = deviceId;
 				flow.tranId = transactionId;
 				deviceVerificationList.add(flow.tranId);
-				var dialog = deviceVerificationDialog.createObject(timelineRoot, 
-                    {flow: flow});
+				var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow});
 				dialog.show();
 			}
 		}
+		Connections {
+			target: TimelineManager.timeline
+			function onOpenProfile(profile) {
+				var userProfile = userProfileComponent.createObject(timelineRoot,{profile: profile});
+				userProfile.show();
+			}
+		}
 
 		Label {
 			visible: !TimelineManager.timeline && !TimelineManager.isInitialSync
@@ -293,10 +299,7 @@ Page {
 
 							MouseArea {
 								anchors.fill: parent
-                                onClicked: {
-									userProfile = userProfileComponent.createObject(timelineRoot,{user_data: modelData,avatarUrl:chat.model.avatarUrl(modelData.userId)});
-									userProfile.show();
-                                }
+								onClicked: chat.model.openUserProfile(modelData.userId)
 								cursorShape: Qt.PointingHandCursor
 								propagateComposedEvents: true
 							}
@@ -311,10 +314,7 @@ Page {
 							MouseArea {
 								anchors.fill: parent
 								Layout.alignment: Qt.AlignHCenter
-                                onClicked: {
-									userProfile = userProfileComponent.createObject(timelineRoot,{user_data: modelData,avatarUrl:chat.model.avatarUrl(modelData.userId)});
-									userProfile.show();
-                                }
+								onClicked: chat.model.openUserProfile(modelData.userId)
 								cursorShape: Qt.PointingHandCursor
 								propagateComposedEvents: true
 							}
diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index db44ec15..df54367b 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -8,220 +8,211 @@ import im.nheko 1.0
 import "./device-verification"
 
 ApplicationWindow{
-    property var user_data
-    property var avatarUrl
-    property var colors: currentActivePalette
-
-    id:userProfileDialog
-    height: 650
-    width: 420
-    modality:Qt.WindowModal
-    Layout.alignment: Qt.AlignHCenter
-    palette: colors
-
-    Component {
+	property var profile
+
+	id: userProfileDialog
+	height: 650
+	width: 420
+	modality: Qt.WindowModal
+	Layout.alignment: Qt.AlignHCenter
+	palette: colors
+
+	Component {
 		id: deviceVerificationDialog
 		DeviceVerification {}
 	}
-    Component{
-        id: deviceVerificationFlow
-        DeviceVerificationFlow {}
-    }
-
-    background: Item{
-        id: userProfileItem
-        width: userProfileDialog.width
-        height: userProfileDialog.height
-
-        // Layout.fillHeight : true
-
-        ColumnLayout{
-            anchors.fill: userProfileItem
-            width: userProfileDialog.width
-            spacing: 10
-
-            Avatar{
-                id: userProfileAvatar
-                url: avatarUrl.replace("mxc://", "image://MxcImage/")
-                height: 130
-                width: 130
-                displayName: user_data.userName
-		        userid: user_data.userId
-                Layout.alignment: Qt.AlignHCenter
-                Layout.margins : {
-                    top: 10
-                }
-            }
-
-            Label{
-                id: userProfileName
-                text: user_data.userName
-                fontSizeMode: Text.HorizontalFit
-                font.pixelSize: 20
-                color:TimelineManager.userColor(user_data.userId, colors.window)
-                font.bold: true
-                Layout.alignment: Qt.AlignHCenter
-            }
-
-            Label{
-                id: matrixUserID
-                text: user_data.userId
-                fontSizeMode: Text.HorizontalFit
-                font.pixelSize: 15
-                color:colors.text
-                Layout.alignment: Qt.AlignHCenter
-            }
-
-            RowLayout{
-                Layout.alignment: Qt.AlignHCenter
-                ImageButton{
-                    image:":/icons/icons/ui/do-not-disturb-rounded-sign.png"
-                    Layout.margins: {
-                        left: 5
-                        right: 5
-                    }
-                    ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Ban the user")
-                    onClicked : {
-                        modelDeviceList.deviceList.banUser()
-                    }
-                }
-                // ImageButton{
-                //     image:":/icons/icons/ui/volume-off-indicator.png"
-                //     Layout.margins: {
-                //         left: 5
-                //         right: 5
-                //     }
-                //     ToolTip.visible: hovered
-			    //     ToolTip.text: qsTr("Ignore messages from this user")
-                //     onClicked : {
-                //         modelDeviceList.deviceList.ignoreUser()
-                //     }
-                // }
-                ImageButton{
-                    image:":/icons/icons/ui/black-bubble-speech.png"
-                    Layout.margins: {
-                        left: 5
-                        right: 5
-                    }
-                    ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Start a private chat")
-                    onClicked : {
-                        modelDeviceList.deviceList.startChat()
-                    }
-                }
-                ImageButton{
-                    image:":/icons/icons/ui/round-remove-button.png"
-                    Layout.margins: {
-                        left: 5
-                        right: 5
-                    }
-                    ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Kick the user")
-                    onClicked : {
-                        modelDeviceList.deviceList.kickUser()
-                    }
-                }
-            }
-
-            ScrollView {
-                implicitHeight: userProfileDialog.height/2 + 20
-                implicitWidth: userProfileDialog.width-20
-                clip: true
-                Layout.alignment: Qt.AlignHCenter
-
-                ListView{
-                    id: devicelist
-                    anchors.fill: parent
-                    clip: true
-                    spacing: 4
-
-                    model: UserProfileModel{
-                        id: modelDeviceList
-                        deviceList.userId : user_data.userId
-                    }
-
-                    delegate: RowLayout{
-                        width: parent.width
-                        Layout.margins : {
-                            top : 50
-                        }
-                        ColumnLayout{
-                            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
-                                color:colors.text
-                                Layout.alignment: Qt.AlignRight
-                                text: displayName
-                            }
-                        }
-                        Button{
-                            id: verifyButton
-                            text:"Verify"
-                            onClicked: {
-                                var newFlow = deviceVerificationFlow.createObject(userProfileDialog,
-                                {userId : user_data.userId,sender: true,deviceId : model.deviceID});
-                                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
-                            }
-                        }
-                    }
-                }
-            }
-
-            Button{
-                id: okbutton
-                text:"OK"
-                onClicked: userProfileDialog.close()
-                
-                Layout.alignment: Qt.AlignRight | Qt.AlignBottom
-
-                Layout.margins : {
-                    right : 10
-                    bottom: 5
-                }
-
-                palette {
-                    button: "white"
-                }
-
-                contentItem: Text {
-                    text: okbutton.text
-                    color: "black"
-                    horizontalAlignment: Text.AlignHCenter
-                    verticalAlignment: Text.AlignVCenter
-                }
-            }
-        }
-
-        Item { Layout.fillHeight: true }
-    }
+	Component{
+		id: deviceVerificationFlow
+		DeviceVerificationFlow {}
+	}
+
+	background: Item{
+		id: userProfileItem
+		width: userProfileDialog.width
+		height: userProfileDialog.height
+
+		// Layout.fillHeight : true
+
+		ColumnLayout{
+			anchors.fill: userProfileItem
+			width: userProfileDialog.width
+			spacing: 10
+
+			Avatar {
+				url: profile.avatarUrl.replace("mxc://", "image://MxcImage/")
+				height: 130
+				width: 130
+				displayName: profile.displayName
+				userid: profile.userid
+				Layout.alignment: Qt.AlignHCenter
+				Layout.margins : {
+					top: 10
+				}
+			}
+
+			Label {
+				text: profile.displayName
+				fontSizeMode: Text.HorizontalFit
+				font.pixelSize: 20
+				color: TimelineManager.userColor(profile.userid, colors.window)
+				font.bold: true
+				Layout.alignment: Qt.AlignHCenter
+			}
+
+			Label {
+				text: profile.userid
+				fontSizeMode: Text.HorizontalFit
+				font.pixelSize: 15
+				color: colors.text
+				Layout.alignment: Qt.AlignHCenter
+			}
+
+			RowLayout {
+				Layout.alignment: Qt.AlignHCenter
+				ImageButton {
+					image:":/icons/icons/ui/do-not-disturb-rounded-sign.png"
+					Layout.margins: {
+						left: 5
+						right: 5
+					}
+					ToolTip.visible: hovered
+					ToolTip.text: qsTr("Ban the user")
+					onClicked : {
+						profile.banUser()
+					}
+				}
+				// ImageButton{
+				//     image:":/icons/icons/ui/volume-off-indicator.png"
+				//     Layout.margins: {
+				//         left: 5
+				//         right: 5
+				//     }
+				//     ToolTip.visible: hovered
+				//     ToolTip.text: qsTr("Ignore messages from this user")
+				//     onClicked : {
+				//         profile.ignoreUser()
+				//     }
+				// }
+				ImageButton{
+					image:":/icons/icons/ui/black-bubble-speech.png"
+					Layout.margins: {
+						left: 5
+						right: 5
+					}
+					ToolTip.visible: hovered
+					ToolTip.text: qsTr("Start a private chat")
+					onClicked : {
+						profile.startChat()
+					}
+				}
+				ImageButton{
+					image:":/icons/icons/ui/round-remove-button.png"
+					Layout.margins: {
+						left: 5
+						right: 5
+					}
+					ToolTip.visible: hovered
+					ToolTip.text: qsTr("Kick the user")
+					onClicked : {
+						profile.kickUser()
+					}
+				}
+			}
+
+			ScrollView {
+				implicitHeight: userProfileDialog.height/2 + 20
+				implicitWidth: userProfileDialog.width-20
+				clip: true
+				Layout.alignment: Qt.AlignHCenter
+
+				ListView{
+					id: devicelist
+					anchors.fill: parent
+					clip: true
+					spacing: 4
+
+					model: profile.deviceList
+
+					delegate: RowLayout{
+						width: parent.width
+						Layout.margins : {
+							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
+								Layout.alignment: Qt.AlignRight
+								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();
+							}
+							Layout.margins:{
+								right: 10
+							}
+							palette {
+								button: "white"
+							}
+							contentItem: Text {
+								text: verifyButton.text
+								color: "black"
+								horizontalAlignment: Text.AlignHCenter
+								verticalAlignment: Text.AlignVCenter
+							}
+						}
+					}
+				}
+			}
+
+			Button{
+				id: okbutton
+				text:"OK"
+				onClicked: userProfileDialog.close()
+
+				Layout.alignment: Qt.AlignRight | Qt.AlignBottom
+
+				Layout.margins : {
+					right : 10
+					bottom: 5
+				}
+
+				palette {
+					button: "white"
+				}
+
+				contentItem: Text {
+					text: okbutton.text
+					color: "black"
+					horizontalAlignment: Text.AlignHCenter
+					verticalAlignment: Text.AlignVCenter
+				}
+			}
+		}
+
+		Item { Layout.fillHeight: true }
+	}
 }
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index cc1d868b..63b524c8 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -317,15 +317,6 @@ MainWindow::hasActiveUser()
                settings.contains("auth/user_id");
 }
 
-void
-MainWindow::openUserProfile(const QString &user_id, const QString &room_id)
-{
-        auto dialog = new dialogs::UserProfile(this);
-        dialog->init(user_id, room_id);
-
-        showDialog(dialog);
-}
-
 void
 MainWindow::openRoomSettings(const QString &room_id)
 {
diff --git a/src/MainWindow.h b/src/MainWindow.h
index e3e04698..2fc2d00f 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -25,7 +25,6 @@
 #include 
 
 #include "UserSettingsPage.h"
-#include "dialogs/UserProfile.h"
 #include "ui/OverlayModal.h"
 
 #include "jdenticoninterface.h"
@@ -76,7 +75,6 @@ public:
         void openLogoutDialog();
         void openRoomSettings(const QString &room_id = "");
         void openMemberListDialog(const QString &room_id = "");
-        void openUserProfile(const QString &user_id, const QString &room_id);
         void openReadReceiptsDialog(const QString &event_id);
 
         void hideOverlay();
diff --git a/src/dialogs/UserProfile.cpp b/src/dialogs/UserProfile.cpp
deleted file mode 100644
index 3415b127..00000000
--- a/src/dialogs/UserProfile.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "Cache.h"
-#include "ChatPage.h"
-#include "Logging.h"
-#include "MatrixClient.h"
-#include "Utils.h"
-#include "dialogs/UserProfile.h"
-#include "ui/Avatar.h"
-#include "ui/FlatButton.h"
-
-using namespace dialogs;
-
-Q_DECLARE_METATYPE(std::vector)
-
-constexpr int BUTTON_SIZE       = 36;
-constexpr int BUTTON_RADIUS     = BUTTON_SIZE / 2;
-constexpr int WIDGET_MARGIN     = 20;
-constexpr int TOP_WIDGET_MARGIN = 2 * WIDGET_MARGIN;
-constexpr int WIDGET_SPACING    = 15;
-constexpr int TEXT_SPACING      = 4;
-constexpr int DEVICE_SPACING    = 5;
-
-DeviceItem::DeviceItem(DeviceInfo device, QWidget *parent)
-  : QWidget(parent)
-  , info_(std::move(device))
-{
-        QFont font;
-        font.setBold(true);
-
-        auto deviceIdLabel = new QLabel(info_.device_id, this);
-        deviceIdLabel->setFont(font);
-
-        auto layout = new QVBoxLayout{this};
-        layout->addWidget(deviceIdLabel);
-
-        if (!info_.display_name.isEmpty())
-                layout->addWidget(new QLabel(info_.display_name, this));
-
-        layout->setMargin(0);
-        layout->setSpacing(4);
-}
-
-UserProfile::UserProfile(QWidget *parent)
-  : QWidget(parent)
-{
-        setAutoFillBackground(true);
-        setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
-        setAttribute(Qt::WA_DeleteOnClose, true);
-
-        QIcon banIcon, kickIcon, ignoreIcon, startChatIcon;
-
-        banIcon.addFile(":/icons/icons/ui/do-not-disturb-rounded-sign.png");
-        banBtn_ = new FlatButton(this);
-        banBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        banBtn_->setCornerRadius(BUTTON_RADIUS);
-        banBtn_->setIcon(banIcon);
-        banBtn_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        banBtn_->setToolTip(tr("Ban the user from the room"));
-
-        ignoreIcon.addFile(":/icons/icons/ui/volume-off-indicator.png");
-        ignoreBtn_ = new FlatButton(this);
-        ignoreBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        ignoreBtn_->setCornerRadius(BUTTON_RADIUS);
-        ignoreBtn_->setIcon(ignoreIcon);
-        ignoreBtn_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        ignoreBtn_->setToolTip(tr("Ignore messages from this user"));
-        ignoreBtn_->setDisabled(true); // Not used yet.
-
-        kickIcon.addFile(":/icons/icons/ui/round-remove-button.png");
-        kickBtn_ = new FlatButton(this);
-        kickBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        kickBtn_->setCornerRadius(BUTTON_RADIUS);
-        kickBtn_->setIcon(kickIcon);
-        kickBtn_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        kickBtn_->setToolTip(tr("Kick the user from the room"));
-
-        startChatIcon.addFile(":/icons/icons/ui/black-bubble-speech.png");
-        startChat_ = new FlatButton(this);
-        startChat_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        startChat_->setCornerRadius(BUTTON_RADIUS);
-        startChat_->setIcon(startChatIcon);
-        startChat_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        startChat_->setToolTip(tr("Start a conversation"));
-
-        connect(startChat_, &QPushButton::clicked, this, [this]() {
-                auto user_id = userIdLabel_->text();
-
-                mtx::requests::CreateRoom req;
-                req.preset     = mtx::requests::Preset::PrivateChat;
-                req.visibility = mtx::requests::Visibility::Private;
-
-                if (utils::localUser() != user_id)
-                        req.invite = {user_id.toStdString()};
-
-                emit ChatPage::instance()->createRoom(req);
-        });
-
-        connect(banBtn_, &QPushButton::clicked, this, [this] {
-                ChatPage::instance()->banUser(userIdLabel_->text(), "");
-        });
-        connect(kickBtn_, &QPushButton::clicked, this, [this] {
-                ChatPage::instance()->kickUser(userIdLabel_->text(), "");
-        });
-
-        // Button line
-        auto btnLayout = new QHBoxLayout;
-        btnLayout->addStretch(1);
-        btnLayout->addWidget(startChat_);
-        btnLayout->addWidget(ignoreBtn_);
-
-        btnLayout->addWidget(kickBtn_);
-        btnLayout->addWidget(banBtn_);
-        btnLayout->addStretch(1);
-        btnLayout->setSpacing(8);
-        btnLayout->setMargin(0);
-
-        avatar_ = new Avatar(this, 128);
-        avatar_->setLetter("X");
-
-        QFont font;
-        font.setPointSizeF(font.pointSizeF() * 2);
-
-        userIdLabel_      = new QLabel(this);
-        displayNameLabel_ = new QLabel(this);
-        displayNameLabel_->setFont(font);
-
-        auto textLayout = new QVBoxLayout;
-        textLayout->addWidget(displayNameLabel_);
-        textLayout->addWidget(userIdLabel_);
-        textLayout->setAlignment(displayNameLabel_, Qt::AlignCenter | Qt::AlignTop);
-        textLayout->setAlignment(userIdLabel_, Qt::AlignCenter | Qt::AlignTop);
-        textLayout->setSpacing(TEXT_SPACING);
-        textLayout->setMargin(0);
-
-        devices_ = new QListWidget{this};
-        devices_->setFrameStyle(QFrame::NoFrame);
-        devices_->setSelectionMode(QAbstractItemView::NoSelection);
-        devices_->setAttribute(Qt::WA_MacShowFocusRect, 0);
-        devices_->setSpacing(DEVICE_SPACING);
-
-        QFont descriptionLabelFont;
-        descriptionLabelFont.setWeight(65);
-
-        devicesLabel_ = new QLabel(tr("Devices").toUpper(), this);
-        devicesLabel_->setFont(descriptionLabelFont);
-        devicesLabel_->hide();
-        devicesLabel_->setFixedSize(devicesLabel_->sizeHint());
-
-        auto okBtn = new QPushButton("OK", this);
-
-        auto closeLayout = new QHBoxLayout();
-        closeLayout->setSpacing(15);
-        closeLayout->addStretch(1);
-        closeLayout->addWidget(okBtn);
-
-        auto vlayout = new QVBoxLayout{this};
-        vlayout->addWidget(avatar_, 0, Qt::AlignCenter | Qt::AlignTop);
-        vlayout->addLayout(textLayout);
-        vlayout->addLayout(btnLayout);
-        vlayout->addWidget(devicesLabel_, 0, Qt::AlignLeft);
-        vlayout->addWidget(devices_, 1);
-        vlayout->addLayout(closeLayout);
-
-        QFont largeFont;
-        largeFont.setPointSizeF(largeFont.pointSizeF() * 1.5);
-
-        setMinimumWidth(
-          std::max(devices_->sizeHint().width() + 4 * WIDGET_MARGIN, conf::window::minModalWidth));
-        setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
-
-        vlayout->setSpacing(WIDGET_SPACING);
-        vlayout->setContentsMargins(WIDGET_MARGIN, TOP_WIDGET_MARGIN, WIDGET_MARGIN, WIDGET_MARGIN);
-
-        qRegisterMetaType>();
-
-        auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this);
-        connect(closeShortcut, &QShortcut::activated, this, &UserProfile::close);
-        connect(okBtn, &QPushButton::clicked, this, &UserProfile::close);
-}
-
-void
-UserProfile::resetToDefaults()
-{
-        avatar_->setLetter("X");
-        devices_->clear();
-
-        ignoreBtn_->show();
-        devices_->hide();
-        devicesLabel_->hide();
-}
-
-void
-UserProfile::init(const QString &userId, const QString &roomId)
-{
-        resetToDefaults();
-
-        auto displayName = cache::displayName(roomId, userId);
-
-        userIdLabel_->setText(userId);
-        displayNameLabel_->setText(displayName);
-        avatar_->setLetter(utils::firstChar(displayName));
-
-        avatar_->setImage(roomId, userId);
-
-        auto localUser = utils::localUser();
-
-        try {
-                bool hasMemberRights =
-                  cache::hasEnoughPowerLevel({mtx::events::EventType::RoomMember},
-                                             roomId.toStdString(),
-                                             localUser.toStdString());
-                if (!hasMemberRights) {
-                        kickBtn_->hide();
-                        banBtn_->hide();
-                } else {
-                        kickBtn_->show();
-                        banBtn_->show();
-                }
-        } catch (const lmdb::error &e) {
-                nhlog::db()->warn("lmdb error: {}", e.what());
-        }
-
-        if (localUser == userId) {
-                // TODO: click on display name & avatar to change.
-                kickBtn_->hide();
-                banBtn_->hide();
-                ignoreBtn_->hide();
-        }
-
-        mtx::requests::QueryKeys req;
-        req.device_keys[userId.toStdString()] = {};
-
-        // A proxy object is used to emit the signal instead of the original object
-        // which might be destroyed by the time the http call finishes.
-        auto proxy = std::make_shared();
-        QObject::connect(proxy.get(), &Proxy::done, this, &UserProfile::updateDeviceList);
-
-        http::client()->query_keys(
-          req,
-          [user_id = userId.toStdString(), proxy = std::move(proxy)](
-            const mtx::responses::QueryKeys &res, mtx::http::RequestErr err) {
-                  if (err) {
-                          nhlog::net()->warn("failed to query device keys: {} {}",
-                                             err->matrix_error.error,
-                                             static_cast(err->status_code));
-                          // TODO: Notify the UI.
-                          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);
-
-                  std::vector deviceInfo;
-                  for (const auto &d : devices) {
-                          auto device = d.second;
-
-                          // TODO: Verify signatures and ignore those that don't pass.
-                          deviceInfo.emplace_back(DeviceInfo{
-                            QString::fromStdString(d.first),
-                            QString::fromStdString(device.unsigned_info.device_display_name)});
-                  }
-
-                  std::sort(deviceInfo.begin(),
-                            deviceInfo.end(),
-                            [](const DeviceInfo &a, const DeviceInfo &b) {
-                                    return a.device_id > b.device_id;
-                            });
-
-                  if (!deviceInfo.empty())
-                          emit proxy->done(QString::fromStdString(user_id), deviceInfo);
-          });
-}
-
-void
-UserProfile::updateDeviceList(const QString &user_id, const std::vector &devices)
-{
-        if (user_id != userIdLabel_->text())
-                return;
-
-        for (const auto &dev : devices) {
-                auto deviceItem = new DeviceItem(dev, this);
-                auto item       = new QListWidgetItem;
-
-                item->setSizeHint(deviceItem->minimumSizeHint());
-                item->setFlags(Qt::NoItemFlags);
-                item->setTextAlignment(Qt::AlignCenter);
-
-                devices_->insertItem(devices_->count() - 1, item);
-                devices_->setItemWidget(item, deviceItem);
-        }
-
-        devicesLabel_->show();
-        devices_->show();
-        adjustSize();
-}
diff --git a/src/dialogs/UserProfile.h b/src/dialogs/UserProfile.h
deleted file mode 100644
index 81276d2a..00000000
--- a/src/dialogs/UserProfile.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#pragma once
-
-#include 
-#include 
-
-class Avatar;
-class FlatButton;
-class QLabel;
-class QListWidget;
-class Toggle;
-
-struct DeviceInfo
-{
-        QString device_id;
-        QString display_name;
-};
-
-class Proxy : public QObject
-{
-        Q_OBJECT
-
-signals:
-        void done(const QString &user_id, const std::vector &devices);
-};
-
-namespace dialogs {
-
-class DeviceItem : public QWidget
-{
-        Q_OBJECT
-
-public:
-        explicit DeviceItem(DeviceInfo device, QWidget *parent);
-
-private:
-        DeviceInfo info_;
-
-        // Toggle *verifyToggle_;
-};
-
-class UserProfile : public QWidget
-{
-        Q_OBJECT
-public:
-        explicit UserProfile(QWidget *parent = nullptr);
-
-        void init(const QString &userId, const QString &roomId);
-
-private slots:
-        void updateDeviceList(const QString &user_id, const std::vector &devices);
-
-private:
-        void resetToDefaults();
-
-        Avatar *avatar_;
-
-        QLabel *userIdLabel_;
-        QLabel *displayNameLabel_;
-
-        FlatButton *banBtn_;
-        FlatButton *kickBtn_;
-        FlatButton *ignoreBtn_;
-        FlatButton *startChat_;
-
-        QLabel *devicesLabel_;
-        QListWidget *devices_;
-};
-
-} // dialogs
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index f41e7712..773a5a23 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -654,9 +654,9 @@ TimelineModel::viewDecryptedRawMessage(QString id) const
 }
 
 void
-TimelineModel::openUserProfile(QString userid) const
+TimelineModel::openUserProfile(QString userid)
 {
-        MainWindow::instance()->openUserProfile(userid, room_id_);
+        emit openProfile(new UserProfile(room_id_, userid, this));
 }
 
 void
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index f8a84f17..104a475c 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -9,7 +9,12 @@
 #include 
 
 #include "CacheCryptoStructs.h"
+<<<<<<< HEAD
 #include "EventStore.h"
+=======
+#include "ReactionsModel.h"
+#include "ui/UserProfile.h"
+>>>>>>> Refactor UserProfile
 
 namespace mtx::http {
 using RequestErr = const std::optional &;
@@ -188,7 +193,7 @@ public:
         Q_INVOKABLE QString escapeEmoji(QString str) const;
         Q_INVOKABLE void viewRawMessage(QString id) const;
         Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
-        Q_INVOKABLE void openUserProfile(QString userid) const;
+        Q_INVOKABLE void openUserProfile(QString userid);
         Q_INVOKABLE void replyAction(QString id);
         Q_INVOKABLE void readReceiptsAction(QString id) const;
         Q_INVOKABLE void redactEvent(QString id);
@@ -256,8 +261,7 @@ signals:
         void replyChanged(QString reply);
         void paginationInProgressChanged(const bool);
 
-        void newMessageToSend(mtx::events::collections::TimelineEvents event);
-        void addPendingMessageToStore(mtx::events::collections::TimelineEvents event);
+        void openProfile(UserProfile *profile);
 
 private:
         void sendEncryptedMessage(const std::string txn_id, nlohmann::json content);
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 0b732232..81c8d6d3 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -16,10 +16,9 @@
 #include "dialogs/ImageOverlay.h"
 #include "emoji/EmojiModel.h"
 #include "emoji/Provider.h"
-#include "src/ui/UserProfile.h"
-#include "src/ui/UserProfileModel.h"
 
 Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
+Q_DECLARE_METATYPE(std::vector)
 
 namespace msgs = mtx::events::msg;
 
@@ -109,15 +108,28 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
                                          0,
                                          "MtxEvent",
                                          "Can't instantiate enum!");
+        qmlRegisterUncreatableMetaObject(verification::staticMetaObject,
+                                         "im.nheko",
+                                         1,
+                                         0,
+                                         "VerificationStatus",
+                                         "Can't instantiate enum!");
+
         qmlRegisterType("im.nheko", 1, 0, "DelegateChoice");
         qmlRegisterType("im.nheko", 1, 0, "DelegateChooser");
         qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow");
-        qmlRegisterType("im.nheko", 1, 0, "UserProfileModel");
-        qmlRegisterType("im.nheko", 1, 0, "UserProfileList");
+        qmlRegisterUncreatableType(
+          "im.nheko",
+          1,
+          0,
+          "UserProfileModel",
+          "UserProfile needs to be instantiated on the C++ side");
         qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", this);
         qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", settings.data());
 
         qRegisterMetaType();
+        qRegisterMetaType>();
+
         qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiModel");
         qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel");
         qmlRegisterUncreatableType(
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 8c6fb8e4..fde0044b 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -5,47 +5,72 @@
 #include "Utils.h"
 #include "mtx/responses/crypto.hpp"
 
-#include  // only for debugging
+UserProfile::UserProfile(QString roomid, QString userid, QObject *parent)
+  : QObject(parent)
+  , roomid_(roomid)
+  , userid_(userid)
+{
+        fetchDeviceList(this->userid_);
+}
 
-Q_DECLARE_METATYPE(UserProfile::Status)
+QHash
+DeviceInfoModel::roleNames() const
+{
+        return {
+          {DeviceId, "deviceId"},
+          {DeviceName, "deviceName"},
+          {VerificationStatus, "verificationStatus"},
+        };
+}
 
-UserProfile::UserProfile(QObject *parent)
-  : QObject(parent)
+QVariant
+DeviceInfoModel::data(const QModelIndex &index, int role) const
 {
-        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});
-          });
+        if (!index.isValid() || index.row() >= (int)deviceList_.size() || index.row() < 0)
+                return {};
+
+        switch (role) {
+        case DeviceId:
+                return deviceList_[index.row()].device_id;
+        case DeviceName:
+                return deviceList_[index.row()].display_name;
+        case VerificationStatus:
+                return QVariant::fromValue(deviceList_[index.row()].verification_status);
+        default:
+                return {};
+        }
 }
 
-std::vector
-UserProfile::getDeviceList()
+void
+DeviceInfoModel::reset(const std::vector &deviceList)
 {
-        return this->deviceList;
+        beginResetModel();
+        this->deviceList_ = std::move(deviceList);
+        endResetModel();
+}
+
+DeviceInfoModel *
+UserProfile::deviceList()
+{
+        return &this->deviceList_;
 }
 
 QString
-UserProfile::getUserId()
+UserProfile::userid()
 {
-        return this->userId;
+        return this->userid_;
 }
 
-void
-UserProfile::setUserId(const QString &user_id)
+QString
+UserProfile::displayName()
 {
-        if (this->userId != userId)
-                return;
-        else {
-                this->userId = user_id;
-                emit UserProfile::userIdChanged();
-        }
+        return cache::displayName(roomid_, userid_);
+}
+
+QString
+UserProfile::avatarUrl()
+{
+        return cache::avatarUrl(roomid_, userid_);
 }
 
 void
@@ -74,27 +99,27 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
                 auto device = d.second;
 
                 // TODO: Verify signatures and ignore those that don't pass.
-                UserProfile::Status verified = UserProfile::Status::UNVERIFIED;
+                verification::Status verified = verification::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;
+                                verified = verification::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;
+                                verified = verification::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;
+                                verified = verification::Status::BLOCKED;
                 }
 
-                emit UserProfile::appendDeviceList(
-                  QString::fromStdString(d.first),
-                  QString::fromStdString(device.unsigned_info.device_display_name),
-                  verified);
+                deviceInfo.push_back(
+                  {QString::fromStdString(d.first),
+                   QString::fromStdString(device.unsigned_info.device_display_name),
+                   verified});
         }
 
         // std::sort(
@@ -102,8 +127,7 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
         //           return a.device_id > b.device_id;
         //   });
 
-        this->deviceList = std::move(deviceInfo);
-        emit UserProfile::deviceListUpdated();
+        this->deviceList_.queueReset(std::move(deviceInfo));
 }
 
 void
@@ -130,7 +154,7 @@ UserProfile::fetchDeviceList(const QString &userID)
 void
 UserProfile::banUser()
 {
-        ChatPage::instance()->banUser(this->userId, "");
+        ChatPage::instance()->banUser(this->userid_, "");
 }
 
 // void ignoreUser(){
@@ -140,7 +164,7 @@ UserProfile::banUser()
 void
 UserProfile::kickUser()
 {
-        ChatPage::instance()->kickUser(this->userId, "");
+        ChatPage::instance()->kickUser(this->userid_, "");
 }
 
 void
@@ -149,7 +173,7 @@ UserProfile::startChat()
         mtx::requests::CreateRoom req;
         req.preset     = mtx::requests::Preset::PrivateChat;
         req.visibility = mtx::requests::Visibility::Private;
-        if (utils::localUser() != this->userId)
-                req.invite = {this->userId.toStdString()};
+        if (utils::localUser() != this->userid_)
+                req.invite = {this->userid_.toStdString()};
         emit ChatPage::instance()->createRoom(req);
 }
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 1725b961..38002fff 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -1,34 +1,92 @@
 #pragma once
 
+#include 
 #include 
 #include 
 #include 
 
 #include "MatrixClient.h"
 
-class DeviceInfo;
+namespace verification {
+Q_NAMESPACE
 
-class UserProfile : public QObject
+enum Status
+{
+        VERIFIED,
+        UNVERIFIED,
+        BLOCKED
+};
+Q_ENUM_NS(Status)
+}
+
+class DeviceInfo
+{
+public:
+        DeviceInfo(const QString deviceID,
+                   const QString displayName,
+                   verification::Status verification_status_)
+          : device_id(deviceID)
+          , display_name(displayName)
+          , verification_status(verification_status_)
+        {}
+        DeviceInfo()
+          : verification_status(verification::UNVERIFIED)
+        {}
+
+        QString device_id;
+        QString display_name;
+
+        verification::Status verification_status;
+};
+
+class DeviceInfoModel : public QAbstractListModel
 {
         Q_OBJECT
-        Q_PROPERTY(QString userId READ getUserId WRITE setUserId NOTIFY userIdChanged)
-        Q_PROPERTY(std::vector deviceList READ getDeviceList NOTIFY deviceListUpdated)
 public:
-        // constructor
-        explicit UserProfile(QObject *parent = 0);
-        // getters
-        std::vector getDeviceList();
-        QString getUserId();
-        // setters
-        void setUserId(const QString &userId);
-
-        enum Status
+        enum Roles
         {
-                VERIFIED,
-                UNVERIFIED,
-                BLOCKED
+                DeviceId,
+                DeviceName,
+                VerificationStatus,
         };
-        Q_ENUM(Status)
+
+        explicit DeviceInfoModel(QObject *parent = nullptr)
+        {
+                (void)parent;
+                connect(this, &DeviceInfoModel::queueReset, this, &DeviceInfoModel::reset);
+        };
+        QHash roleNames() const override;
+        int rowCount(const QModelIndex &parent = QModelIndex()) const
+        {
+                (void)parent;
+                return (int)deviceList_.size();
+        }
+        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+signals:
+        void queueReset(const std::vector &deviceList);
+public slots:
+        void reset(const std::vector &deviceList);
+
+private:
+        std::vector deviceList_;
+};
+
+class UserProfile : public QObject
+{
+        Q_OBJECT
+        Q_PROPERTY(QString displayName READ displayName CONSTANT)
+        Q_PROPERTY(QString userid READ userid CONSTANT)
+        Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
+        Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
+public:
+        UserProfile(QString roomid, QString userid, QObject *parent = 0);
+
+        DeviceInfoModel *deviceList();
+
+        QString userid();
+        QString displayName();
+        QString avatarUrl();
 
         void fetchDeviceList(const QString &userID);
         Q_INVOKABLE void banUser();
@@ -36,37 +94,13 @@ public:
         Q_INVOKABLE void kickUser();
         Q_INVOKABLE void startChat();
 
-signals:
-        void userIdChanged();
-        void deviceListUpdated();
-        void updateDeviceList();
-        void appendDeviceList(const QString device_id,
-                              const QString device_naem,
-                              const UserProfile::Status verification_status);
-
 private:
-        std::vector deviceList;
-        QString userId;
+        QString roomid_, userid_;
         std::optional cross_verified;
+        DeviceInfoModel deviceList_;
 
         void callback_fn(const mtx::responses::QueryKeys &res,
                          mtx::http::RequestErr err,
                          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
deleted file mode 100644
index 3fa8fe2d..00000000
--- a/src/ui/UserProfileModel.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "UserProfileModel.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
-{
-        if (parent.isValid() || !this->deviceList)
-                return 0;
-        return this->deviceList->getDeviceList().size();
-}
-
-QVariant
-UserProfileModel::data(const QModelIndex &index, int role) const
-{
-        if (!index.isValid() &&
-            static_cast(this->deviceList->getDeviceList().size()) <= index.row())
-                return QVariant();
-
-        const DeviceInfo device = this->deviceList->getDeviceList().at(index.row());
-        switch (role) {
-        case DEVICEID:
-                return QVariant(device.device_id);
-        case DISPLAYNAME:
-                return QVariant(device.display_name);
-        case VERIFIED_STATUS:
-                return device.verification_status;
-        }
-        return QVariant();
-}
-
-QHash
-UserProfileModel::roleNames() const
-{
-        QHash names;
-        names[DEVICEID]        = "deviceID";
-        names[DISPLAYNAME]     = "displayName";
-        names[VERIFIED_STATUS] = "verified_status";
-        return names;
-}
-
-UserProfile *
-UserProfileModel::getList() const
-{
-        return (this->deviceList);
-}
diff --git a/src/ui/UserProfileModel.h b/src/ui/UserProfileModel.h
deleted file mode 100644
index ba7a2525..00000000
--- a/src/ui/UserProfileModel.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include "UserProfile.h"
-#include 
-
-class UserProfile; // forward declaration of the class UserProfile
-
-class UserProfileModel : public QAbstractListModel
-{
-        Q_OBJECT
-        Q_PROPERTY(UserProfile *deviceList READ getList)
-
-public:
-        explicit UserProfileModel(QObject *parent = nullptr);
-
-        enum
-        {
-                DEVICEID,
-                DISPLAYNAME,
-                VERIFIED_STATUS
-        };
-        UserProfile *getList() const;
-
-        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-        QVariant data(const QModelIndex &index, int role) const override;
-        virtual QHash roleNames() const override;
-
-private:
-        UserProfile *deviceList;
-};
\ No newline at end of file
-- 
cgit 1.5.1


From 1fcd768f88f7e84978d19283c9fa6205624f2544 Mon Sep 17 00:00:00 2001
From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>
Date: Sat, 18 Jul 2020 01:46:30 +0530
Subject: Adding Room Key Verification Stuff

---
 resources/qml/UserProfile.qml               |  22 +-
 resources/qml/delegates/MessageDelegate.qml |  54 +++
 src/Cache.cpp                               |   2 +-
 src/ChatPage.h                              |  18 +-
 src/DeviceVerificationFlow.cpp              | 665 +++++++++++++++-------------
 src/DeviceVerificationFlow.h                |  17 +-
 src/EventAccessors.cpp                      |  11 +-
 src/Olm.cpp                                 |  39 +-
 src/timeline/TimelineModel.cpp              | 187 +++++++-
 src/timeline/TimelineModel.h                |   8 +
 src/timeline/TimelineViewManager.cpp        |  76 ++--
 src/timeline/TimelineViewManager.h          |   9 +-
 src/ui/UserProfile.cpp                      |  34 ++
 src/ui/UserProfile.h                        |   4 +
 14 files changed, 786 insertions(+), 360 deletions(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index 5bdccb4d..c7dbc9aa 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -74,6 +74,26 @@ ApplicationWindow{
 				Layout.alignment: Qt.AlignHCenter
 			}
 
+			Button {
+				id: verifyUserButton
+				text: "Verify"
+				Layout.alignment: Qt.AlignHCenter
+				enabled: profile.isUserVerified?false:true
+				visible: profile.isUserVerified?false:true
+				palette {
+					button: "white"
+				}
+				contentItem: Text {
+					text: verifyUserButton.text
+					color: "black"
+					horizontalAlignment: Text.AlignHCenter
+					verticalAlignment: Text.AlignVCenter
+				}
+				onClicked: {
+					profile.verifyUser();
+				}
+			}
+
 			RowLayout {
 				Layout.alignment: Qt.AlignHCenter
 				ImageButton {
@@ -127,7 +147,7 @@ ApplicationWindow{
 			}
 
 			ScrollView {
-				implicitHeight: userProfileDialog.height/2 + 20
+				implicitHeight: userProfileDialog.height/2-13
 				implicitWidth: userProfileDialog.width-20
 				clip: true
 				Layout.alignment: Qt.AlignHCenter
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index 6f69f026..c556a978 100644
--- a/resources/qml/delegates/MessageDelegate.qml
+++ b/resources/qml/delegates/MessageDelegate.qml
@@ -127,6 +127,60 @@ Item {
 				text: TimelineManager.timeline.formatMemberEvent(model.data.id);
 			}
 		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationRequest
+			NoticeMessage {
+				text: "KeyVerificationRequest";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationStart
+			NoticeMessage {
+				text: "KeyVerificationStart";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationReady
+			NoticeMessage {
+				text: "KeyVerificationReady";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationCancel
+			NoticeMessage {
+				text: "KeyVerificationCancel";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationKey
+			NoticeMessage {
+				text: "KeyVerificationKey";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationMac
+			NoticeMessage {
+				text: "KeyVerificationMac";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationDone
+			NoticeMessage {
+				text: "KeyVerificationDone";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationDone
+			NoticeMessage {
+				text: "KeyVerificationDone";
+			}
+		}
+		DelegateChoice {
+			roleValue: MtxEvent.KeyVerificationAccept
+			NoticeMessage {
+				text: "KeyVerificationAccept";
+			}
+		}
 		DelegateChoice {
 			Placeholder {}
 		}
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 1008277a..8cee3453 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1011,7 +1011,7 @@ Cache::saveState(const mtx::responses::Sync &res)
 
         savePresence(txn, res.presence);
 
-        updateUserCache(res.device_lists);
+        // updateUserCache(res.device_lists);
 
         removeLeftRooms(txn, res.rooms.leave);
 
diff --git a/src/ChatPage.h b/src/ChatPage.h
index 172f74fe..0e7c889f 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -167,16 +167,18 @@ signals:
 
         //! Signals for device verificaiton
         void recievedDeviceVerificationAccept(
-          const mtx::events::collections::DeviceEvents &message);
+          const mtx::events::msg::KeyVerificationAccept &message);
         void recievedDeviceVerificationRequest(
-          const mtx::events::collections::DeviceEvents &message);
+          const mtx::events::msg::KeyVerificationRequest &message,
+          std::string sender);
         void recievedDeviceVerificationCancel(
-          const mtx::events::collections::DeviceEvents &message);
-        void recievedDeviceVerificationKey(const mtx::events::collections::DeviceEvents &message);
-        void recievedDeviceVerificationMac(const mtx::events::collections::DeviceEvents &message);
-        void recievedDeviceVerificationStart(const mtx::events::collections::DeviceEvents &message);
-        void recievedDeviceVerificationReady(const mtx::events::collections::DeviceEvents &message);
-        void recievedDeviceVerificationDone(const mtx::events::collections::DeviceEvents &message);
+          const mtx::events::msg::KeyVerificationCancel &message);
+        void recievedDeviceVerificationKey(const mtx::events::msg::KeyVerificationKey &message);
+        void recievedDeviceVerificationMac(const mtx::events::msg::KeyVerificationMac &message);
+        void recievedDeviceVerificationStart(const mtx::events::msg::KeyVerificationStart &message,
+                                             std::string sender);
+        void recievedDeviceVerificationReady(const mtx::events::msg::KeyVerificationReady &message);
+        void recievedDeviceVerificationDone(const mtx::events::msg::KeyVerificationDone &message);
 
 private slots:
         void showUnreadMessageNotification(int count);
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index 0122e691..69de4937 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -6,11 +6,13 @@
 #include 
 #include 
 
+#include 
+
 static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes
 
 namespace msgs = mtx::events::msg;
 
-DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
+DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow::Type)
 {
         timeout = new QTimer(this);
         timeout->setSingleShot(true);
@@ -26,192 +28,218 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
           ChatPage::instance(),
           &ChatPage::recievedDeviceVerificationStart,
           this,
-          [this](const mtx::events::collections::DeviceEvents &message) {
-                  auto msg =
-                    std::get>(message);
-                  if (msg.content.transaction_id == this->transaction_id) {
-                          if ((std::find(msg.content.key_agreement_protocols.begin(),
-                                         msg.content.key_agreement_protocols.end(),
-                                         "curve25519-hkdf-sha256") !=
-                               msg.content.key_agreement_protocols.end()) &&
-                              (std::find(msg.content.hashes.begin(),
-                                         msg.content.hashes.end(),
-                                         "sha256") != msg.content.hashes.end()) &&
-                              (std::find(msg.content.message_authentication_codes.begin(),
-                                         msg.content.message_authentication_codes.end(),
-                                         "hmac-sha256") !=
-                               msg.content.message_authentication_codes.end())) {
-                                  if (std::find(msg.content.short_authentication_string.begin(),
-                                                msg.content.short_authentication_string.end(),
-                                                mtx::events::msg::SASMethods::Decimal) !=
-                                      msg.content.short_authentication_string.end()) {
-                                          this->method = DeviceVerificationFlow::Method::Emoji;
-                                  } else if (std::find(
-                                               msg.content.short_authentication_string.begin(),
-                                               msg.content.short_authentication_string.end(),
-                                               mtx::events::msg::SASMethods::Emoji) !=
-                                             msg.content.short_authentication_string.end()) {
-                                          this->method = DeviceVerificationFlow::Method::Decimal;
-                                  } else {
-                                          this->cancelVerification(
-                                            DeviceVerificationFlow::Error::UnknownMethod);
-                                          return;
-                                  }
-                                  this->acceptVerificationRequest();
-                                  this->canonical_json = nlohmann::json(msg.content);
-                          } else {
-                                  this->cancelVerification(
-                                    DeviceVerificationFlow::Error::UnknownMethod);
-                          }
+          [this](const mtx::events::msg::KeyVerificationStart &msg, std::string) {
+                  if (msg.transaction_id.has_value()) {
+                          if (msg.transaction_id.value() != this->transaction_id)
+                                  return;
+                  } else if (msg.relates_to.has_value()) {
+                          if (msg.relates_to.value().in_reply_to.event_id !=
+                              this->relation.in_reply_to.event_id)
+                                  return;
                   }
-          });
-        connect(
-          ChatPage::instance(),
-          &ChatPage::recievedDeviceVerificationAccept,
-          this,
-          [this](const mtx::events::collections::DeviceEvents &message) {
-                  auto msg =
-                    std::get>(message);
-                  if (msg.content.transaction_id == this->transaction_id) {
-                          if ((msg.content.key_agreement_protocol == "curve25519-hkdf-sha256") &&
-                              (msg.content.hash == "sha256") &&
-                              (msg.content.message_authentication_code == "hkdf-hmac-sha256")) {
-                                  this->commitment = msg.content.commitment;
-                                  if (std::find(msg.content.short_authentication_string.begin(),
-                                                msg.content.short_authentication_string.end(),
-                                                mtx::events::msg::SASMethods::Emoji) !=
-                                      msg.content.short_authentication_string.end()) {
-                                          this->method = DeviceVerificationFlow::Method::Emoji;
-                                  } else {
-                                          this->method = DeviceVerificationFlow::Method::Decimal;
-                                  }
-                                  this->mac_method = msg.content.message_authentication_code;
-                                  this->sendVerificationKey();
+                  if ((std::find(msg.key_agreement_protocols.begin(),
+                                 msg.key_agreement_protocols.end(),
+                                 "curve25519-hkdf-sha256") != msg.key_agreement_protocols.end()) &&
+                      (std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
+                       msg.hashes.end()) &&
+                      (std::find(msg.message_authentication_codes.begin(),
+                                 msg.message_authentication_codes.end(),
+                                 "hmac-sha256") != msg.message_authentication_codes.end())) {
+                          if (std::find(msg.short_authentication_string.begin(),
+                                        msg.short_authentication_string.end(),
+                                        mtx::events::msg::SASMethods::Decimal) !=
+                              msg.short_authentication_string.end()) {
+                                  this->method = DeviceVerificationFlow::Method::Emoji;
+                          } else if (std::find(msg.short_authentication_string.begin(),
+                                               msg.short_authentication_string.end(),
+                                               mtx::events::msg::SASMethods::Emoji) !=
+                                     msg.short_authentication_string.end()) {
+                                  this->method = DeviceVerificationFlow::Method::Decimal;
                           } else {
                                   this->cancelVerification(
                                     DeviceVerificationFlow::Error::UnknownMethod);
+                                  return;
                           }
+                          this->acceptVerificationRequest();
+                          this->canonical_json = nlohmann::json(msg);
+                  } else {
+                          this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
                   }
           });
+
+        connect(ChatPage::instance(),
+                &ChatPage::recievedDeviceVerificationAccept,
+                this,
+                [this](const mtx::events::msg::KeyVerificationAccept &msg) {
+                        if (msg.transaction_id.has_value()) {
+                                if (msg.transaction_id.value() != this->transaction_id)
+                                        return;
+                        } else if (msg.relates_to.has_value()) {
+                                if (msg.relates_to.value().in_reply_to.event_id !=
+                                    this->relation.in_reply_to.event_id)
+                                        return;
+                        }
+                        if ((msg.key_agreement_protocol == "curve25519-hkdf-sha256") &&
+                            (msg.hash == "sha256") &&
+                            (msg.message_authentication_code == "hkdf-hmac-sha256")) {
+                                this->commitment = msg.commitment;
+                                if (std::find(msg.short_authentication_string.begin(),
+                                              msg.short_authentication_string.end(),
+                                              mtx::events::msg::SASMethods::Emoji) !=
+                                    msg.short_authentication_string.end()) {
+                                        this->method = DeviceVerificationFlow::Method::Emoji;
+                                } else {
+                                        this->method = DeviceVerificationFlow::Method::Decimal;
+                                }
+                                this->mac_method = msg.message_authentication_code;
+                                this->sendVerificationKey();
+                        } else {
+                                this->cancelVerification(
+                                  DeviceVerificationFlow::Error::UnknownMethod);
+                        }
+                });
+
         connect(ChatPage::instance(),
                 &ChatPage::recievedDeviceVerificationCancel,
                 this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get>(message);
-                        if (msg.content.transaction_id == this->transaction_id) {
-                                emit verificationCanceled();
+                [this](const mtx::events::msg::KeyVerificationCancel &msg) {
+                        if (msg.transaction_id.has_value()) {
+                                if (msg.transaction_id.value() != this->transaction_id)
+                                        return;
+                        } else if (msg.relates_to.has_value()) {
+                                if (msg.relates_to.value().in_reply_to.event_id !=
+                                    this->relation.in_reply_to.event_id)
+                                        return;
+                        }
+                        emit verificationCanceled();
+                });
+
+        connect(ChatPage::instance(),
+                &ChatPage::recievedDeviceVerificationKey,
+                this,
+                [this](const mtx::events::msg::KeyVerificationKey &msg) {
+                        if (msg.transaction_id.has_value()) {
+                                if (msg.transaction_id.value() != this->transaction_id)
+                                        return;
+                        } else if (msg.relates_to.has_value()) {
+                                if (msg.relates_to.value().in_reply_to.event_id !=
+                                    this->relation.in_reply_to.event_id)
+                                        return;
+                        }
+                        this->sas->set_their_key(msg.key);
+                        std::string info;
+                        if (this->sender == true) {
+                                info = "MATRIX_KEY_VERIFICATION_SAS|" +
+                                       http::client()->user_id().to_string() + "|" +
+                                       http::client()->device_id() + "|" + this->sas->public_key() +
+                                       "|" + this->toClient.to_string() + "|" +
+                                       this->deviceId.toStdString() + "|" + msg.key + "|" +
+                                       this->transaction_id;
+                        } else {
+                                info = "MATRIX_KEY_VERIFICATION_SAS|" + this->toClient.to_string() +
+                                       "|" + this->deviceId.toStdString() + "|" + msg.key + "|" +
+                                       http::client()->user_id().to_string() + "|" +
+                                       http::client()->device_id() + "|" + this->sas->public_key() +
+                                       "|" + this->transaction_id;
+                        }
+
+                        if (this->method == DeviceVerificationFlow::Method::Emoji) {
+                                this->sasList = this->sas->generate_bytes_emoji(info);
+                        } else if (this->method == DeviceVerificationFlow::Method::Decimal) {
+                                this->sasList = this->sas->generate_bytes_decimal(info);
+                        }
+                        if (this->sender == false) {
+                                emit this->verificationRequestAccepted(this->method);
+                                this->sendVerificationKey();
+                        } else {
+                                if (this->commitment ==
+                                    mtx::crypto::bin2base64_unpadded(
+                                      mtx::crypto::sha256(msg.key + this->canonical_json.dump()))) {
+                                        emit this->verificationRequestAccepted(this->method);
+                                } else {
+                                        this->cancelVerification(
+                                          DeviceVerificationFlow::Error::MismatchedCommitment);
+                                }
                         }
                 });
+
         connect(
           ChatPage::instance(),
-          &ChatPage::recievedDeviceVerificationKey,
+          &ChatPage::recievedDeviceVerificationMac,
           this,
-          [this](const mtx::events::collections::DeviceEvents &message) {
-                  auto msg = std::get>(message);
-                  if (msg.content.transaction_id == this->transaction_id) {
-                          this->sas->set_their_key(msg.content.key);
-                          std::string info;
-                          if (this->sender == true) {
-                                  info = "MATRIX_KEY_VERIFICATION_SAS|" +
-                                         http::client()->user_id().to_string() + "|" +
-                                         http::client()->device_id() + "|" +
-                                         this->sas->public_key() + "|" +
-                                         this->toClient.to_string() + "|" +
-                                         this->deviceId.toStdString() + "|" + msg.content.key +
-                                         "|" + this->transaction_id;
-                          } else {
-                                  info = "MATRIX_KEY_VERIFICATION_SAS|" +
-                                         this->toClient.to_string() + "|" +
-                                         this->deviceId.toStdString() + "|" + msg.content.key +
-                                         "|" + http::client()->user_id().to_string() + "|" +
-                                         http::client()->device_id() + "|" +
-                                         this->sas->public_key() + "|" + this->transaction_id;
-                          }
-
-                          if (this->method == DeviceVerificationFlow::Method::Emoji) {
-                                  this->sasList = this->sas->generate_bytes_emoji(info);
-                          } else if (this->method == DeviceVerificationFlow::Method::Decimal) {
-                                  this->sasList = this->sas->generate_bytes_decimal(info);
-                          }
-                          if (this->sender == false) {
-                                  emit this->verificationRequestAccepted(this->method);
-                                  this->sendVerificationKey();
-                          } else {
-                                  if (this->commitment ==
-                                      mtx::crypto::bin2base64_unpadded(mtx::crypto::sha256(
-                                        msg.content.key + this->canonical_json.dump()))) {
-                                          emit this->verificationRequestAccepted(this->method);
+          [this](const mtx::events::msg::KeyVerificationMac &msg) {
+                  if (msg.transaction_id.has_value()) {
+                          if (msg.transaction_id.value() != this->transaction_id)
+                                  return;
+                  } else if (msg.relates_to.has_value()) {
+                          if (msg.relates_to.value().in_reply_to.event_id !=
+                              this->relation.in_reply_to.event_id)
+                                  return;
+                  }
+                  std::string info = "MATRIX_KEY_VERIFICATION_MAC" + this->toClient.to_string() +
+                                     this->deviceId.toStdString() +
+                                     http::client()->user_id().to_string() +
+                                     http::client()->device_id() + this->transaction_id;
+
+                  std::vector key_list;
+                  std::string key_string;
+                  for (auto mac : msg.mac) {
+                          key_string += mac.first + ",";
+                          if (device_keys[mac.first] != "") {
+                                  if (mac.second ==
+                                      this->sas->calculate_mac(this->device_keys[mac.first],
+                                                               info + mac.first)) {
                                   } else {
                                           this->cancelVerification(
-                                            DeviceVerificationFlow::Error::MismatchedCommitment);
+                                            DeviceVerificationFlow::Error::KeyMismatch);
+                                          return;
                                   }
                           }
                   }
-          });
-        connect(
-          ChatPage::instance(),
-          &ChatPage::recievedDeviceVerificationMac,
-          this,
-          [this](const mtx::events::collections::DeviceEvents &message) {
-                  auto msg = std::get>(message);
-                  if (msg.content.transaction_id == this->transaction_id) {
-                          std::string info =
-                            "MATRIX_KEY_VERIFICATION_MAC" + this->toClient.to_string() +
-                            this->deviceId.toStdString() + http::client()->user_id().to_string() +
-                            http::client()->device_id() + this->transaction_id;
-
-                          std::vector key_list;
-                          std::string key_string;
-                          for (auto mac : msg.content.mac) {
-                                  key_string += mac.first + ",";
-                                  if (device_keys[mac.first] != "") {
-                                          if (mac.second ==
-                                              this->sas->calculate_mac(this->device_keys[mac.first],
-                                                                       info + mac.first)) {
-                                          } else {
-                                                  this->cancelVerification(
-                                                    DeviceVerificationFlow::Error::KeyMismatch);
-                                                  return;
-                                          }
-                                  }
-                          }
-                          key_string = key_string.substr(0, key_string.length() - 1);
-                          if (msg.content.keys ==
-                              this->sas->calculate_mac(key_string, info + "KEY_IDS")) {
-                                  // uncomment this in future to be compatible with the
-                                  // MSC2366 this->sendVerificationDone(); and remove the
-                                  // below line
-                                  if (this->isMacVerified == true) {
-                                          this->acceptDevice();
-                                  } else
-                                          this->isMacVerified = true;
-                          } else {
-                                  this->cancelVerification(
-                                    DeviceVerificationFlow::Error::KeyMismatch);
-                          }
+                  key_string = key_string.substr(0, key_string.length() - 1);
+                  if (msg.keys == this->sas->calculate_mac(key_string, info + "KEY_IDS")) {
+                          // uncomment this in future to be compatible with the
+                          // MSC2366 this->sendVerificationDone(); and remove the
+                          // below line
+                          if (this->isMacVerified == true) {
+                                  this->acceptDevice();
+                          } else
+                                  this->isMacVerified = true;
+                  } else {
+                          this->cancelVerification(DeviceVerificationFlow::Error::KeyMismatch);
                   }
           });
+
         connect(ChatPage::instance(),
                 &ChatPage::recievedDeviceVerificationReady,
                 this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get>(message);
-                        if (msg.content.transaction_id == this->transaction_id) {
-                                this->startVerificationRequest();
+                [this](const mtx::events::msg::KeyVerificationReady &msg) {
+                        if (msg.transaction_id.has_value()) {
+                                if (msg.transaction_id.value() != this->transaction_id)
+                                        return;
+                        } else if (msg.relates_to.has_value()) {
+                                if (msg.relates_to.value().in_reply_to.event_id !=
+                                    this->relation.in_reply_to.event_id)
+                                        return;
                         }
+                        this->startVerificationRequest();
                 });
+
         connect(ChatPage::instance(),
                 &ChatPage::recievedDeviceVerificationDone,
                 this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get>(message);
-                        if (msg.content.transaction_id == this->transaction_id) {
-                                this->acceptDevice();
+                [this](const mtx::events::msg::KeyVerificationDone &msg) {
+                        if (msg.transaction_id.has_value()) {
+                                if (msg.transaction_id.value() != this->transaction_id)
+                                        return;
+                        } else if (msg.relates_to.has_value()) {
+                                if (msg.relates_to.value().in_reply_to.event_id !=
+                                    this->relation.in_reply_to.event_id)
+                                        return;
                         }
+                        this->acceptDevice();
                 });
+
         timeout->start(TIMEOUT);
 }
 
@@ -294,18 +322,18 @@ void
 DeviceVerificationFlow::setSender(bool sender_)
 {
         this->sender = sender_;
-        if (this->sender == true)
+        if (this->sender == true && this->type == DeviceVerificationFlow::Type::ToDevice)
                 this->transaction_id = http::client()->generate_txn_id();
+        else if (this->sender == true && this->type == DeviceVerificationFlow::Type::RoomMsg)
+                this->relation.in_reply_to.event_id = http::client()->generate_txn_id();
 }
 
 //! accepts a verification
 void
 DeviceVerificationFlow::acceptVerificationRequest()
 {
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationAccept req;
 
-        req.transaction_id              = this->transaction_id;
         req.method                      = mtx::events::msg::VerificationMethods::SASv1;
         req.key_agreement_protocol      = "curve25519-hkdf-sha256";
         req.hash                        = "sha256";
@@ -317,126 +345,152 @@ DeviceVerificationFlow::acceptVerificationRequest()
         req.commitment = mtx::crypto::bin2base64_unpadded(
           mtx::crypto::sha256(this->sas->public_key() + this->canonical_json.dump()));
 
-        body[this->toClient][this->deviceId.toStdString()] = req;
-
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [](mtx::http::RequestErr err) {
-                    if (err)
-                            nhlog::net()->warn("failed to accept verification request: {} {}",
-                                               err->matrix_error.error,
-                                               static_cast(err->status_code));
-            });
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                mtx::requests::ToDeviceMessages body;
+                req.transaction_id = this->transaction_id;
+
+                body[this->toClient][this->deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn(
+                                      "failed to accept verification request: {} {}",
+                                      err->matrix_error.error,
+                                      static_cast(err->status_code));
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                req.relates_to = this->relation;
+        }
 }
 //! responds verification request
 void
 DeviceVerificationFlow::sendVerificationReady()
 {
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationReady req;
 
-        req.from_device    = http::client()->device_id();
-        req.transaction_id = this->transaction_id;
-        req.methods        = {mtx::events::msg::VerificationMethods::SASv1};
-
-        body[this->toClient][this->deviceId.toStdString()] = req;
-
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [](mtx::http::RequestErr err) {
-                    if (err)
-                            nhlog::net()->warn("failed to send verification ready: {} {}",
-                                               err->matrix_error.error,
-                                               static_cast(err->status_code));
-            });
+        req.from_device = http::client()->device_id();
+        req.methods     = {mtx::events::msg::VerificationMethods::SASv1};
+
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                req.transaction_id = this->transaction_id;
+                mtx::requests::ToDeviceMessages body;
+
+                body[this->toClient][this->deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn("failed to send verification ready: {} {}",
+                                                       err->matrix_error.error,
+                                                       static_cast(err->status_code));
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                req.relates_to = this->relation;
+        }
 }
 //! accepts a verification
 void
 DeviceVerificationFlow::sendVerificationDone()
 {
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationDone req;
 
-        req.transaction_id = this->transaction_id;
-
-        body[this->toClient][this->deviceId.toStdString()] = req;
-
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [](mtx::http::RequestErr err) {
-                    if (err)
-                            nhlog::net()->warn("failed to send verification done: {} {}",
-                                               err->matrix_error.error,
-                                               static_cast(err->status_code));
-            });
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                mtx::requests::ToDeviceMessages body;
+                req.transaction_id = this->transaction_id;
+
+                body[this->toClient][this->deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn("failed to send verification done: {} {}",
+                                                       err->matrix_error.error,
+                                                       static_cast(err->status_code));
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                req.relates_to = this->relation;
+        }
 }
 //! starts the verification flow
 void
 DeviceVerificationFlow::startVerificationRequest()
 {
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationStart req;
 
         req.from_device                  = http::client()->device_id();
-        req.transaction_id               = this->transaction_id;
         req.method                       = mtx::events::msg::VerificationMethods::SASv1;
         req.key_agreement_protocols      = {"curve25519-hkdf-sha256"};
         req.hashes                       = {"sha256"};
-        req.message_authentication_codes = {"hkdf-hmac-sha256", "hmac-sha256"};
+        req.message_authentication_codes = {"hkdf-hmac-sha256"};
         req.short_authentication_string  = {mtx::events::msg::SASMethods::Decimal,
                                            mtx::events::msg::SASMethods::Emoji};
 
-        body[this->toClient][this->deviceId.toStdString()] = req;
-        this->canonical_json                               = nlohmann::json(req);
-
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [body](mtx::http::RequestErr err) {
-                    if (err)
-                            nhlog::net()->warn("failed to start verification request: {} {}",
-                                               err->matrix_error.error,
-                                               static_cast(err->status_code));
-            });
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                mtx::requests::ToDeviceMessages body;
+                req.transaction_id                                 = this->transaction_id;
+                this->canonical_json                               = nlohmann::json(req);
+                body[this->toClient][this->deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [body](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn(
+                                      "failed to start verification request: {} {}",
+                                      err->matrix_error.error,
+                                      static_cast(err->status_code));
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                req.relates_to = this->relation;
+        }
 }
 //! sends a verification request
 void
 DeviceVerificationFlow::sendVerificationRequest()
 {
-        QDateTime CurrentTime = QDateTime::currentDateTimeUtc();
-
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationRequest req;
 
-        req.from_device    = http::client()->device_id();
-        req.transaction_id = this->transaction_id;
+        req.from_device = http::client()->device_id();
         req.methods.resize(1);
         req.methods[0] = mtx::events::msg::VerificationMethods::SASv1;
-        req.timestamp  = (uint64_t)CurrentTime.toTime_t();
-
-        body[this->toClient][this->deviceId.toStdString()] = req;
-
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [](mtx::http::RequestErr err) {
-                    if (err)
-                            nhlog::net()->warn("failed to send verification request: {} {}",
-                                               err->matrix_error.error,
-                                               static_cast(err->status_code));
-            });
+
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                QDateTime CurrentTime = QDateTime::currentDateTimeUtc();
+
+                req.transaction_id = this->transaction_id;
+                req.timestamp      = (uint64_t)CurrentTime.toTime_t();
+
+                mtx::requests::ToDeviceMessages body;
+
+                body[this->toClient][this->deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn("failed to send verification request: {} {}",
+                                                       err->matrix_error.error,
+                                                       static_cast(err->status_code));
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                std::cout << "lulz" << std::endl;
+        }
 }
 //! cancels a verification flow
 void
 DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_code)
 {
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationCancel req;
 
-        req.transaction_id = this->transaction_id;
         if (error_code == DeviceVerificationFlow::Error::UnknownMethod) {
                 req.code   = "m.unknown_method";
                 req.reason = "unknown method recieved";
@@ -457,65 +511,79 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
                 req.reason = "user cancelled the verification";
         }
 
-        body[this->toClient][deviceId.toStdString()] = req;
-
         emit this->verificationCanceled();
 
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [this](mtx::http::RequestErr err) {
-                    if (err)
-                            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();
-            });
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                req.transaction_id = this->transaction_id;
+                mtx::requests::ToDeviceMessages body;
+
+                body[this->toClient][deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [this](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn(
+                                      "failed to cancel verification request: {} {}",
+                                      err->matrix_error.error,
+                                      static_cast(err->status_code));
+
+                            this->deleteLater();
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                req.relates_to = this->relation;
+        }
+
+        // TODO : Handle Blocking user better
+        // 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()}});
+        //     }
 }
 //! sends the verification key
 void
 DeviceVerificationFlow::sendVerificationKey()
 {
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationKey req;
 
-        req.key            = this->sas->public_key();
-        req.transaction_id = this->transaction_id;
-
-        body[this->toClient][deviceId.toStdString()] = req;
-
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [](mtx::http::RequestErr err) {
-                    if (err)
-                            nhlog::net()->warn("failed to send verification key: {} {}",
-                                               err->matrix_error.error,
-                                               static_cast(err->status_code));
-            });
+        req.key = this->sas->public_key();
+
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                mtx::requests::ToDeviceMessages body;
+                req.transaction_id = this->transaction_id;
+
+                body[this->toClient][deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn("failed to send verification key: {} {}",
+                                                       err->matrix_error.error,
+                                                       static_cast(err->status_code));
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                req.relates_to = this->relation;
+        }
 }
 //! sends the mac of the keys
 void
 DeviceVerificationFlow::sendVerificationMac()
 {
-        mtx::requests::ToDeviceMessages body;
         mtx::events::msg::KeyVerificationMac req;
 
         std::string info = "MATRIX_KEY_VERIFICATION_MAC" + http::client()->user_id().to_string() +
                            http::client()->device_id() + this->toClient.to_string() +
                            this->deviceId.toStdString() + this->transaction_id;
 
-        req.transaction_id = this->transaction_id;
         //! this vector stores the type of the key and the key
         std::vector> key_list;
         key_list.push_back(make_pair("ed25519", olm::client()->identity_keys().ed25519));
@@ -531,22 +599,28 @@ DeviceVerificationFlow::sendVerificationMac()
         req.keys =
           this->sas->calculate_mac(req.keys.substr(0, req.keys.size() - 1), info + "KEY_IDS");
 
-        body[this->toClient][deviceId.toStdString()] = req;
-
-        http::client()
-          ->send_to_device(
-            this->transaction_id, body, [this](mtx::http::RequestErr err) {
-                    if (err)
-                            nhlog::net()->warn("failed to send verification MAC: {} {}",
-                                               err->matrix_error.error,
-                                               static_cast(err->status_code));
-
-                    if (this->isMacVerified == true)
-                            this->acceptDevice();
-                    else
-                            this->isMacVerified = true;
-            });
+        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                mtx::requests::ToDeviceMessages body;
+                req.transaction_id                           = this->transaction_id;
+                body[this->toClient][deviceId.toStdString()] = req;
+
+                http::client()
+                  ->send_to_device(
+                    this->transaction_id, body, [this](mtx::http::RequestErr err) {
+                            if (err)
+                                    nhlog::net()->warn("failed to send verification MAC: {} {}",
+                                                       err->matrix_error.error,
+                                                       static_cast(err->status_code));
+
+                            if (this->isMacVerified == true)
+                                    this->acceptDevice();
+                            else
+                                    this->isMacVerified = true;
+                    });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg) {
+                req.relates_to = this->relation;
+        }
 }
 //! Completes the verification flow
 void
@@ -555,14 +629,11 @@ 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());
+                verified_cache->device_blocked.erase(
+                  std::remove(verified_cache->device_blocked.begin(),
+                              verified_cache->device_blocked.end(),
+                              this->deviceId.toStdString()),
+                  verified_cache->device_blocked.end());
         } else {
                 cache::setVerifiedCache(
                   this->userId.toStdString(),
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index edff7c8e..3f999e80 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -2,8 +2,8 @@
 
 #include "Olm.h"
 
+#include "MatrixClient.h"
 #include "mtx/responses/crypto.hpp"
-#include 
 #include 
 
 class QTimer;
@@ -19,15 +19,22 @@ 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(std::vector sasList READ getSasList)
+        Q_PROPERTY(std::vector sasList READ getSasList CONSTANT)
 
 public:
+        enum Type
+        {
+                ToDevice,
+                RoomMsg
+        };
+
         enum Method
         {
                 Decimal,
                 Emoji
         };
         Q_ENUM(Method)
+
         enum Error
         {
                 UnknownMethod,
@@ -39,7 +46,9 @@ public:
         };
         Q_ENUM(Error)
 
-        DeviceVerificationFlow(QObject *parent = nullptr);
+        DeviceVerificationFlow(
+          QObject *parent              = nullptr,
+          DeviceVerificationFlow::Type = DeviceVerificationFlow::Type::ToDevice);
         QString getTransactionId();
         QString getUserId();
         QString getDeviceId();
@@ -90,6 +99,7 @@ private:
         QString userId;
         QString deviceId;
         Method method;
+        Type type;
         bool sender;
 
         QTimer *timeout = nullptr;
@@ -101,4 +111,5 @@ private:
         mtx::identifiers::User toClient;
         std::vector sasList;
         std::map device_keys;
+        mtx::common::ReplyRelatesTo relation;
 };
diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp
index 0618206c..869687f4 100644
--- a/src/EventAccessors.cpp
+++ b/src/EventAccessors.cpp
@@ -72,8 +72,15 @@ struct EventBody
         template
         std::string operator()(const mtx::events::Event &e)
         {
-                if constexpr (is_detected::value)
-                        return e.content.body;
+                if constexpr (is_detected::value) {
+                        if constexpr (std::is_same_v,
+                                                     std::remove_cv_t>)
+                                return e.content.body ? e.content.body.value() : "";
+                        else if constexpr (std::is_same_v<
+                                             std::string,
+                                             std::remove_cv_t>)
+                                return e.content.body;
+                }
                 return "";
         }
 };
diff --git a/src/Olm.cpp b/src/Olm.cpp
index 7d7037c9..ff6ea2f4 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -5,10 +5,10 @@
 
 #include "Cache.h"
 #include "ChatPage.h"
+#include "DeviceVerificationFlow.h"
 #include "Logging.h"
 #include "MatrixClient.h"
 #include "Utils.h"
-#include 
 
 static const std::string STORAGE_SECRET_KEY("secret");
 constexpr auto MEGOLM_ALGO = "m.megolm.v1.aes-sha2";
@@ -77,21 +77,42 @@ handle_to_device_messages(const std::vectorrecievedDeviceVerificationAccept(msg);
+                        auto message = std::get<
+                          mtx::events::DeviceEvent>(msg);
+                        ChatPage::instance()->recievedDeviceVerificationAccept(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationRequest)) {
-                        ChatPage::instance()->recievedDeviceVerificationRequest(msg);
+                        auto message = std::get<
+                          mtx::events::DeviceEvent>(msg);
+                        ChatPage::instance()->recievedDeviceVerificationRequest(message.content,
+                                                                                message.sender);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationCancel)) {
-                        ChatPage::instance()->recievedDeviceVerificationCancel(msg);
+                        auto message = std::get<
+                          mtx::events::DeviceEvent>(msg);
+                        ChatPage::instance()->recievedDeviceVerificationCancel(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationKey)) {
-                        ChatPage::instance()->recievedDeviceVerificationKey(msg);
+                        auto message =
+                          std::get>(
+                            msg);
+                        ChatPage::instance()->recievedDeviceVerificationKey(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationMac)) {
-                        ChatPage::instance()->recievedDeviceVerificationMac(msg);
+                        auto message =
+                          std::get>(
+                            msg);
+                        ChatPage::instance()->recievedDeviceVerificationMac(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationStart)) {
-                        ChatPage::instance()->recievedDeviceVerificationStart(msg);
+                        auto message = std::get<
+                          mtx::events::DeviceEvent>(msg);
+                        ChatPage::instance()->recievedDeviceVerificationStart(message.content,
+                                                                              message.sender);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationReady)) {
-                        ChatPage::instance()->recievedDeviceVerificationReady(msg);
+                        auto message = std::get<
+                          mtx::events::DeviceEvent>(msg);
+                        ChatPage::instance()->recievedDeviceVerificationReady(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationDone)) {
-                        ChatPage::instance()->recievedDeviceVerificationDone(msg);
+                        auto message =
+                          std::get>(
+                            msg);
+                        ChatPage::instance()->recievedDeviceVerificationDone(message.content);
                 } else {
                         nhlog::crypto()->warn("unhandled event: {}", j_msg.dump(2));
                 }
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 773a5a23..71cc53c5 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -22,6 +22,8 @@
 #include "Utils.h"
 #include "dialogs/RawMessage.h"
 
+#include 
+
 Q_DECLARE_METATYPE(QModelIndex)
 
 namespace std {
@@ -116,7 +118,41 @@ struct RoomEventType
         {
                 return qml_mtx_events::EventType::VideoMessage;
         }
-
+        qml_mtx_events::EventType operator()(
+          const mtx::events::Event &)
+        {
+                return qml_mtx_events::EventType::KeyVerificationRequest;
+        }
+        qml_mtx_events::EventType operator()(
+          const mtx::events::Event &)
+        {
+                return qml_mtx_events::EventType::KeyVerificationStart;
+        }
+        qml_mtx_events::EventType operator()(
+          const mtx::events::Event &)
+        {
+                return qml_mtx_events::EventType::KeyVerificationMac;
+        }
+        qml_mtx_events::EventType operator()(
+          const mtx::events::Event &)
+        {
+                return qml_mtx_events::EventType::KeyVerificationAccept;
+        }
+        qml_mtx_events::EventType operator()(
+          const mtx::events::Event &)
+        {
+                return qml_mtx_events::EventType::KeyVerificationCancel;
+        }
+        qml_mtx_events::EventType operator()(
+          const mtx::events::Event &)
+        {
+                return qml_mtx_events::EventType::KeyVerificationKey;
+        }
+        qml_mtx_events::EventType operator()(
+          const mtx::events::Event &)
+        {
+                return qml_mtx_events::EventType::KeyVerificationDone;
+        }
         qml_mtx_events::EventType operator()(const mtx::events::Event &)
         {
                 return qml_mtx_events::EventType::Redacted;
@@ -572,6 +608,155 @@ TimelineModel::updateLastMessage()
         }
 }
 
+std::vector
+TimelineModel::internalAddEvents(
+  const std::vector &timeline)
+{
+        std::vector ids;
+        for (auto e : timeline) {
+                QString id = QString::fromStdString(mtx::accessors::event_id(e));
+
+                if (this->events.contains(id)) {
+                        this->events.insert(id, e);
+                        int idx = idToIndex(id);
+                        emit dataChanged(index(idx, 0), index(idx, 0));
+                        continue;
+                }
+
+                QString txid = QString::fromStdString(mtx::accessors::transaction_id(e));
+                if (this->pending.removeOne(txid)) {
+                        this->events.insert(id, e);
+                        this->events.remove(txid);
+                        int idx = idToIndex(txid);
+                        if (idx < 0) {
+                                nhlog::ui()->warn("Received index out of range");
+                                continue;
+                        }
+                        eventOrder[idx] = id;
+                        emit dataChanged(index(idx, 0), index(idx, 0));
+                        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);
+                        auto redacted   = std::find(eventOrder.begin(), eventOrder.end(), redacts);
+
+                        auto event = events.value(redacts);
+                        if (auto reaction =
+                              std::get_if>(
+                                &event)) {
+                                QString reactedTo =
+                                  QString::fromStdString(reaction->content.relates_to.event_id);
+                                reactions[reactedTo].removeReaction(*reaction);
+                                int idx = idToIndex(reactedTo);
+                                if (idx >= 0)
+                                        emit dataChanged(index(idx, 0), index(idx, 0));
+                        }
+
+                        if (redacted != eventOrder.end()) {
+                                auto redactedEvent = std::visit(
+                                  [](const auto &ev)
+                                    -> mtx::events::RoomEvent {
+                                          mtx::events::RoomEvent
+                                            replacement                = {};
+                                          replacement.event_id         = ev.event_id;
+                                          replacement.room_id          = ev.room_id;
+                                          replacement.sender           = ev.sender;
+                                          replacement.origin_server_ts = ev.origin_server_ts;
+                                          replacement.type             = ev.type;
+                                          return replacement;
+                                  },
+                                  e);
+                                events.insert(redacts, redactedEvent);
+
+                                int row = (int)std::distance(eventOrder.begin(), redacted);
+                                emit dataChanged(index(row, 0), index(row, 0));
+                        }
+
+                        continue; // don't insert redaction into timeline
+                }
+
+                if (auto reaction =
+                      std::get_if>(&e)) {
+                        QString reactedTo =
+                          QString::fromStdString(reaction->content.relates_to.event_id);
+                        events.insert(id, e);
+
+                        // remove local echo
+                        if (!txid.isEmpty()) {
+                                auto rCopy     = *reaction;
+                                rCopy.event_id = txid.toStdString();
+                                reactions[reactedTo].removeReaction(rCopy);
+                        }
+
+                        reactions[reactedTo].addReaction(room_id_.toStdString(), *reaction);
+                        int idx = idToIndex(reactedTo);
+                        if (idx >= 0)
+                                emit dataChanged(index(idx, 0), index(idx, 0));
+                        continue; // don't insert reaction into timeline
+                }
+
+                if (auto event =
+                      std::get_if>(&e)) {
+                        auto e_      = decryptEvent(*event).event;
+                        auto encInfo = mtx::accessors::file(e_);
+
+                        if (encInfo)
+                                emit newEncryptedImage(encInfo.value());
+                }
+
+                this->events.insert(id, e);
+                ids.push_back(id);
+
+                auto replyTo  = mtx::accessors::in_reply_to_event(e);
+                auto qReplyTo = QString::fromStdString(replyTo);
+                if (!replyTo.empty() && !events.contains(qReplyTo)) {
+                        http::client()->get_event(
+                          this->room_id_.toStdString(),
+                          replyTo,
+                          [this, id, replyTo](
+                            const mtx::events::collections::TimelineEvents &timeline,
+                            mtx::http::RequestErr err) {
+                                  if (err) {
+                                          nhlog::net()->error(
+                                            "Failed to retrieve event with id {}, which was "
+                                            "requested to show the replyTo for event {}",
+                                            replyTo,
+                                            id.toStdString());
+                                          return;
+                                  }
+                                  emit eventFetched(id, timeline);
+                          });
+                }
+        }
+        return ids;
+}
+
 void
 TimelineModel::setCurrentIndex(int index)
 {
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 104a475c..708ed38e 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -84,6 +84,14 @@ enum EventType
         VideoMessage,
         Redacted,
         UnknownMessage,
+        KeyVerificationRequest,
+        KeyVerificationStart,
+        KeyVerificationMac,
+        KeyVerificationAccept,
+        KeyVerificationCancel,
+        KeyVerificationKey,
+        KeyVerificationDone,
+        KeyVerificationReady
 };
 Q_ENUM_NS(EventType)
 
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 81c8d6d3..02b74d20 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -101,7 +101,15 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
   , blurhashProvider(new BlurhashProvider())
   , settings(userSettings)
 {
-        qRegisterMetaType();
+        qRegisterMetaType();
+        qRegisterMetaType();
+        qRegisterMetaType();
+        qRegisterMetaType();
+        qRegisterMetaType();
+        qRegisterMetaType();
+        qRegisterMetaType();
+        qRegisterMetaType();
+
         qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
                                          "im.nheko",
                                          1,
@@ -181,21 +189,19 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
           dynamic_cast(parent),
           &ChatPage::recievedDeviceVerificationRequest,
           this,
-          [this](const mtx::events::collections::DeviceEvents &message) {
-                  auto msg =
-                    std::get>(message);
+          [this](const mtx::events::msg::KeyVerificationRequest &msg, std::string sender) {
                   auto flow = new DeviceVerificationFlow(this);
-                  if (!(this->dvList->exist(QString::fromStdString(msg.content.transaction_id)))) {
-                          if (std::find(msg.content.methods.begin(),
-                                        msg.content.methods.end(),
+                  if (!(this->dvList->exist(QString::fromStdString(msg.transaction_id.value())))) {
+                          if (std::find(msg.methods.begin(),
+                                        msg.methods.end(),
                                         mtx::events::msg::VerificationMethods::SASv1) !=
-                              msg.content.methods.end()) {
+                              msg.methods.end()) {
                                   //   flow->sendVerificationReady();
                                   emit newDeviceVerificationRequest(
                                     std::move(flow),
-                                    QString::fromStdString(msg.content.transaction_id),
-                                    QString::fromStdString(msg.sender),
-                                    QString::fromStdString(msg.content.from_device));
+                                    QString::fromStdString(msg.transaction_id.value()),
+                                    QString::fromStdString(sender),
+                                    QString::fromStdString(msg.from_device));
                           } else {
                                   flow->cancelVerification(
                                     DeviceVerificationFlow::Error::UnknownMethod);
@@ -206,33 +212,29 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
           dynamic_cast(parent),
           &ChatPage::recievedDeviceVerificationStart,
           this,
-          [this](const mtx::events::collections::DeviceEvents &message) {
-                  auto msg =
-                    std::get>(message);
+          [this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) {
                   auto flow            = new DeviceVerificationFlow(this);
-                  flow->canonical_json = nlohmann::json(msg.content);
-                  if (!(this->dvList->exist(QString::fromStdString(msg.content.transaction_id)))) {
-                          if ((std::find(msg.content.key_agreement_protocols.begin(),
-                                         msg.content.key_agreement_protocols.end(),
+                  flow->canonical_json = nlohmann::json(msg);
+                  if (!(this->dvList->exist(QString::fromStdString(msg.transaction_id.value())))) {
+                          if ((std::find(msg.key_agreement_protocols.begin(),
+                                         msg.key_agreement_protocols.end(),
                                          "curve25519-hkdf-sha256") !=
-                               msg.content.key_agreement_protocols.end()) &&
-                              (std::find(msg.content.hashes.begin(),
-                                         msg.content.hashes.end(),
-                                         "sha256") != msg.content.hashes.end()) &&
-                              (std::find(msg.content.message_authentication_codes.begin(),
-                                         msg.content.message_authentication_codes.end(),
+                               msg.key_agreement_protocols.end()) &&
+                              (std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
+                               msg.hashes.end()) &&
+                              (std::find(msg.message_authentication_codes.begin(),
+                                         msg.message_authentication_codes.end(),
                                          "hmac-sha256") !=
-                               msg.content.message_authentication_codes.end())) {
-                                  if (std::find(msg.content.short_authentication_string.begin(),
-                                                msg.content.short_authentication_string.end(),
+                               msg.message_authentication_codes.end())) {
+                                  if (std::find(msg.short_authentication_string.begin(),
+                                                msg.short_authentication_string.end(),
                                                 mtx::events::msg::SASMethods::Emoji) !=
-                                      msg.content.short_authentication_string.end()) {
+                                      msg.short_authentication_string.end()) {
                                           flow->setMethod(DeviceVerificationFlow::Method::Emoji);
-                                  } else if (std::find(
-                                               msg.content.short_authentication_string.begin(),
-                                               msg.content.short_authentication_string.end(),
-                                               mtx::events::msg::SASMethods::Decimal) !=
-                                             msg.content.short_authentication_string.end()) {
+                                  } else if (std::find(msg.short_authentication_string.begin(),
+                                                       msg.short_authentication_string.end(),
+                                                       mtx::events::msg::SASMethods::Decimal) !=
+                                             msg.short_authentication_string.end()) {
                                           flow->setMethod(DeviceVerificationFlow::Method::Decimal);
                                   } else {
                                           flow->cancelVerification(
@@ -241,10 +243,10 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
                                   }
                                   emit newDeviceVerificationRequest(
                                     std::move(flow),
-                                    QString::fromStdString(msg.content.transaction_id),
-                                    QString::fromStdString(msg.sender),
-                                    QString::fromStdString(msg.content.from_device));
-                                  flow->canonical_json = nlohmann::json(msg.content);
+                                    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 a438ef5e..71aee5ef 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -133,4 +133,11 @@ private:
 
         DeviceVerificationList *dvList;
 };
-Q_DECLARE_METATYPE(mtx::events::collections::DeviceEvents)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationAccept)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationCancel)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationDone)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationKey)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationMac)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationReady)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationRequest)
+Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationStart)
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 6ae04d0b..3499384c 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -6,6 +6,8 @@
 #include "Utils.h"
 #include "mtx/responses/crypto.hpp"
 
+#include  // only for debugging
+
 UserProfile::UserProfile(QString roomid, QString userid, QObject *parent)
   : QObject(parent)
   , roomid_(roomid)
@@ -74,6 +76,12 @@ UserProfile::avatarUrl()
         return cache::avatarUrl(roomid_, userid_);
 }
 
+bool
+UserProfile::getUserStatus()
+{
+        return isUserVerified;
+}
+
 void
 UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
                          mtx::http::RequestErr err,
@@ -100,6 +108,7 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
 
                 // TODO: Verify signatures and ignore those that don't pass.
                 verification::Status verified = verification::Status::UNVERIFIED;
+                isUserVerified                = device_verified->is_user_verified;
                 if (device_verified.has_value()) {
                         if (std::find(device_verified->cross_verified.begin(),
                                       device_verified->cross_verified.end(),
@@ -174,4 +183,29 @@ UserProfile::startChat()
         if (utils::localUser() != this->userid_)
                 req.invite = {this->userid_.toStdString()};
         emit ChatPage::instance()->createRoom(req);
+}
+
+void
+UserProfile::verifyUser()
+{
+        std::cout << "Checking if to start to device verification or room message verification"
+                  << std::endl;
+        auto joined_rooms = cache::joinedRooms();
+        auto room_infos   = cache::getRoomInfo(joined_rooms);
+
+        for (std::string room_id : joined_rooms) {
+                if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
+                    cache::isRoomEncrypted(room_id)) {
+                        auto room_members = cache::roomMembers(room_id);
+                        if (std::find(room_members.begin(),
+                                      room_members.end(),
+                                      (this->userid()).toStdString()) != room_members.end()) {
+                                std::cout << "FOUND A ENCRYPTED ROOM WITH THIS USER : " << room_id
+                                          << std::endl;
+                                return;
+                        }
+                }
+        }
+
+        std::cout << "DIDN'T FIND A ENCRYPTED ROOM WITH THIS USER" << std::endl;
 }
\ No newline at end of file
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 4e048400..3f9cbe6f 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -81,6 +81,7 @@ class UserProfile : public QObject
         Q_PROPERTY(QString userid READ userid CONSTANT)
         Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
         Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
+        Q_PROPERTY(bool isUserVerified READ getUserStatus CONSTANT)
 public:
         UserProfile(QString roomid, QString userid, QObject *parent = 0);
 
@@ -89,17 +90,20 @@ public:
         QString userid();
         QString displayName();
         QString avatarUrl();
+        bool getUserStatus();
 
         Q_INVOKABLE void fetchDeviceList(const QString &userID);
         Q_INVOKABLE void banUser();
         // Q_INVOKABLE void ignoreUser();
         Q_INVOKABLE void kickUser();
         Q_INVOKABLE void startChat();
+        Q_INVOKABLE void verifyUser();
 
 private:
         QString roomid_, userid_;
         std::optional cross_verified;
         DeviceInfoModel deviceList_;
+        bool isUserVerified = false;
 
         void callback_fn(const mtx::responses::QueryKeys &res,
                          mtx::http::RequestErr err,
-- 
cgit 1.5.1


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: Add Room Verification Messages

---
 resources/qml/TimelineView.qml                     |  15 ++-
 .../qml/device-verification/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(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

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);
-- 
cgit 1.5.1


From 8a4bd37fead20e24876ec9ce703cabb041ec67ba Mon Sep 17 00:00:00 2001
From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>
Date: Tue, 18 Aug 2020 11:29:02 +0530
Subject: [WIP] Room Verification Works!

---
 resources/qml/UserProfile.qml        |  2 +-
 src/DeviceVerificationFlow.cpp       | 71 ++++++++++++++++++------------------
 src/DeviceVerificationFlow.h         |  6 +--
 src/Olm.cpp                          | 18 ++++++---
 src/timeline/EventStore.cpp          | 22 +++++++++--
 src/timeline/EventStore.h            |  1 +
 src/timeline/TimelineModel.cpp       |  7 ++--
 src/timeline/TimelineViewManager.cpp | 71 +++++++++++++++++++-----------------
 src/ui/UserProfile.cpp               |  5 ++-
 9 files changed, 114 insertions(+), 89 deletions(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index 9b53ff35..115a73c4 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -14,7 +14,7 @@ ApplicationWindow{
 	height: 650
 	width: 420
 	modality: Qt.WindowModal
-	Layout.alignment: Qt.AlignHCenter
+	Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
 	palette: colors
 
 	Connections{
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index 5069ff9d..8c230887 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -8,24 +8,31 @@
 #include 
 #include 
 
-#include 
-
 static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes
 
 namespace msgs = mtx::events::msg;
 
-DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow::Type flow_type)
+DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
+                                               DeviceVerificationFlow::Type flow_type,
+                                               TimelineModel *model)
   : type(flow_type)
+  , model_(model)
 {
         timeout = new QTimer(this);
         timeout->setSingleShot(true);
         this->sas           = olm::client()->sas_init();
         this->isMacVerified = false;
 
-        connect(this->model_,
-                &TimelineModel::updateFlowEventId,
-                this,
-                [this](std::string event_id) { this->relation.in_reply_to.event_id = event_id; });
+        if (model) {
+                connect(this->model_,
+                        &TimelineModel::updateFlowEventId,
+                        this,
+                        [this](std::string event_id) {
+                                this->relation.rel_type = mtx::common::RelationType::Reference;
+                                this->relation.event_id = event_id;
+                                this->transaction_id    = event_id;
+                        });
+        }
 
         connect(timeout, &QTimer::timeout, this, [this]() {
                 emit timedout();
@@ -42,8 +49,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                           if (msg.transaction_id.value() != this->transaction_id)
                                   return;
                   } else if (msg.relates_to.has_value()) {
-                          if (msg.relates_to.value().in_reply_to.event_id !=
-                              this->relation.in_reply_to.event_id)
+                          if (msg.relates_to.value().event_id != this->relation.event_id)
                                   return;
                   }
                   if ((std::find(msg.key_agreement_protocols.begin(),
@@ -69,8 +75,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                                     DeviceVerificationFlow::Error::UnknownMethod);
                                   return;
                           }
-                          this->acceptVerificationRequest();
                           this->canonical_json = nlohmann::json(msg);
+                          this->acceptVerificationRequest();
                   } else {
                           this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
                   }
@@ -84,8 +90,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                                 if (msg.transaction_id.value() != this->transaction_id)
                                         return;
                         } else if (msg.relates_to.has_value()) {
-                                if (msg.relates_to.value().in_reply_to.event_id !=
-                                    this->relation.in_reply_to.event_id)
+                                if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
                         }
                         if ((msg.key_agreement_protocol == "curve25519-hkdf-sha256") &&
@@ -116,8 +121,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                                 if (msg.transaction_id.value() != this->transaction_id)
                                         return;
                         } else if (msg.relates_to.has_value()) {
-                                if (msg.relates_to.value().in_reply_to.event_id !=
-                                    this->relation.in_reply_to.event_id)
+                                if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
                         }
                         emit verificationCanceled();
@@ -131,8 +135,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                                 if (msg.transaction_id.value() != this->transaction_id)
                                         return;
                         } else if (msg.relates_to.has_value()) {
-                                if (msg.relates_to.value().in_reply_to.event_id !=
-                                    this->relation.in_reply_to.event_id)
+                                if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
                         }
                         this->sas->set_their_key(msg.key);
@@ -157,6 +160,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                         } else if (this->method == DeviceVerificationFlow::Method::Decimal) {
                                 this->sasList = this->sas->generate_bytes_decimal(info);
                         }
+
                         if (this->sender == false) {
                                 emit this->verificationRequestAccepted(this->method);
                                 this->sendVerificationKey();
@@ -181,8 +185,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                           if (msg.transaction_id.value() != this->transaction_id)
                                   return;
                   } else if (msg.relates_to.has_value()) {
-                          if (msg.relates_to.value().in_reply_to.event_id !=
-                              this->relation.in_reply_to.event_id)
+                          if (msg.relates_to.value().event_id != this->relation.event_id)
                                   return;
                   }
                   std::string info = "MATRIX_KEY_VERIFICATION_MAC" + this->toClient.to_string() +
@@ -227,12 +230,11 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                                 if (msg.transaction_id.value() != this->transaction_id)
                                         return;
                         } else if (msg.relates_to.has_value()) {
-                                // this is just a workaround
-                                this->relation.in_reply_to.event_id =
-                                  msg.relates_to.value().in_reply_to.event_id;
-                                if (msg.relates_to.value().in_reply_to.event_id !=
-                                    this->relation.in_reply_to.event_id)
+                                if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
+                                else {
+                                        this->deviceId = QString::fromStdString(msg.from_device);
+                                }
                         }
                         this->startVerificationRequest();
                 });
@@ -245,8 +247,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                                 if (msg.transaction_id.value() != this->transaction_id)
                                         return;
                         } else if (msg.relates_to.has_value()) {
-                                if (msg.relates_to.value().in_reply_to.event_id !=
-                                    this->relation.in_reply_to.event_id)
+                                if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
                         }
                         this->acceptDevice();
@@ -297,12 +298,6 @@ DeviceVerificationFlow::getSasList()
         return this->sasList;
 }
 
-void
-DeviceVerificationFlow::setModel(TimelineModel *&model)
-{
-        this->model_ = model;
-}
-
 void
 DeviceVerificationFlow::setTransactionId(QString transaction_id_)
 {
@@ -351,15 +346,17 @@ DeviceVerificationFlow::setType(Type type)
 void
 DeviceVerificationFlow::setSender(bool sender_)
 {
-        this->sender         = sender_;
-        this->transaction_id = http::client()->generate_txn_id();
+        this->sender = sender_;
+        if (this->sender)
+                this->transaction_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;
+        this->relation.rel_type = mtx::common::RelationType::Reference;
+        this->relation.event_id = event_id;
+        this->transaction_id    = event_id;
 }
 
 //! accepts a verification
@@ -476,7 +473,8 @@ DeviceVerificationFlow::startVerificationRequest()
                                                      static_cast(err->status_code));
                   });
         } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.relates_to = this->relation;
+                req.relates_to       = this->relation;
+                this->canonical_json = nlohmann::json(req);
                 (model_)->sendMessage(req);
         }
 }
@@ -562,6 +560,7 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
         } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
                 (model_)->sendMessage(req);
+                this->deleteLater();
         }
 
         // TODO : Handle Blocking user better
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index 1ad3b1d0..4c3e5171 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -52,7 +52,8 @@ public:
 
         DeviceVerificationFlow(
           QObject *parent              = nullptr,
-          DeviceVerificationFlow::Type = DeviceVerificationFlow::Type::ToDevice);
+          DeviceVerificationFlow::Type = DeviceVerificationFlow::Type::ToDevice,
+          TimelineModel *model         = nullptr);
         // getters
         QString getTransactionId();
         QString getUserId();
@@ -62,7 +63,6 @@ public:
         std::vector getSasList();
         bool getSender();
         // setters
-        void setModel(TimelineModel *&model);
         void setTransactionId(QString transaction_id_);
         void setUserId(QString userID);
         void setDeviceId(QString deviceID);
@@ -127,5 +127,5 @@ private:
         std::optional room_id;
         std::optional event_id;
         TimelineModel *model_;
-        mtx::common::ReplyRelatesTo relation;
+        mtx::common::ReactionRelatesTo relation;
 };
diff --git a/src/Olm.cpp b/src/Olm.cpp
index ff6ea2f4..48439fa3 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -211,10 +211,15 @@ encrypt_group_message(const std::string &room_id, const std::string &device_id,
 
         // relations shouldn't be encrypted...
         mtx::common::ReplyRelatesTo relation;
+        mtx::common::ReactionRelatesTo r_relation;
+
         if (body["content"].contains("m.relates_to") &&
             body["content"]["m.relates_to"].contains("m.in_reply_to")) {
                 relation = body["content"]["m.relates_to"];
                 body["content"].erase("m.relates_to");
+        } else if (body["content"]["m.relates_to"].contains("event_id")) {
+                r_relation = body["content"]["m.relates_to"];
+                body["content"].erase("m.relates_to");
         }
 
         // Always check before for existence.
@@ -223,12 +228,13 @@ encrypt_group_message(const std::string &room_id, const std::string &device_id,
 
         // Prepare the m.room.encrypted event.
         msg::Encrypted data;
-        data.ciphertext = std::string((char *)payload.data(), payload.size());
-        data.sender_key = olm::client()->identity_keys().curve25519;
-        data.session_id = res.data.session_id;
-        data.device_id  = device_id;
-        data.algorithm  = MEGOLM_ALGO;
-        data.relates_to = relation;
+        data.ciphertext   = std::string((char *)payload.data(), payload.size());
+        data.sender_key   = olm::client()->identity_keys().curve25519;
+        data.session_id   = res.data.session_id;
+        data.device_id    = device_id;
+        data.algorithm    = MEGOLM_ALGO;
+        data.relates_to   = relation;
+        data.r_relates_to = r_relation;
 
         auto message_index = olm_outbound_group_session_message_index(res.session);
         nhlog::crypto()->debug("next message_index {}", message_index);
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 208b20e2..b210e157 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -95,8 +95,8 @@ EventStore::EventStore(std::string room_id, QObject *)
                                     room_id_,
                                     txn_id,
                                     e.content,
-                                    [this, txn_id](const mtx::responses::EventId &event_id,
-                                                   mtx::http::RequestErr err) {
+                                    [this, txn_id, e](const mtx::responses::EventId &event_id,
+                                                      mtx::http::RequestErr err) {
                                             if (err) {
                                                     const int status_code =
                                                       static_cast(err->status_code);
@@ -108,7 +108,21 @@ EventStore::EventStore(std::string room_id, QObject *)
                                                     emit messageFailed(txn_id);
                                                     return;
                                             }
+
                                             emit messageSent(txn_id, event_id.event_id.to_string());
+                                            if constexpr (mtx::events::message_content_to_type<
+                                                            decltype(e.content)> ==
+                                                          mtx::events::EventType::RoomEncrypted) {
+                                                    auto event =
+                                                      decryptEvent({room_id_, e.event_id}, e);
+                                                    if (auto dec =
+                                                          std::get_if>(event)) {
+                                                            emit updateFlowEventId(
+                                                              event_id.event_id.to_string());
+                                                    }
+                                            }
                                     });
                   },
                   event->data);
@@ -318,12 +332,12 @@ EventStore::reactions(const std::string &event_id)
 
                 if (auto reaction = std::get_if>(
                       related_event)) {
-                        auto &agg = aggregation[reaction->content.relates_to.key];
+                        auto &agg = aggregation[reaction->content.relates_to.key.value()];
 
                         if (agg.count == 0) {
                                 Reaction temp{};
                                 temp.key_ =
-                                  QString::fromStdString(reaction->content.relates_to.key);
+                                  QString::fromStdString(reaction->content.relates_to.key.value());
                                 reactions.push_back(temp);
                         }
 
diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h
index 28d46e90..55a66f49 100644
--- a/src/timeline/EventStore.h
+++ b/src/timeline/EventStore.h
@@ -100,6 +100,7 @@ signals:
         void messageFailed(std::string txn_id);
         void startDMVerification(
           mtx::events::RoomEvent &msg);
+        void updateFlowEventId(std::string event_id);
 
 public slots:
         void addPending(mtx::events::collections::TimelineEvents event);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 809fe382..dc5eb8cc 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -22,8 +22,6 @@
 #include "Utils.h"
 #include "dialogs/RawMessage.h"
 
-#include 
-
 Q_DECLARE_METATYPE(QModelIndex)
 
 namespace std {
@@ -237,6 +235,9 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
                 [this](mtx::events::RoomEvent msg) {
                         ChatPage::instance()->recievedRoomDeviceVerificationRequest(msg, this);
                 });
+        connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
+                this->updateFlowEventId(event_id);
+        });
 }
 
 QHash
@@ -814,7 +815,6 @@ TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent msg)
 
         json doc = {
           {"type", to_string(msg.type)}, {"content", json(msg.content)}, {"room_id", room_id}};
-        std::cout << doc.dump(2) << std::endl;
 
         try {
                 // Check if we have already an outbound megolm session then we can use.
@@ -1095,7 +1095,6 @@ struct SendMessageVisitor
 
         void operator()(const mtx::events::RoomEvent &msg)
         {
-                emit model_->updateFlowEventId(msg.event_id);
                 model_->sendEncryptedMessage(msg);
         }
         void operator()(const mtx::events::RoomEvent &msg)
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index c16e09d1..fb4a094e 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -194,13 +194,12 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
           [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);
+                          auto flow = new DeviceVerificationFlow(
+                            this, DeviceVerificationFlow::Type::RoomMsg, model);
                           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),
@@ -241,42 +240,48 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
           &ChatPage::recievedDeviceVerificationStart,
           this,
           [this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) {
-                  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") !=
-                               msg.key_agreement_protocols.end()) &&
-                              (std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
-                               msg.hashes.end()) &&
-                              (std::find(msg.message_authentication_codes.begin(),
-                                         msg.message_authentication_codes.end(),
-                                         "hmac-sha256") !=
-                               msg.message_authentication_codes.end())) {
-                                  if (std::find(msg.short_authentication_string.begin(),
-                                                msg.short_authentication_string.end(),
-                                                mtx::events::msg::SASMethods::Emoji) !=
-                                      msg.short_authentication_string.end()) {
-                                          flow->setMethod(DeviceVerificationFlow::Method::Emoji);
-                                  } else if (std::find(msg.short_authentication_string.begin(),
+                  if (msg.transaction_id.has_value()) {
+                          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") !=
+                                       msg.key_agreement_protocols.end()) &&
+                                      (std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
+                                       msg.hashes.end()) &&
+                                      (std::find(msg.message_authentication_codes.begin(),
+                                                 msg.message_authentication_codes.end(),
+                                                 "hmac-sha256") !=
+                                       msg.message_authentication_codes.end())) {
+                                          if (std::find(msg.short_authentication_string.begin(),
+                                                        msg.short_authentication_string.end(),
+                                                        mtx::events::msg::SASMethods::Emoji) !=
+                                              msg.short_authentication_string.end()) {
+                                                  flow->setMethod(
+                                                    DeviceVerificationFlow::Method::Emoji);
+                                          } else if (std::find(
+                                                       msg.short_authentication_string.begin(),
                                                        msg.short_authentication_string.end(),
                                                        mtx::events::msg::SASMethods::Decimal) !=
-                                             msg.short_authentication_string.end()) {
-                                          flow->setMethod(DeviceVerificationFlow::Method::Decimal);
+                                                     msg.short_authentication_string.end()) {
+                                                  flow->setMethod(
+                                                    DeviceVerificationFlow::Method::Decimal);
+                                          } else {
+                                                  flow->cancelVerification(
+                                                    DeviceVerificationFlow::Error::UnknownMethod);
+                                                  return;
+                                          }
+                                          emit newDeviceVerificationRequest(
+                                            std::move(flow),
+                                            QString::fromStdString(msg.transaction_id.value()),
+                                            QString::fromStdString(sender),
+                                            QString::fromStdString(msg.from_device));
                                   } else {
                                           flow->cancelVerification(
                                             DeviceVerificationFlow::Error::UnknownMethod);
-                                          return;
                                   }
-                                  emit newDeviceVerificationRequest(
-                                    std::move(flow),
-                                    QString::fromStdString(msg.transaction_id.value()),
-                                    QString::fromStdString(sender),
-                                    QString::fromStdString(msg.from_device));
-                          } else {
-                                  flow->cancelVerification(
-                                    DeviceVerificationFlow::Error::UnknownMethod);
                           }
                   }
           });
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 1eaa9d27..87eae001 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -211,8 +211,9 @@ UserProfile::createFlow(bool isVerifyUser)
                                           << std::endl;
                                         if (this->roomid_.toStdString() == room_id) {
                                                 auto newflow = new DeviceVerificationFlow(
-                                                  this, DeviceVerificationFlow::Type::RoomMsg);
-                                                newflow->setModel(this->model);
+                                                  this,
+                                                  DeviceVerificationFlow::Type::RoomMsg,
+                                                  this->model);
                                                 return (std::move(newflow));
                                         } else {
                                                 std::cout << "FOUND A ENCRYPTED ROOM BUT CURRENTLY "
-- 
cgit 1.5.1


From 2b5deabbdc72f278ea112139999f6e91b8e571b7 Mon Sep 17 00:00:00 2001
From: Chethan2k1 <40890937+Chethan2k1@users.noreply.github.com>
Date: Thu, 10 Sep 2020 14:50:10 +0530
Subject: Fix breaking while using qmlRegisterSingletonInstance

---
 src/DeviceVerificationFlow.cpp       | 4 +---
 src/timeline/TimelineViewManager.cpp | 8 ++++++--
 2 files changed, 7 insertions(+), 5 deletions(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index 70cc0baf..96fed55a 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -41,9 +41,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                 this->deleteLater();
         });
 
-        connect(this,&DeviceVerificationFlow::deleteFlow,this,[this](){
-                this->deleteLater();
-        });
+        connect(this, &DeviceVerificationFlow::deleteFlow, this, [this]() { this->deleteLater(); });
 
         connect(
           ChatPage::instance(),
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index f199578f..97c119bf 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -140,8 +140,12 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
           0,
           "UserProfileModel",
           "UserProfile needs to be instantiated on the C++ side");
-        qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", this);
-        qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", settings.data());
+        qmlRegisterSingletonType(
+          "im.nheko", 1, 0, "TimelineManager", [this](QQmlEngine *, QJSEngine *) { return this; });
+        qmlRegisterSingletonType(
+          "im.nheko", 1, 0, "Settings", [this](QQmlEngine *, QJSEngine *) {
+                  return this->settings.data();
+          });
 
         qRegisterMetaType();
         qRegisterMetaType>();
-- 
cgit 1.5.1


From bca29a4227a871caac21236c29430b69264018ce Mon Sep 17 00:00:00 2001
From: Nicolas Werner 
Date: Mon, 5 Oct 2020 22:12:10 +0200
Subject: Make steps in verification flow explicit

---
 resources/qml/TimelineView.qml                     |  14 +-
 resources/qml/UserProfile.qml                      |  31 +-
 .../AcceptNewVerificationRequest.qml               |  49 --
 .../AwaitingVerificationConfirmation.qml           |   5 +-
 .../AwaitingVerificationRequest.qml                |  40 --
 .../qml/device-verification/DeviceVerification.qml |  80 +--
 .../qml/device-verification/DigitVerification.qml  |  12 +-
 .../qml/device-verification/EmojiVerification.qml  |  12 +-
 resources/qml/device-verification/Failed.qml       |  42 ++
 .../device-verification/NewVerificationRequest.qml |  37 +-
 .../qml/device-verification/PartnerAborted.qml     |  34 --
 resources/qml/device-verification/Success.qml      |  31 ++
 resources/qml/device-verification/TimedOut.qml     |  35 --
 .../device-verification/VerificationSuccess.qml    |  35 --
 resources/qml/device-verification/Waiting.qml      |  45 ++
 resources/res.qrc                                  |   9 +-
 src/ChatPage.h                                     |  18 +-
 src/DeviceVerificationFlow.cpp                     | 613 ++++++++++-----------
 src/DeviceVerificationFlow.h                       | 215 ++++++--
 src/Olm.cpp                                        |  32 +-
 src/timeline/EventStore.cpp                        |  16 +-
 src/timeline/TimelineModel.cpp                     |   4 +-
 src/timeline/TimelineViewManager.cpp               | 194 +++----
 src/timeline/TimelineViewManager.h                 |  25 +-
 src/ui/UserProfile.cpp                             |  55 +-
 src/ui/UserProfile.h                               |  10 +-
 26 files changed, 798 insertions(+), 895 deletions(-)
 delete mode 100644 resources/qml/device-verification/AcceptNewVerificationRequest.qml
 delete mode 100644 resources/qml/device-verification/AwaitingVerificationRequest.qml
 create mode 100644 resources/qml/device-verification/Failed.qml
 delete mode 100644 resources/qml/device-verification/PartnerAborted.qml
 create mode 100644 resources/qml/device-verification/Success.qml
 delete mode 100644 resources/qml/device-verification/TimedOut.qml
 delete mode 100644 resources/qml/device-verification/VerificationSuccess.qml
 create mode 100644 resources/qml/device-verification/Waiting.qml

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index 3f72a7dd..1dbe7c1a 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -106,19 +106,7 @@ Page {
 		Connections {
 			target: TimelineManager
 			function onNewDeviceVerificationRequest(flow,transactionId,userId,deviceId,isRequest) {
-				flow.userId = userId;
-				flow.sender = false;
-				flow.deviceId = deviceId;
-				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,tran_id: flow.tranId});
+				var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow});
 				dialog.show();
 			}
 		}
diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index dc6bc165..e7dcc777 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -15,24 +15,12 @@ ApplicationWindow{
 	width: 420
 	minimumHeight: 420
 
-	modality: Qt.WindowModal
 	palette: colors
 
-	Connections{
-		target: deviceVerificationList
-		function onUpdateProfile() {
-			profile.fetchDeviceList(profile.userid)
-		}
-	}
-
 	Component {
 		id: deviceVerificationDialog
 		DeviceVerification {}
 	}
-	Component{
-		id: deviceVerificationFlow
-		DeviceVerificationFlow {}
-	}
 
 	ColumnLayout{
 		id: contentL
@@ -73,14 +61,7 @@ ApplicationWindow{
 			enabled: !profile.isUserVerified
 			visible: !profile.isUserVerified
 
-			onClicked: {
-				var newFlow = profile.createFlow(true);
-				newFlow.userId = profile.userid;
-				newFlow.sender = true;
-				deviceVerificationList.add(newFlow.tranId);
-				var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow,isRequest: true,tran_id: newFlow.tranId});
-				dialog.show();
-			}
+			onClicked: profile.verify()
 		}
 
 		RowLayout {
@@ -172,17 +153,11 @@ ApplicationWindow{
 					id: verifyButton
 					text: (model.verificationStatus != VerificationStatus.VERIFIED)?"Verify":"Unverify"
 					onClicked: {
-						var newFlow = profile.createFlow(false);
-						newFlow.userId = profile.userid;
-						newFlow.sender = true;
-						newFlow.deviceId = model.deviceId;
 						if(model.verificationStatus == VerificationStatus.VERIFIED){
-							newFlow.unverify();
+							profile.unverify(model.deviceId)
 							deviceVerificationList.updateProfile(newFlow.userId);
 						}else{
-							deviceVerificationList.add(newFlow.tranId);
-							var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow,isRequest:false,tran_id: newFlow.tranId});
-							dialog.show();
+							profile.verify(model.deviceId);
 						}
 					}
 				}
diff --git a/resources/qml/device-verification/AcceptNewVerificationRequest.qml b/resources/qml/device-verification/AcceptNewVerificationRequest.qml
deleted file mode 100644
index 5bdbc4a6..00000000
--- a/resources/qml/device-verification/AcceptNewVerificationRequest.qml
+++ /dev/null
@@ -1,49 +0,0 @@
-import QtQuick 2.3
-import QtQuick.Controls 2.10
-import QtQuick.Layouts 1.10
-
-import im.nheko 1.0
-
-Pane {
-	property string title: qsTr("Recieving Device Verification Request")
-	Component {
-		id: awaitingVerificationRequestAccept
-		AwaitingVerificationRequest {}
-	}
-	ColumnLayout {
-		spacing: 16
-		Label {
-			Layout.maximumWidth: 400
-			Layout.fillHeight: true
-			Layout.fillWidth: true
-			wrapMode: Text.Wrap
-			text: qsTr("The device was requested to be verified")
-			color:colors.text
-			verticalAlignment: Text.AlignVCenter
-		}
-		RowLayout {
-			Button {
-				Layout.alignment: Qt.AlignLeft
-				text: qsTr("Deny")
-
-				onClicked: { 
-					flow.cancelVerification(DeviceVerificationFlow.User);
-					deviceVerificationList.remove(tran_id);
-					dialog.destroy();
-				}
-			}
-			Item {
-				Layout.fillWidth: true
-			}
-			Button {
-				Layout.alignment: Qt.AlignRight
-				text: qsTr("Accept")
-
-				onClicked: { 
-					stack.replace(awaitingVerificationRequestAccept); 
-					flow.sender ?flow.sendVerificationReady():flow.acceptVerificationRequest(); 
-				}
-			}
-		}
-	}
-}
diff --git a/resources/qml/device-verification/AwaitingVerificationConfirmation.qml b/resources/qml/device-verification/AwaitingVerificationConfirmation.qml
index aaebba6a..cd8ccfd9 100644
--- a/resources/qml/device-verification/AwaitingVerificationConfirmation.qml
+++ b/resources/qml/device-verification/AwaitingVerificationConfirmation.qml
@@ -27,9 +27,8 @@ Pane {
 				text: qsTr("Cancel")
 
 				onClicked: { 
-					flow.cancelVerification(DeviceVerificationFlow.User); 
-					deviceVerificationList.remove(tran_id);
-					dialog.destroy();
+					flow.cancel();
+					dialog.close();
 				}
 			}
 			Item {
diff --git a/resources/qml/device-verification/AwaitingVerificationRequest.qml b/resources/qml/device-verification/AwaitingVerificationRequest.qml
deleted file mode 100644
index b4b9178a..00000000
--- a/resources/qml/device-verification/AwaitingVerificationRequest.qml
+++ /dev/null
@@ -1,40 +0,0 @@
-import QtQuick 2.3
-import QtQuick.Controls 2.10
-import QtQuick.Layouts 1.10
-
-import im.nheko 1.0
-
-Pane {
-	property string title: qsTr("Waiting for other party")
-	ColumnLayout {
-		spacing: 16
-		Label {
-			Layout.maximumWidth: 400
-			Layout.fillHeight: true
-			Layout.fillWidth: true
-			wrapMode: Text.Wrap
-			id: content
-			text: qsTr("Waiting for other side to accept the verification request.")
-			color:colors.text
-			verticalAlignment: Text.AlignVCenter
-		}
-		BusyIndicator {
-			Layout.alignment: Qt.AlignHCenter
-		}
-		RowLayout {
-			Button {
-				Layout.alignment: Qt.AlignLeft
-				text: qsTr("Cancel")
-
-				onClicked: { 
-					flow.cancelVerification(DeviceVerificationFlow.User);
-					deviceVerificationList.remove(tran_id);
-					dialog.destroy();
-				}
-			}
-			Item {
-				Layout.fillWidth: true
-			}
-		}
-	}
-}
diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index ca980987..4e93df06 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -18,36 +18,31 @@ ApplicationWindow {
 	height: stack.implicitHeight
 	width: stack.implicitWidth
 
-	Component{
-		id: newVerificationRequest
-		NewVerificationRequest {}
-	}
-
-	Component{
-		id: acceptNewVerificationRequest
-		AcceptNewVerificationRequest {}
-	}
-
 	StackView {
 		id: stack
-		initialItem: flow.sender == true?newVerificationRequest:acceptNewVerificationRequest
+		initialItem: newVerificationRequest
 		implicitWidth: currentItem.implicitWidth
 		implicitHeight: currentItem.implicitHeight
 	}
 
+	Component{
+		id: newVerificationRequest
+		NewVerificationRequest {}
+	}
+
 	Component {
-		id: partnerAborted
-		PartnerAborted {}
+		id: waiting
+		Waiting {}
 	}
 
 	Component {
-		id: timedout
-		TimedOut {}
+		id: success
+		Success {}
 	}
 
 	Component {
-		id: verificationSuccess
-		VerificationSuccess {}
+		id: failed
+		Failed {}
 	}
 
 	Component {
@@ -60,19 +55,42 @@ ApplicationWindow {
 		EmojiVerification {}
 	}
 
-	Connections {
-		target: flow
-		onVerificationCanceled: stack.replace(partnerAborted)
-		onTimedout: stack.replace(timedout)
-		onDeviceVerified: stack.replace(verificationSuccess)
-
-		onVerificationRequestAccepted: switch(method) {
-			case DeviceVerificationFlow.Decimal: stack.replace(digitVerification); break;
-			case DeviceVerificationFlow.Emoji: stack.replace(emojiVerification); break;
+	Item {
+	state: flow.state
+
+	states: [
+		State {
+			name: "PromptStartVerification"
+			StateChangeScript { script: stack.replace(newVerificationRequest) }
+		},
+		State {
+			name: "CompareEmoji"
+			StateChangeScript { script: stack.replace(emojiVerification) }
+		},
+		State {
+			name: "CompareNumber"
+			StateChangeScript { script: stack.replace(digitVerification) }
+		},
+		State {
+			name: "WaitingForKeys"
+			StateChangeScript { script: stack.replace(waiting) }
+		},
+		State {
+			name: "WaitingForOtherToAccept"
+			StateChangeScript { script: stack.replace(waiting) }
+		},
+		State {
+			name: "WaitingForMac"
+			StateChangeScript { script: stack.replace(waiting) }
+		},
+		State {
+			name: "Success"
+			StateChangeScript { script: stack.replace(success) }
+		},
+		State {
+			name: "Failed"
+			StateChangeScript { script: stack.replace(failed); }
 		}
-
-		onRefreshProfile: {
-			deviceVerificationList.updateProfile(flow.userId);
-		}
-	}
+	]
+}
 }
diff --git a/resources/qml/device-verification/DigitVerification.qml b/resources/qml/device-verification/DigitVerification.qml
index f3b1f5cf..ff878a50 100644
--- a/resources/qml/device-verification/DigitVerification.qml
+++ b/resources/qml/device-verification/DigitVerification.qml
@@ -6,10 +6,7 @@ import im.nheko 1.0
 
 Pane {
 	property string title: qsTr("Verification Code")
-	Component {
-		id: awaitingVerificationConfirmation
-		AwaitingVerificationConfirmation {}
-	}
+
 	ColumnLayout {
 		spacing: 16
 		Label {
@@ -45,9 +42,8 @@ Pane {
 				text: qsTr("They do not match!")
 
 				onClicked: {
-					flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
-					deviceVerificationList.remove(tran_id);
-					dialog.destroy();
+					flow.cancel();
+					dialog.close();
 				}
 			}
 			Item {
@@ -57,7 +53,7 @@ Pane {
 				Layout.alignment: Qt.AlignRight
 				text: qsTr("They match!")
 
-				onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
+				onClicked: flow.next();
 			}
 		}
 	}
diff --git a/resources/qml/device-verification/EmojiVerification.qml b/resources/qml/device-verification/EmojiVerification.qml
index 19faf1b7..ed7727aa 100644
--- a/resources/qml/device-verification/EmojiVerification.qml
+++ b/resources/qml/device-verification/EmojiVerification.qml
@@ -6,10 +6,7 @@ import im.nheko 1.0
 
 Pane {
 	property string title: qsTr("Verification Code")
-	Component {
-		id: awaitingVerificationConfirmation
-		AwaitingVerificationConfirmation{}
-	}
+
 	ColumnLayout {
 		spacing: 16
 		Label {
@@ -125,9 +122,8 @@ Pane {
 				text: qsTr("They do not match!")
 
 				onClicked: {  
-					flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
-					deviceVerificationList.remove(tran_id);
-					dialog.destroy();
+					flow.cancel();
+					dialog.close();
 				}
 			}
 			Item {
@@ -137,7 +133,7 @@ Pane {
 				Layout.alignment: Qt.AlignRight
 				text: qsTr("They match!")
 
-				onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
+				onClicked: flow.next()
 			}
 		}
 	}
diff --git a/resources/qml/device-verification/Failed.qml b/resources/qml/device-verification/Failed.qml
new file mode 100644
index 00000000..6b5d57ef
--- /dev/null
+++ b/resources/qml/device-verification/Failed.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+Pane {
+	property string title: qsTr("Verification timed out")
+	ColumnLayout {
+		spacing: 16
+		Text {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: switch (flow.error) {
+				case VerificationStatus.UnknownMethod: return qsTr("Device verification timed out.")
+				case VerificationStatus.MismatchedCommitment: return qsTr("Device verification timed out.")
+				case VerificationStatus.MismatchedSAS: return qsTr("Device verification timed out.")
+				case VerificationStatus.KeyMismatch: return qsTr("Device verification timed out.")
+				case VerificationStatus.Timeout: return qsTr("Device verification timed out.")
+				case VerificationStatus.OutOfOrder: return qsTr("Device verification timed out.")
+			}
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("Close")
+
+				onClicked: {
+					deviceVerificationList.remove(tran_id);
+					flow.deleteFlow();
+					dialog.close()
+				}
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/NewVerificationRequest.qml b/resources/qml/device-verification/NewVerificationRequest.qml
index ef730b13..bd25bb90 100644
--- a/resources/qml/device-verification/NewVerificationRequest.qml
+++ b/resources/qml/device-verification/NewVerificationRequest.qml
@@ -2,12 +2,11 @@ import QtQuick 2.3
 import QtQuick.Controls 2.10
 import QtQuick.Layouts 1.10
 
+import im.nheko 1.0
+
 Pane {
-	property string title: qsTr("Sending Device Verification Request")
-	Component {
-		id: awaitingVerificationRequestAccept
-		AwaitingVerificationRequest {}
-	}
+	property string title: flow.sender ? qsTr("Send Device Verification Request") : qsTr("Recieved Device Verification Request")
+
 	ColumnLayout {
 		spacing: 16
 		Label {
@@ -15,28 +14,20 @@ Pane {
 			Layout.fillHeight: true
 			Layout.fillWidth: true
 			wrapMode: Text.Wrap
-			text: qsTr("A new device was added.")
-			color:colors.text
-			verticalAlignment: Text.AlignVCenter
-		}
-		Label {
-			Layout.maximumWidth: 400
-			Layout.fillHeight: true
-			Layout.fillWidth: true
-			wrapMode: Text.Wrap
-			text: qsTr("The device may have been added by you signing in from another client or physical device. To ensure that no malicious user can eavesdrop on your encrypted communications, you should verify the new device.")
+			text: flow.sender ?
+			    qsTr("To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device.")
+			    : qsTr("The device was requested to be verified")
 			color:colors.text
 			verticalAlignment: Text.AlignVCenter
 		}
 		RowLayout {
 			Button {
 				Layout.alignment: Qt.AlignLeft
-				text: qsTr("Cancel")
+				text: flow.sender ? qsTr("Cancel") : qsTr("Deny")
 
 				onClicked: { 
-					deviceVerificationList.remove(tran_id);
-					flow.deleteFlow();
-					dialog.destroy();  
+					flow.cancel();
+					dialog.close();
 				}
 			}
 			Item {
@@ -44,12 +35,10 @@ Pane {
 			}
 			Button {
 				Layout.alignment: Qt.AlignRight
-				text: qsTr("Start verification")
+				text: flow.sender ? qsTr("Start verification") : qsTr("Accept")
 
-				onClicked: { 
-					stack.replace(awaitingVerificationRequestAccept); 
-					flow.sender ?flow.sendVerificationRequest():flow.startVerificationRequest(); }
-				}
+				onClicked: flow.next();
 			}
 		}
 	}
+}
diff --git a/resources/qml/device-verification/PartnerAborted.qml b/resources/qml/device-verification/PartnerAborted.qml
deleted file mode 100644
index 6174477d..00000000
--- a/resources/qml/device-verification/PartnerAborted.qml
+++ /dev/null
@@ -1,34 +0,0 @@
-import QtQuick 2.3
-import QtQuick.Controls 2.10
-import QtQuick.Layouts 1.10
-
-Pane {
-	property string title: qsTr("Verification aborted!")
-	ColumnLayout {
-		spacing: 16
-		Label {
-			Layout.maximumWidth: 400
-			Layout.fillHeight: true
-			Layout.fillWidth: true
-			wrapMode: Text.Wrap
-			id: content
-			text: qsTr("Verification canceled by the other party!")
-			color:colors.text
-			verticalAlignment: Text.AlignVCenter
-		}
-		RowLayout {
-			Item {
-				Layout.fillWidth: true
-			}
-			Button {
-				Layout.alignment: Qt.AlignRight
-				text: qsTr("Close")
-
-				onClicked: {
-					deviceVerificationList.remove(tran_id);
-					dialog.destroy();
-				}
-			}
-		}
-	}
-}
diff --git a/resources/qml/device-verification/Success.qml b/resources/qml/device-verification/Success.qml
new file mode 100644
index 00000000..b17b293c
--- /dev/null
+++ b/resources/qml/device-verification/Success.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+Pane {
+	property string title: qsTr("Successful Verification")
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: qsTr("Verification successful! Both sides verified their devices!")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("Close")
+
+				onClicked: dialog.close();
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/TimedOut.qml b/resources/qml/device-verification/TimedOut.qml
deleted file mode 100644
index 7dd0ab69..00000000
--- a/resources/qml/device-verification/TimedOut.qml
+++ /dev/null
@@ -1,35 +0,0 @@
-import QtQuick 2.3
-import QtQuick.Controls 2.10
-import QtQuick.Layouts 1.10
-
-Pane {
-	property string title: qsTr("Verification timed out")
-	ColumnLayout {
-		spacing: 16
-		Text {
-			Layout.maximumWidth: 400
-			Layout.fillHeight: true
-			Layout.fillWidth: true
-			wrapMode: Text.Wrap
-			id: content
-			text: qsTr("Device verification timed out.")
-			color:colors.text
-			verticalAlignment: Text.AlignVCenter
-		}
-		RowLayout {
-			Item {
-				Layout.fillWidth: true
-			}
-			Button {
-				Layout.alignment: Qt.AlignRight
-				text: qsTr("Close")
-
-				onClicked: {
-					deviceVerificationList.remove(tran_id);
-					flow.deleteFlow();
-					dialog.destroy()
-				}
-			}
-		}
-	}
-}
diff --git a/resources/qml/device-verification/VerificationSuccess.qml b/resources/qml/device-verification/VerificationSuccess.qml
deleted file mode 100644
index bc1e64f7..00000000
--- a/resources/qml/device-verification/VerificationSuccess.qml
+++ /dev/null
@@ -1,35 +0,0 @@
-import QtQuick 2.3
-import QtQuick.Controls 2.10
-import QtQuick.Layouts 1.10
-
-Pane {
-	property string title: qsTr("Successful Verification")
-	ColumnLayout {
-		spacing: 16
-		Label {
-			Layout.maximumWidth: 400
-			Layout.fillHeight: true
-			Layout.fillWidth: true
-			wrapMode: Text.Wrap
-			id: content
-			text: qsTr("Verification successful! Both sides verified their devices!")
-			color:colors.text
-			verticalAlignment: Text.AlignVCenter
-		}
-		RowLayout {
-			Item {
-				Layout.fillWidth: true
-			}
-			Button {
-				Layout.alignment: Qt.AlignRight
-				text: qsTr("Close")
-
-				onClicked: {
-					deviceVerificationList.remove(tran_id);
-					if(flow) flow.deleteFlow();
-					dialog.destroy();
-				}
-			}
-		}
-	}
-}
diff --git a/resources/qml/device-verification/Waiting.qml b/resources/qml/device-verification/Waiting.qml
new file mode 100644
index 00000000..f36910e7
--- /dev/null
+++ b/resources/qml/device-verification/Waiting.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+import im.nheko 1.0
+
+Pane {
+	property string title: qsTr("Waiting for other party")
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: switch (flow.state) {
+				case "WaitingForOtherToAccept": return qsTr("Waiting for other side to accept the verification request.")
+				case "WaitingForKeys": return qsTr("Waiting for other side to continue the verification request.")
+				case "WaitingForMac": return qsTr("Waiting for other side to complete the verification request.")
+			}
+
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		BusyIndicator {
+			Layout.alignment: Qt.AlignHCenter
+			palette: color
+		}
+		RowLayout {
+			Button {
+				Layout.alignment: Qt.AlignLeft
+				text: qsTr("Cancel")
+
+				onClicked: { 
+					flow.cancel();
+					dialog.close();
+				}
+			}
+			Item {
+				Layout.fillWidth: true
+			}
+		}
+	}
+}
diff --git a/resources/res.qrc b/resources/res.qrc
index 7ef7ecf9..64e5b084 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -141,16 +141,13 @@
         qml/delegates/Pill.qml
         qml/delegates/Placeholder.qml
         qml/delegates/Reply.qml
-        qml/device-verification/AcceptNewVerificationRequest.qml
-        qml/device-verification/AwaitingVerificationConfirmation.qml
-        qml/device-verification/AwaitingVerificationRequest.qml
+        qml/device-verification/Waiting.qml
         qml/device-verification/DeviceVerification.qml
         qml/device-verification/DigitVerification.qml
         qml/device-verification/EmojiVerification.qml
         qml/device-verification/NewVerificationRequest.qml
-        qml/device-verification/PartnerAborted.qml
-        qml/device-verification/TimedOut.qml
-        qml/device-verification/VerificationSuccess.qml
+        qml/device-verification/Failed.qml
+        qml/device-verification/Success.qml
     
     
         media/ring.ogg
diff --git a/src/ChatPage.h b/src/ChatPage.h
index f363c4fe..c37aa915 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -169,22 +169,22 @@ signals:
         void decryptSidebarChanged();
 
         //! Signals for device verificaiton
-        void recievedDeviceVerificationAccept(
+        void receivedDeviceVerificationAccept(
           const mtx::events::msg::KeyVerificationAccept &message);
-        void recievedDeviceVerificationRequest(
+        void receivedDeviceVerificationRequest(
           const mtx::events::msg::KeyVerificationRequest &message,
           std::string sender);
-        void recievedRoomDeviceVerificationRequest(
+        void receivedRoomDeviceVerificationRequest(
           const mtx::events::RoomEvent &message,
           TimelineModel *model);
-        void recievedDeviceVerificationCancel(
+        void receivedDeviceVerificationCancel(
           const mtx::events::msg::KeyVerificationCancel &message);
-        void recievedDeviceVerificationKey(const mtx::events::msg::KeyVerificationKey &message);
-        void recievedDeviceVerificationMac(const mtx::events::msg::KeyVerificationMac &message);
-        void recievedDeviceVerificationStart(const mtx::events::msg::KeyVerificationStart &message,
+        void receivedDeviceVerificationKey(const mtx::events::msg::KeyVerificationKey &message);
+        void receivedDeviceVerificationMac(const mtx::events::msg::KeyVerificationMac &message);
+        void receivedDeviceVerificationStart(const mtx::events::msg::KeyVerificationStart &message,
                                              std::string sender);
-        void recievedDeviceVerificationReady(const mtx::events::msg::KeyVerificationReady &message);
-        void recievedDeviceVerificationDone(const mtx::events::msg::KeyVerificationDone &message);
+        void receivedDeviceVerificationReady(const mtx::events::msg::KeyVerificationReady &message);
+        void receivedDeviceVerificationDone(const mtx::events::msg::KeyVerificationDone &message);
 
 private slots:
         void showUnreadMessageNotification(int count);
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index 7b367de9..99fd7bed 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -15,8 +15,12 @@ namespace msgs = mtx::events::msg;
 
 DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                                                DeviceVerificationFlow::Type flow_type,
-                                               TimelineModel *model)
-  : type(flow_type)
+                                               TimelineModel *model,
+                                               QString userID,
+                                               QString deviceId_)
+  : sender(false)
+  , type(flow_type)
+  , deviceId(deviceId_)
   , model_(model)
 {
         timeout = new QTimer(this);
@@ -24,6 +28,30 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
         this->sas           = olm::client()->sas_init();
         this->isMacVerified = false;
 
+        auto user_id   = userID.toStdString();
+        this->toClient = mtx::identifiers::parse(user_id);
+        ChatPage::instance()->query_keys(
+          user_id, [user_id, this](const UserKeyCache &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;
+                  }
+
+                  if (!this->deviceId.isEmpty() &&
+                      (res.device_keys.find(deviceId.toStdString()) == res.device_keys.end())) {
+                          nhlog::net()->warn("no devices retrieved {}", user_id);
+                          return;
+                  }
+
+                  for (const auto &[algorithm, key] :
+                       res.device_keys.at(deviceId.toStdString()).keys) {
+                          // TODO: Verify Signatures
+                          this->device_keys[algorithm] = key;
+                  }
+          });
+
         if (model) {
                 connect(this->model_,
                         &TimelineModel::updateFlowEventId,
@@ -36,64 +64,15 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
         }
 
         connect(timeout, &QTimer::timeout, this, [this]() {
-                emit timedout();
                 this->cancelVerification(DeviceVerificationFlow::Error::Timeout);
-                this->deleteLater();
         });
 
-        connect(this, &DeviceVerificationFlow::deleteFlow, this, [this]() { this->deleteLater(); });
-
-        connect(
-          ChatPage::instance(),
-          &ChatPage::recievedDeviceVerificationStart,
-          this,
-          [this](const mtx::events::msg::KeyVerificationStart &msg, std::string) {
-                  if (msg.transaction_id.has_value()) {
-                          if (msg.transaction_id.value() != this->transaction_id)
-                                  return;
-                  } else if (msg.relates_to.has_value()) {
-                          if (msg.relates_to.value().event_id != this->relation.event_id)
-                                  return;
-                  }
-                  if ((std::find(msg.key_agreement_protocols.begin(),
-                                 msg.key_agreement_protocols.end(),
-                                 "curve25519-hkdf-sha256") != msg.key_agreement_protocols.end()) &&
-                      (std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
-                       msg.hashes.end()) &&
-                      (std::find(msg.message_authentication_codes.begin(),
-                                 msg.message_authentication_codes.end(),
-                                 "hkdf-hmac-sha256") != msg.message_authentication_codes.end())) {
-                          if (std::find(msg.short_authentication_string.begin(),
-                                        msg.short_authentication_string.end(),
-                                        mtx::events::msg::SASMethods::Decimal) !=
-                              msg.short_authentication_string.end()) {
-                                  this->method = DeviceVerificationFlow::Method::Emoji;
-                          } else if (std::find(msg.short_authentication_string.begin(),
-                                               msg.short_authentication_string.end(),
-                                               mtx::events::msg::SASMethods::Emoji) !=
-                                     msg.short_authentication_string.end()) {
-                                  this->method = DeviceVerificationFlow::Method::Decimal;
-                          } else {
-                                  this->cancelVerification(
-                                    DeviceVerificationFlow::Error::UnknownMethod);
-                                  return;
-                          }
-                          if (!sender)
-                                  this->canonical_json = nlohmann::json(msg);
-                          else {
-                                  if (utils::localUser().toStdString() <
-                                      this->toClient.to_string()) {
-                                          this->canonical_json = nlohmann::json(msg);
-                                  }
-                          }
-                          this->acceptVerificationRequest();
-                  } else {
-                          this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
-                  }
-          });
-
         connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationAccept,
+                &ChatPage::receivedDeviceVerificationStart,
+                this,
+                &DeviceVerificationFlow::handleStartMessage);
+        connect(ChatPage::instance(),
+                &ChatPage::receivedDeviceVerificationAccept,
                 this,
                 [this](const mtx::events::msg::KeyVerificationAccept &msg) {
                         if (msg.transaction_id.has_value()) {
@@ -111,9 +90,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                                               msg.short_authentication_string.end(),
                                               mtx::events::msg::SASMethods::Emoji) !=
                                     msg.short_authentication_string.end()) {
-                                        this->method = DeviceVerificationFlow::Method::Emoji;
+                                        this->method = mtx::events::msg::SASMethods::Emoji;
                                 } else {
-                                        this->method = DeviceVerificationFlow::Method::Decimal;
+                                        this->method = mtx::events::msg::SASMethods::Decimal;
                                 }
                                 this->mac_method = msg.message_authentication_code;
                                 this->sendVerificationKey();
@@ -124,7 +103,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                 });
 
         connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationCancel,
+                &ChatPage::receivedDeviceVerificationCancel,
                 this,
                 [this](const mtx::events::msg::KeyVerificationCancel &msg) {
                         if (msg.transaction_id.has_value()) {
@@ -134,12 +113,13 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                                 if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
                         }
-                        this->deleteLater();
-                        emit verificationCanceled();
+                        error_ = User;
+                        emit errorChanged();
+                        setState(Failed);
                 });
 
         connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationKey,
+                &ChatPage::receivedDeviceVerificationKey,
                 this,
                 [this](const mtx::events::msg::KeyVerificationKey &msg) {
                         if (msg.transaction_id.has_value()) {
@@ -149,6 +129,19 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                                 if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
                         }
+
+                        if (sender) {
+                                if (state_ != WaitingForOtherToAccept) {
+                                        this->cancelVerification(OutOfOrder);
+                                        return;
+                                }
+                        } else {
+                                if (state_ != WaitingForKeys) {
+                                        this->cancelVerification(OutOfOrder);
+                                        return;
+                                }
+                        }
+
                         this->sas->set_their_key(msg.key);
                         std::string info;
                         if (this->sender == true) {
@@ -166,31 +159,30 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                                        "|" + this->transaction_id;
                         }
 
-                        if (this->method == DeviceVerificationFlow::Method::Emoji) {
-                                std::cout << info << std::endl;
-                                this->sasList = this->sas->generate_bytes_emoji(info);
-                        } else if (this->method == DeviceVerificationFlow::Method::Decimal) {
-                                this->sasList = this->sas->generate_bytes_decimal(info);
-                        }
-
                         if (this->sender == false) {
-                                emit this->verificationRequestAccepted(this->method);
                                 this->sendVerificationKey();
                         } else {
-                                if (this->commitment ==
+                                if (this->commitment !=
                                     mtx::crypto::bin2base64_unpadded(
                                       mtx::crypto::sha256(msg.key + this->canonical_json.dump()))) {
-                                        emit this->verificationRequestAccepted(this->method);
-                                } else {
                                         this->cancelVerification(
                                           DeviceVerificationFlow::Error::MismatchedCommitment);
+                                        return;
                                 }
                         }
+
+                        if (this->method == mtx::events::msg::SASMethods::Emoji) {
+                                this->sasList = this->sas->generate_bytes_emoji(info);
+                                setState(CompareEmoji);
+                        } else if (this->method == mtx::events::msg::SASMethods::Decimal) {
+                                this->sasList = this->sas->generate_bytes_decimal(info);
+                                setState(CompareNumber);
+                        }
                 });
 
         connect(
           ChatPage::instance(),
-          &ChatPage::recievedDeviceVerificationMac,
+          &ChatPage::receivedDeviceVerificationMac,
           this,
           [this](const mtx::events::msg::KeyVerificationMac &msg) {
                   if (msg.transaction_id.has_value()) {
@@ -222,26 +214,22 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                   }
                   key_string = key_string.substr(0, key_string.length() - 1);
                   if (msg.keys == this->sas->calculate_mac(key_string, info + "KEY_IDS")) {
-                          // uncomment this in future to be compatible with the
-                          // MSC2366 this->sendVerificationDone(); and remove the
-                          // below line
-                          if (this->isMacVerified == true) {
-                                  this->acceptDevice();
-                          } else
-                                  this->isMacVerified = true;
+                          this->isMacVerified = true;
+                          this->acceptDevice();
                   } else {
                           this->cancelVerification(DeviceVerificationFlow::Error::KeyMismatch);
                   }
           });
 
         connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationReady,
+                &ChatPage::receivedDeviceVerificationReady,
                 this,
                 [this](const mtx::events::msg::KeyVerificationReady &msg) {
                         if (!sender) {
                                 if (msg.from_device != http::client()->device_id()) {
-                                        this->deleteLater();
-                                        emit verificationCanceled();
+                                        error_ = User;
+                                        emit errorChanged();
+                                        setState(Failed);
                                 }
 
                                 return;
@@ -261,7 +249,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                 });
 
         connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationDone,
+                &ChatPage::receivedDeviceVerificationDone,
                 this,
                 [this](const mtx::events::msg::KeyVerificationDone &msg) {
                         if (msg.transaction_id.has_value()) {
@@ -271,22 +259,85 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                                 if (msg.relates_to.value().event_id != this->relation.event_id)
                                         return;
                         }
-                        this->acceptDevice();
+                        nhlog::ui()->info("Flow done on other side");
                 });
 
         timeout->start(TIMEOUT);
 }
 
 QString
-DeviceVerificationFlow::getTransactionId()
+DeviceVerificationFlow::state()
 {
-        return QString::fromStdString(this->transaction_id);
+        switch (state_) {
+        case PromptStartVerification:
+                return "PromptStartVerification";
+        case CompareEmoji:
+                return "CompareEmoji";
+        case CompareNumber:
+                return "CompareNumber";
+        case WaitingForKeys:
+                return "WaitingForKeys";
+        case WaitingForOtherToAccept:
+                return "WaitingForOtherToAccept";
+        case WaitingForMac:
+                return "WaitingForMac";
+        case Success:
+                return "Success";
+        case Failed:
+                return "Failed";
+        default:
+                return "";
+        }
+}
+
+void
+DeviceVerificationFlow::next()
+{
+        if (sender) {
+                switch (state_) {
+                case PromptStartVerification:
+                        sendVerificationRequest();
+                        break;
+                case CompareEmoji:
+                case CompareNumber:
+                        sendVerificationMac();
+                        break;
+                case WaitingForKeys:
+                case WaitingForOtherToAccept:
+                case WaitingForMac:
+                case Success:
+                case Failed:
+                        nhlog::db()->error("verification: Invalid state transition!");
+                        break;
+                }
+        } else {
+                switch (state_) {
+                case PromptStartVerification:
+                        if (canonical_json.is_null())
+                                sendVerificationReady();
+                        else // legacy path without request and ready
+                                acceptVerificationRequest();
+                        break;
+                case CompareEmoji:
+                        [[fallthrough]];
+                case CompareNumber:
+                        sendVerificationMac();
+                        break;
+                case WaitingForKeys:
+                case WaitingForOtherToAccept:
+                case WaitingForMac:
+                case Success:
+                case Failed:
+                        nhlog::db()->error("verification: Invalid state transition!");
+                        break;
+                }
+        }
 }
 
 QString
 DeviceVerificationFlow::getUserId()
 {
-        return this->userId;
+        return QString::fromStdString(this->toClient.to_string());
 }
 
 QString
@@ -295,18 +346,6 @@ DeviceVerificationFlow::getDeviceId()
         return this->deviceId;
 }
 
-DeviceVerificationFlow::Method
-DeviceVerificationFlow::getMethod()
-{
-        return this->method;
-}
-
-DeviceVerificationFlow::Type
-DeviceVerificationFlow::getType()
-{
-        return this->type;
-}
-
 bool
 DeviceVerificationFlow::getSender()
 {
@@ -320,56 +359,58 @@ DeviceVerificationFlow::getSasList()
 }
 
 void
-DeviceVerificationFlow::setTransactionId(QString transaction_id_)
-{
-        this->transaction_id = transaction_id_.toStdString();
-}
-
-void
-DeviceVerificationFlow::setUserId(QString userID)
-{
-        this->userId   = userID;
-        this->toClient = mtx::identifiers::parse(userID.toStdString());
-
-        auto user_id = userID.toStdString();
-        ChatPage::instance()->query_keys(
-          user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
-                  this->callback_fn(res, err, user_id);
-          });
-}
-
-void
-DeviceVerificationFlow::setDeviceId(QString deviceID)
-{
-        this->deviceId = deviceID;
-}
-
-void
-DeviceVerificationFlow::setMethod(DeviceVerificationFlow::Method method_)
-{
-        this->method = method_;
-}
-
-void
-DeviceVerificationFlow::setType(Type type_)
+DeviceVerificationFlow::setEventId(std::string event_id_)
 {
-        this->type = type_;
+        this->relation.rel_type = mtx::common::RelationType::Reference;
+        this->relation.event_id = event_id_;
+        this->transaction_id    = event_id_;
 }
 
 void
-DeviceVerificationFlow::setSender(bool sender_)
+DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificationStart &msg,
+                                           std::string)
 {
-        this->sender = sender_;
-        if (this->sender)
-                this->transaction_id = http::client()->generate_txn_id();
-}
+        if (msg.transaction_id.has_value()) {
+                if (msg.transaction_id.value() != this->transaction_id)
+                        return;
+        } else if (msg.relates_to.has_value()) {
+                if (msg.relates_to.value().event_id != this->relation.event_id)
+                        return;
+        }
+        if ((std::find(msg.key_agreement_protocols.begin(),
+                       msg.key_agreement_protocols.end(),
+                       "curve25519-hkdf-sha256") != msg.key_agreement_protocols.end()) &&
+            (std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") != msg.hashes.end()) &&
+            (std::find(msg.message_authentication_codes.begin(),
+                       msg.message_authentication_codes.end(),
+                       "hkdf-hmac-sha256") != msg.message_authentication_codes.end())) {
+                if (std::find(msg.short_authentication_string.begin(),
+                              msg.short_authentication_string.end(),
+                              mtx::events::msg::SASMethods::Emoji) !=
+                    msg.short_authentication_string.end()) {
+                        this->method = mtx::events::msg::SASMethods::Emoji;
+                } else if (std::find(msg.short_authentication_string.begin(),
+                                     msg.short_authentication_string.end(),
+                                     mtx::events::msg::SASMethods::Decimal) !=
+                           msg.short_authentication_string.end()) {
+                        this->method = mtx::events::msg::SASMethods::Decimal;
+                } else {
+                        this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
+                        return;
+                }
+                if (!sender)
+                        this->canonical_json = nlohmann::json(msg);
+                else {
+                        if (utils::localUser().toStdString() < this->toClient.to_string()) {
+                                this->canonical_json = nlohmann::json(msg);
+                        }
+                }
 
-void
-DeviceVerificationFlow::setEventId(std::string event_id_)
-{
-        this->relation.rel_type = mtx::common::RelationType::Reference;
-        this->relation.event_id = event_id_;
-        this->transaction_id    = event_id_;
+                if (state_ != PromptStartVerification)
+                        this->acceptVerificationRequest();
+        } else {
+                this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
+        }
 }
 
 //! accepts a verification
@@ -382,30 +423,15 @@ DeviceVerificationFlow::acceptVerificationRequest()
         req.key_agreement_protocol      = "curve25519-hkdf-sha256";
         req.hash                        = "sha256";
         req.message_authentication_code = "hkdf-hmac-sha256";
-        if (this->method == DeviceVerificationFlow::Method::Emoji)
+        if (this->method == mtx::events::msg::SASMethods::Emoji)
                 req.short_authentication_string = {mtx::events::msg::SASMethods::Emoji};
-        else if (this->method == DeviceVerificationFlow::Method::Decimal)
+        else if (this->method == mtx::events::msg::SASMethods::Decimal)
                 req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal};
         req.commitment = mtx::crypto::bin2base64_unpadded(
           mtx::crypto::sha256(this->sas->public_key() + this->canonical_json.dump()));
 
-        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
-                mtx::requests::ToDeviceMessages body;
-                req.transaction_id = this->transaction_id;
-
-                body[this->toClient][this->deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to accept verification request: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-                  });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.relates_to = this->relation;
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationAccept);
-        }
+        send(req);
+        setState(WaitingForKeys);
 }
 //! responds verification request
 void
@@ -416,23 +442,8 @@ DeviceVerificationFlow::sendVerificationReady()
         req.from_device = http::client()->device_id();
         req.methods     = {mtx::events::msg::VerificationMethods::SASv1};
 
-        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
-                req.transaction_id = this->transaction_id;
-                mtx::requests::ToDeviceMessages body;
-
-                body[this->toClient][this->deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to send verification ready: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-                  });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.relates_to = this->relation;
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationReady);
-        }
+        send(req);
+        setState(WaitingForKeys);
 }
 //! accepts a verification
 void
@@ -440,23 +451,7 @@ DeviceVerificationFlow::sendVerificationDone()
 {
         mtx::events::msg::KeyVerificationDone req;
 
-        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
-                mtx::requests::ToDeviceMessages body;
-                req.transaction_id = this->transaction_id;
-
-                body[this->toClient][this->deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to send verification done: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-                  });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.relates_to = this->relation;
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationDone);
-        }
+        send(req);
 }
 //! starts the verification flow
 void
@@ -474,22 +469,14 @@ DeviceVerificationFlow::startVerificationRequest()
 
         if (this->type == DeviceVerificationFlow::Type::ToDevice) {
                 mtx::requests::ToDeviceMessages body;
-                req.transaction_id                                 = this->transaction_id;
-                this->canonical_json                               = nlohmann::json(req);
-                body[this->toClient][this->deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [body](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to start verification request: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-                  });
+                req.transaction_id   = this->transaction_id;
+                this->canonical_json = nlohmann::json(req);
         } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to       = this->relation;
                 this->canonical_json = nlohmann::json(req);
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationStart);
         }
+        send(req);
+        setState(WaitingForOtherToAccept);
 }
 //! sends a verification request
 void
@@ -503,28 +490,18 @@ DeviceVerificationFlow::sendVerificationRequest()
         if (this->type == DeviceVerificationFlow::Type::ToDevice) {
                 QDateTime currentTime = QDateTime::currentDateTimeUtc();
 
-                req.transaction_id = this->transaction_id;
-                req.timestamp      = (uint64_t)currentTime.toMSecsSinceEpoch();
-
-                mtx::requests::ToDeviceMessages body;
+                req.timestamp = (uint64_t)currentTime.toMSecsSinceEpoch();
 
-                body[this->toClient][this->deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to send verification request: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-                  });
         } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.to      = this->userId.toStdString();
+                req.to      = this->toClient.to_string();
                 req.msgtype = "m.key.verification.request";
                 req.body = "User is requesting to verify keys with you. However, your client does "
                            "not support this method, so you will need to use the legacy method of "
                            "key verification.";
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationRequest);
         }
+
+        send(req);
+        setState(WaitingForOtherToAccept);
 }
 //! cancels a verification flow
 void
@@ -534,7 +511,7 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
 
         if (error_code == DeviceVerificationFlow::Error::UnknownMethod) {
                 req.code   = "m.unknown_method";
-                req.reason = "unknown method recieved";
+                req.reason = "unknown method received";
         } else if (error_code == DeviceVerificationFlow::Error::MismatchedCommitment) {
                 req.code   = "m.mismatched_commitment";
                 req.reason = "commitment didn't match";
@@ -550,42 +527,16 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
         } else if (error_code == DeviceVerificationFlow::Error::User) {
                 req.code   = "m.user";
                 req.reason = "user cancelled the verification";
+        } else if (error_code == DeviceVerificationFlow::Error::OutOfOrder) {
+                req.code   = "m.unexpected_message";
+                req.reason = "received messages out of order";
         }
 
-        emit this->verificationCanceled();
+        this->error_ = error_code;
+        emit errorChanged();
+        this->setState(Failed);
 
-        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
-                req.transaction_id = this->transaction_id;
-                mtx::requests::ToDeviceMessages body;
-
-                body[this->toClient][deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [this](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to cancel verification request: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-
-                          this->deleteLater();
-                  });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.relates_to = this->relation;
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationCancel);
-                this->deleteLater();
-        }
-
-        // TODO : Handle Blocking user better
-        // 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()}});
-        //     }
+        send(req);
 }
 //! sends the verification key
 void
@@ -595,23 +546,7 @@ DeviceVerificationFlow::sendVerificationKey()
 
         req.key = this->sas->public_key();
 
-        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
-                mtx::requests::ToDeviceMessages body;
-                req.transaction_id = this->transaction_id;
-
-                body[this->toClient][deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to send verification key: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-                  });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.relates_to = this->relation;
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationKey);
-        }
+        send(req);
 }
 
 mtx::events::msg::KeyVerificationMac
@@ -660,68 +595,102 @@ DeviceVerificationFlow::sendVerificationMac()
                                this->transaction_id,
                                key_list);
 
-        if (this->type == DeviceVerificationFlow::Type::ToDevice) {
-                mtx::requests::ToDeviceMessages body;
-                req.transaction_id                           = this->transaction_id;
-                body[this->toClient][deviceId.toStdString()] = req;
-
-                http::client()->send_to_device(
-                  this->transaction_id, body, [this](mtx::http::RequestErr err) {
-                          if (err)
-                                  nhlog::net()->warn("failed to send verification MAC: {} {}",
-                                                     err->matrix_error.error,
-                                                     static_cast(err->status_code));
-
-                          if (this->isMacVerified == true)
-                                  this->acceptDevice();
-                          else
-                                  this->isMacVerified = true;
-                  });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
-                req.relates_to = this->relation;
-                (model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationMac);
-        }
+        send(req);
+
+        setState(WaitingForMac);
+        acceptDevice();
 }
 //! Completes the verification flow
 void
 DeviceVerificationFlow::acceptDevice()
 {
-        cache::markDeviceVerified(this->userId.toStdString(), this->deviceId.toStdString());
+        if (!isMacVerified) {
+                setState(WaitingForMac);
+        } else if (state_ == WaitingForMac) {
+                cache::markDeviceVerified(this->toClient.to_string(), this->deviceId.toStdString());
+                this->sendVerificationDone();
+                setState(Success);
+        }
+}
+
+void
+DeviceVerificationFlow::unverify()
+{
+        cache::markDeviceUnverified(this->toClient.to_string(), this->deviceId.toStdString());
 
-        emit deviceVerified();
         emit refreshProfile();
-        this->deleteLater();
 }
 
-//! callback function to keep track of devices
-void
-DeviceVerificationFlow::callback_fn(const UserKeyCache &res,
-                                    mtx::http::RequestErr err,
-                                    std::string user_id)
+QSharedPointer
+DeviceVerificationFlow::NewInRoomVerification(QObject *parent_,
+                                              TimelineModel *timelineModel_,
+                                              const mtx::events::msg::KeyVerificationRequest &msg,
+                                              QString other_user_,
+                                              QString event_id_)
 {
-        if (err) {
-                nhlog::net()->warn("failed to query device keys: {},{}",
-                                   err->matrix_error.errcode,
-                                   static_cast(err->status_code));
-                return;
-        }
+        QSharedPointer flow(
+          new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, other_user_, ""));
+
+        flow->event_id = event_id_.toStdString();
 
-        if (res.device_keys.empty() ||
-            (res.device_keys.find(deviceId.toStdString()) == res.device_keys.end())) {
-                nhlog::net()->warn("no devices retrieved {}", user_id);
-                return;
+        if (std::find(msg.methods.begin(),
+                      msg.methods.end(),
+                      mtx::events::msg::VerificationMethods::SASv1) == msg.methods.end()) {
+                flow->cancelVerification(UnknownMethod);
         }
 
-        for (const auto &[algorithm, key] : res.device_keys.at(deviceId.toStdString()).keys) {
-                // TODO: Verify Signatures
-                this->device_keys[algorithm] = key;
+        return flow;
+}
+QSharedPointer
+DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_,
+                                                const mtx::events::msg::KeyVerificationRequest &msg,
+                                                QString other_user_,
+                                                QString txn_id_)
+{
+        QSharedPointer flow(new DeviceVerificationFlow(
+          parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device)));
+        flow->transaction_id = txn_id_.toStdString();
+
+        if (std::find(msg.methods.begin(),
+                      msg.methods.end(),
+                      mtx::events::msg::VerificationMethods::SASv1) == msg.methods.end()) {
+                flow->cancelVerification(UnknownMethod);
         }
+
+        return flow;
 }
+QSharedPointer
+DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_,
+                                                const mtx::events::msg::KeyVerificationStart &msg,
+                                                QString other_user_,
+                                                QString txn_id_)
+{
+        QSharedPointer flow(new DeviceVerificationFlow(
+          parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device)));
+        flow->transaction_id = txn_id_.toStdString();
 
-void
-DeviceVerificationFlow::unverify()
+        flow->handleStartMessage(msg, "");
+
+        return flow;
+}
+QSharedPointer
+DeviceVerificationFlow::InitiateUserVerification(QObject *parent_,
+                                                 TimelineModel *timelineModel_,
+                                                 QString userid)
 {
-        cache::markDeviceUnverified(this->userId.toStdString(), this->deviceId.toStdString());
+        QSharedPointer flow(
+          new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, userid, ""));
+        flow->sender = true;
+        return flow;
+}
+QSharedPointer
+DeviceVerificationFlow::InitiateDeviceVerification(QObject *parent_, QString userid, QString device)
+{
+        QSharedPointer flow(
+          new DeviceVerificationFlow(parent_, Type::ToDevice, nullptr, userid, device));
 
-        emit refreshProfile();
+        flow->sender         = true;
+        flow->transaction_id = http::client()->generate_txn_id();
+
+        return flow;
 }
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index de7a4567..1fe3919b 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -5,41 +5,84 @@
 #include 
 
 #include "CacheCryptoStructs.h"
+#include "Logging.h"
 #include "MatrixClient.h"
 #include "Olm.h"
+#include "timeline/TimelineModel.h"
 
 class QTimer;
 
 using sas_ptr = std::unique_ptr;
 
-class TimelineModel;
-
+// clang-format off
+/*
+ * Stolen from fluffy chat :D
+ *
+ *      State         |   +-------------+                    +-----------+                                  |
+ *                    |   | AliceDevice |                    | BobDevice |                                  |
+ *                    |   | (sender)    |                    |           |                                  |
+ *                    |   +-------------+                    +-----------+                                  |
+ * promptStartVerify  |         |                                 |                                         |
+ *                    |      o  | (m.key.verification.request)    |                                         |
+ *                    |      p  |-------------------------------->| (ASK FOR VERIFICATION REQUEST)          |
+ * waitForOtherAccept |      t  |                                 |                                         | promptStartVerify
+ * &&                 |      i  |      (m.key.verification.ready) |                                         |
+ * no commitment      |      o  |<--------------------------------|                                         |
+ * &&                 |      n  |                                 |                                         |
+ * no canonical_json  |      a  |      (m.key.verification.start) |                                         | waitingForKeys
+ *                    |      l  |<--------------------------------| Not sending to prevent the glare resolve| && no commitment
+ *                    |         |                                 |                                         | && no canonical_json
+ *                    |         | m.key.verification.start        |                                         |
+ * waitForOtherAccept |         |-------------------------------->| (IF NOT ALREADY ASKED,                  |
+ * &&                 |         |                                 |  ASK FOR VERIFICATION REQUEST)          | promptStartVerify, if not accepted
+ * canonical_json     |         |       m.key.verification.accept |                                         |
+ *                    |         |<--------------------------------|                                         |
+ * waitForOtherAccept |         |                                 |                                         | waitingForKeys
+ * &&                 |         | m.key.verification.key          |                                         | && canonical_json
+ * commitment         |         |-------------------------------->|                                         | && commitment
+ *                    |         |                                 |                                         |
+ *                    |         |          m.key.verification.key |                                         |
+ *                    |         |<--------------------------------|                                         |
+ * compareEmoji/Number|         |                                 |                                         | compareEmoji/Number
+ *                    |         |     COMPARE EMOJI / NUMBERS     |                                         |
+ *                    |         |                                 |                                         |
+ * waitingForMac      |         |     m.key.verification.mac      |                                         | waitingForMac
+ *                    | success |<------------------------------->|  success                                |
+ *                    |         |                                 |                                         |
+ * success/fail       |         |         m.key.verification.done |                                         | success/fail
+ *                    |         |<------------------------------->|                                         |
+ */
+// clang-format on
 class DeviceVerificationFlow : public QObject
 {
         Q_OBJECT
         // Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
-        Q_PROPERTY(QString tranId READ getTransactionId WRITE setTransactionId)
-        Q_PROPERTY(bool sender READ getSender WRITE setSender)
-        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(QString state READ state NOTIFY stateChanged)
+        Q_PROPERTY(Error error READ error CONSTANT)
+        Q_PROPERTY(QString userId READ getUserId CONSTANT)
+        Q_PROPERTY(QString deviceId READ getDeviceId CONSTANT)
+        Q_PROPERTY(bool sender READ getSender CONSTANT)
         Q_PROPERTY(std::vector sasList READ getSasList CONSTANT)
 
 public:
-        enum Type
+        enum State
         {
-                ToDevice,
-                RoomMsg
+                PromptStartVerification,
+                WaitingForOtherToAccept,
+                WaitingForKeys,
+                CompareEmoji,
+                CompareNumber,
+                WaitingForMac,
+                Success,
+                Failed,
         };
-        Q_ENUM(Type)
+        Q_ENUM(State)
 
-        enum Method
+        enum Type
         {
-                Decimal,
-                Emoji
+                ToDevice,
+                RoomMsg
         };
-        Q_ENUM(Method)
 
         enum Error
         {
@@ -48,36 +91,75 @@ public:
                 MismatchedSAS,
                 KeyMismatch,
                 Timeout,
-                User
+                User,
+                OutOfOrder,
         };
         Q_ENUM(Error)
 
-        DeviceVerificationFlow(
-          QObject *parent              = nullptr,
-          DeviceVerificationFlow::Type = DeviceVerificationFlow::Type::ToDevice,
-          TimelineModel *model         = nullptr);
+        static QSharedPointer NewInRoomVerification(
+          QObject *parent_,
+          TimelineModel *timelineModel_,
+          const mtx::events::msg::KeyVerificationRequest &msg,
+          QString other_user_,
+          QString event_id_);
+        static QSharedPointer NewToDeviceVerification(
+          QObject *parent_,
+          const mtx::events::msg::KeyVerificationRequest &msg,
+          QString other_user_,
+          QString txn_id_);
+        static QSharedPointer NewToDeviceVerification(
+          QObject *parent_,
+          const mtx::events::msg::KeyVerificationStart &msg,
+          QString other_user_,
+          QString txn_id_);
+        static QSharedPointer
+        InitiateUserVerification(QObject *parent_, TimelineModel *timelineModel_, QString userid);
+        static QSharedPointer InitiateDeviceVerification(QObject *parent,
+                                                                                 QString userid,
+                                                                                 QString device);
+
         // getters
-        QString getTransactionId();
+        QString state();
+        Error error() { return error_; }
         QString getUserId();
         QString getDeviceId();
-        Method getMethod();
-        Type getType();
-        std::vector getSasList();
         bool getSender();
+        std::vector getSasList();
+        QString transactionId() { return QString::fromStdString(this->transaction_id); }
         // setters
-        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 UserKeyCache &res, mtx::http::RequestErr err, std::string user_id);
 
-        nlohmann::json canonical_json;
-
 public slots:
+        //! unverifies a device
+        void unverify();
+        //! Continues the flow
+        void next();
+        //! Cancel the flow
+        void cancel() { cancelVerification(User); }
+
+signals:
+        void refreshProfile();
+        void stateChanged();
+        void errorChanged();
+
+private:
+        DeviceVerificationFlow(QObject *,
+                               DeviceVerificationFlow::Type flow_type,
+                               TimelineModel *model,
+                               QString userID,
+                               QString deviceId_);
+        void setState(State state)
+        {
+                if (state != state_) {
+                        state_ = state;
+                        emit stateChanged();
+                }
+        }
+
+        void handleStartMessage(const mtx::events::msg::KeyVerificationStart &msg, std::string);
         //! sends a verification request
         void sendVerificationRequest();
         //! accepts a verification request
@@ -96,37 +178,60 @@ 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();
-        void deleteFlow();
+        // for to_device messages
+        std::string transaction_id;
+        // for room messages
+        std::optional room_id;
+        std::optional event_id;
 
-private:
-        // general
-        QString userId;
-        QString deviceId;
-        Method method = Method::Emoji;
-        Type type;
         bool sender;
-        QTimer *timeout = nullptr;
+        Type type;
+        mtx::identifiers::User toClient;
+        QString deviceId;
+
+        mtx::events::msg::SASMethods method = mtx::events::msg::SASMethods::Emoji;
+        QTimer *timeout                     = nullptr;
         sas_ptr sas;
-        bool isMacVerified = false;
         std::string mac_method;
         std::string commitment;
-        mtx::identifiers::User toClient;
+        nlohmann::json canonical_json;
+
         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;
         TimelineModel *model_;
         mtx::common::RelatesTo relation;
+
+        State state_ = PromptStartVerification;
+        Error error_;
+
+        bool isMacVerified = false;
+
+        template
+        void send(T msg)
+        {
+                if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                        mtx::requests::ToDeviceMessages body;
+                        msg.transaction_id                           = this->transaction_id;
+                        body[this->toClient][deviceId.toStdString()] = msg;
+
+                        http::client()->send_to_device(
+                          this->transaction_id, body, [this](mtx::http::RequestErr err) {
+                                  if (err)
+                                          nhlog::net()->warn(
+                                            "failed to send verification to_device message: {} {}",
+                                            err->matrix_error.error,
+                                            static_cast(err->status_code));
+                          });
+                } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
+                        if constexpr (!std::is_same_v)
+                                msg.relates_to = this->relation;
+                        (model_)->sendMessageEvent(msg, mtx::events::to_device_content_to_type);
+                }
+
+                nhlog::net()->debug(
+                  "Sent verification step: {} in state: {}",
+                  mtx::events::to_string(mtx::events::to_device_content_to_type),
+                  state().toStdString());
+        }
 };
diff --git a/src/Olm.cpp b/src/Olm.cpp
index 8219ce4c..f4cb2209 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -80,40 +80,40 @@ handle_to_device_messages(const std::vector>(msg);
-                        ChatPage::instance()->recievedDeviceVerificationAccept(message.content);
+                        ChatPage::instance()->receivedDeviceVerificationAccept(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationRequest)) {
                         auto message = std::get<
                           mtx::events::DeviceEvent>(msg);
-                        ChatPage::instance()->recievedDeviceVerificationRequest(message.content,
+                        ChatPage::instance()->receivedDeviceVerificationRequest(message.content,
                                                                                 message.sender);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationCancel)) {
                         auto message = std::get<
                           mtx::events::DeviceEvent>(msg);
-                        ChatPage::instance()->recievedDeviceVerificationCancel(message.content);
+                        ChatPage::instance()->receivedDeviceVerificationCancel(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationKey)) {
                         auto message =
                           std::get>(
                             msg);
-                        ChatPage::instance()->recievedDeviceVerificationKey(message.content);
+                        ChatPage::instance()->receivedDeviceVerificationKey(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationMac)) {
                         auto message =
                           std::get>(
                             msg);
-                        ChatPage::instance()->recievedDeviceVerificationMac(message.content);
+                        ChatPage::instance()->receivedDeviceVerificationMac(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationStart)) {
                         auto message = std::get<
                           mtx::events::DeviceEvent>(msg);
-                        ChatPage::instance()->recievedDeviceVerificationStart(message.content,
+                        ChatPage::instance()->receivedDeviceVerificationStart(message.content,
                                                                               message.sender);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationReady)) {
                         auto message = std::get<
                           mtx::events::DeviceEvent>(msg);
-                        ChatPage::instance()->recievedDeviceVerificationReady(message.content);
+                        ChatPage::instance()->receivedDeviceVerificationReady(message.content);
                 } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationDone)) {
                         auto message =
                           std::get>(
                             msg);
-                        ChatPage::instance()->recievedDeviceVerificationDone(message.content);
+                        ChatPage::instance()->receivedDeviceVerificationDone(message.content);
                 } else {
                         nhlog::crypto()->warn("unhandled event: {}", j_msg.dump(2));
                 }
@@ -153,42 +153,42 @@ handle_olm_message(const OlmMessage &msg)
                         std::string msg_type = payload["type"];
 
                         if (msg_type == to_string(mtx::events::EventType::KeyVerificationAccept)) {
-                                ChatPage::instance()->recievedDeviceVerificationAccept(
+                                ChatPage::instance()->receivedDeviceVerificationAccept(
                                   payload["content"]);
                                 return;
                         } else if (msg_type ==
                                    to_string(mtx::events::EventType::KeyVerificationRequest)) {
-                                ChatPage::instance()->recievedDeviceVerificationRequest(
+                                ChatPage::instance()->receivedDeviceVerificationRequest(
                                   payload["content"], payload["sender"]);
                                 return;
                         } else if (msg_type ==
                                    to_string(mtx::events::EventType::KeyVerificationCancel)) {
-                                ChatPage::instance()->recievedDeviceVerificationCancel(
+                                ChatPage::instance()->receivedDeviceVerificationCancel(
                                   payload["content"]);
                                 return;
                         } else if (msg_type ==
                                    to_string(mtx::events::EventType::KeyVerificationKey)) {
-                                ChatPage::instance()->recievedDeviceVerificationKey(
+                                ChatPage::instance()->receivedDeviceVerificationKey(
                                   payload["content"]);
                                 return;
                         } else if (msg_type ==
                                    to_string(mtx::events::EventType::KeyVerificationMac)) {
-                                ChatPage::instance()->recievedDeviceVerificationMac(
+                                ChatPage::instance()->receivedDeviceVerificationMac(
                                   payload["content"]);
                                 return;
                         } else if (msg_type ==
                                    to_string(mtx::events::EventType::KeyVerificationStart)) {
-                                ChatPage::instance()->recievedDeviceVerificationStart(
+                                ChatPage::instance()->receivedDeviceVerificationStart(
                                   payload["content"], payload["sender"]);
                                 return;
                         } else if (msg_type ==
                                    to_string(mtx::events::EventType::KeyVerificationReady)) {
-                                ChatPage::instance()->recievedDeviceVerificationReady(
+                                ChatPage::instance()->receivedDeviceVerificationReady(
                                   payload["content"]);
                                 return;
                         } else if (msg_type ==
                                    to_string(mtx::events::EventType::KeyVerificationDone)) {
-                                ChatPage::instance()->recievedDeviceVerificationDone(
+                                ChatPage::instance()->receivedDeviceVerificationDone(
                                   payload["content"]);
                                 return;
                         } else if (msg_type == to_string(mtx::events::EventType::RoomKey)) {
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 29b3c239..dc92a37f 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -299,7 +299,7 @@ EventStore::handleSync(const mtx::responses::Timeline &events)
                                       mtx::events::msg::KeyVerificationReady>>(d_event)) {
                                         auto msg = std::get_if>(d_event);
-                                        ChatPage::instance()->recievedDeviceVerificationReady(
+                                        ChatPage::instance()->receivedDeviceVerificationReady(
                                           msg->content);
                                 }
                         }
@@ -328,43 +328,43 @@ EventStore::handle_room_verification(mtx::events::collections::TimelineEvents ev
                 auto msg =
                   std::get>(event);
                 last_verification_cancel_event = msg;
-                ChatPage::instance()->recievedDeviceVerificationCancel(msg.content);
+                ChatPage::instance()->receivedDeviceVerificationCancel(msg.content);
                 return;
         } else if (std::get_if>(
                      &event)) {
                 auto msg =
                   std::get>(event);
-                ChatPage::instance()->recievedDeviceVerificationAccept(msg.content);
+                ChatPage::instance()->receivedDeviceVerificationAccept(msg.content);
                 return;
         } else if (std::get_if>(
                      &event)) {
                 auto msg =
                   std::get>(event);
-                ChatPage::instance()->recievedDeviceVerificationKey(msg.content);
+                ChatPage::instance()->receivedDeviceVerificationKey(msg.content);
                 return;
         } else if (std::get_if>(
                      &event)) {
                 auto msg =
                   std::get>(event);
-                ChatPage::instance()->recievedDeviceVerificationMac(msg.content);
+                ChatPage::instance()->receivedDeviceVerificationMac(msg.content);
                 return;
         } else if (std::get_if>(
                      &event)) {
                 auto msg =
                   std::get>(event);
-                ChatPage::instance()->recievedDeviceVerificationReady(msg.content);
+                ChatPage::instance()->receivedDeviceVerificationReady(msg.content);
                 return;
         } else if (std::get_if>(
                      &event)) {
                 auto msg =
                   std::get>(event);
-                ChatPage::instance()->recievedDeviceVerificationDone(msg.content);
+                ChatPage::instance()->receivedDeviceVerificationDone(msg.content);
                 return;
         } else if (std::get_if>(
                      &event)) {
                 auto msg =
                   std::get>(event);
-                ChatPage::instance()->recievedDeviceVerificationStart(msg.content, msg.sender);
+                ChatPage::instance()->receivedDeviceVerificationStart(msg.content, msg.sender);
                 return;
         }
 }
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 5e8952fc..e8d381df 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -254,7 +254,7 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
                 &EventStore::startDMVerification,
                 this,
                 [this](mtx::events::RoomEvent msg) {
-                        ChatPage::instance()->recievedRoomDeviceVerificationRequest(msg, this);
+                        ChatPage::instance()->receivedRoomDeviceVerificationRequest(msg, this);
                 });
         connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
                 this->updateFlowEventId(event_id);
@@ -793,7 +793,7 @@ TimelineModel::viewDecryptedRawMessage(QString id) const
 void
 TimelineModel::openUserProfile(QString userid)
 {
-        emit openProfile(new UserProfile(room_id_, userid, this));
+        emit openProfile(new UserProfile(room_id_, userid, manager_, this));
 }
 
 void
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 03dd4773..250cd5f0 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -28,22 +28,6 @@ Q_DECLARE_METATYPE(std::vector)
 
 namespace msgs = mtx::events::msg;
 
-void
-DeviceVerificationList::add(QString tran_id)
-{
-        this->deviceVerificationList.push_back(tran_id);
-}
-void
-DeviceVerificationList::remove(QString tran_id)
-{
-        this->deviceVerificationList.removeOne(tran_id);
-}
-bool
-DeviceVerificationList::exist(QString tran_id)
-{
-        return this->deviceVerificationList.contains(tran_id);
-}
-
 void
 TimelineViewManager::updateEncryptedDescriptions()
 {
@@ -134,7 +118,8 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
 
         qmlRegisterType("im.nheko", 1, 0, "DelegateChoice");
         qmlRegisterType("im.nheko", 1, 0, "DelegateChooser");
-        qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow");
+        qmlRegisterUncreatableType(
+          "im.nheko", 1, 0, "DeviceVerificationFlow", "Can't create verification flow from QML!");
         qmlRegisterUncreatableType(
           "im.nheko",
           1,
@@ -163,7 +148,6 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
                                          0,
                                          "EmojiCategory",
                                          "Error: Only enums");
-        this->dvList = new DeviceVerificationList;
 
 #ifdef USE_QUICK_VIEW
         view      = new QQuickView();
@@ -183,7 +167,6 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
         });
 #endif
         container->setMinimumSize(200, 200);
-        view->rootContext()->setContextProperty("deviceVerificationList", this->dvList);
         updateColorPalette();
         view->engine()->addImageProvider("MxcImage", imgProvider);
         view->engine()->addImageProvider("colorimage", colorImgProvider);
@@ -197,102 +180,55 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
                 &TimelineViewManager::updateEncryptedDescriptions);
         connect(
           dynamic_cast(parent),
-          &ChatPage::recievedRoomDeviceVerificationRequest,
+          &ChatPage::receivedRoomDeviceVerificationRequest,
           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, model);
-                          if (std::find(message.content.methods.begin(),
-                                        message.content.methods.end(),
-                                        mtx::events::msg::VerificationMethods::SASv1) !=
-                              message.content.methods.end()) {
-                                  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) {
-                  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()) {
-                                  emit newDeviceVerificationRequest(
-                                    std::move(flow),
-                                    QString::fromStdString(msg.transaction_id.value()),
-                                    QString::fromStdString(sender),
-                                    QString::fromStdString(msg.from_device));
-                          } else {
-                                  flow->cancelVerification(
-                                    DeviceVerificationFlow::Error::UnknownMethod);
-                          }
-                  }
-          });
-        connect(
-          dynamic_cast(parent),
-          &ChatPage::recievedDeviceVerificationStart,
-          this,
-          [this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) {
-                  if (msg.transaction_id.has_value()) {
-                          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") !=
-                                       msg.key_agreement_protocols.end()) &&
-                                      (std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
-                                       msg.hashes.end()) &&
-                                      (std::find(msg.message_authentication_codes.begin(),
-                                                 msg.message_authentication_codes.end(),
-                                                 "hmac-sha256") !=
-                                       msg.message_authentication_codes.end())) {
-                                          if (std::find(msg.short_authentication_string.begin(),
-                                                        msg.short_authentication_string.end(),
-                                                        mtx::events::msg::SASMethods::Emoji) !=
-                                              msg.short_authentication_string.end()) {
-                                                  flow->setMethod(
-                                                    DeviceVerificationFlow::Method::Emoji);
-                                          } else if (std::find(
-                                                       msg.short_authentication_string.begin(),
-                                                       msg.short_authentication_string.end(),
-                                                       mtx::events::msg::SASMethods::Decimal) !=
-                                                     msg.short_authentication_string.end()) {
-                                                  flow->setMethod(
-                                                    DeviceVerificationFlow::Method::Decimal);
-                                          } else {
-                                                  flow->cancelVerification(
-                                                    DeviceVerificationFlow::Error::UnknownMethod);
-                                                  return;
-                                          }
-                                          emit newDeviceVerificationRequest(
-                                            std::move(flow),
-                                            QString::fromStdString(msg.transaction_id.value()),
-                                            QString::fromStdString(sender),
-                                            QString::fromStdString(msg.from_device));
-                                  } else {
-                                          flow->cancelVerification(
-                                            DeviceVerificationFlow::Error::UnknownMethod);
-                                  }
+                  auto event_id = QString::fromStdString(message.event_id);
+                  if (!this->dvList.contains(event_id)) {
+                          if (auto flow = DeviceVerificationFlow::NewInRoomVerification(
+                                this,
+                                model,
+                                message.content,
+                                QString::fromStdString(message.sender),
+                                event_id)) {
+                                  dvList[event_id] = flow;
+                                  emit newDeviceVerificationRequest(flow.data());
                           }
                   }
           });
+        connect(dynamic_cast(parent),
+                &ChatPage::receivedDeviceVerificationRequest,
+                this,
+                [this](const mtx::events::msg::KeyVerificationRequest &msg, std::string sender) {
+                        if (!msg.transaction_id)
+                                return;
+
+                        auto txnid = QString::fromStdString(msg.transaction_id.value());
+                        if (!this->dvList.contains(txnid)) {
+                                if (auto flow = DeviceVerificationFlow::NewToDeviceVerification(
+                                      this, msg, QString::fromStdString(sender), txnid)) {
+                                        dvList[txnid] = flow;
+                                        emit newDeviceVerificationRequest(flow.data());
+                                }
+                        }
+                });
+        connect(dynamic_cast(parent),
+                &ChatPage::receivedDeviceVerificationStart,
+                this,
+                [this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) {
+                        if (!msg.transaction_id)
+                                return;
+
+                        auto txnid = QString::fromStdString(msg.transaction_id.value());
+                        if (!this->dvList.contains(txnid)) {
+                                if (auto flow = DeviceVerificationFlow::NewToDeviceVerification(
+                                      this, msg, QString::fromStdString(sender), txnid)) {
+                                        dvList[txnid] = flow;
+                                        emit newDeviceVerificationRequest(flow.data());
+                                }
+                        }
+                });
         connect(parent, &ChatPage::loggedOut, this, [this]() {
                 isInitialSync_ = true;
                 emit initialSyncChanged(true);
@@ -428,6 +364,46 @@ TimelineViewManager::openRoomSettings() const
         MainWindow::instance()->openRoomSettings(timeline_->roomId());
 }
 
+void
+TimelineViewManager::verifyUser(QString userid)
+{
+        auto joined_rooms = cache::joinedRooms();
+        auto room_infos   = cache::getRoomInfo(joined_rooms);
+
+        for (std::string room_id : joined_rooms) {
+                if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
+                    cache::isRoomEncrypted(room_id)) {
+                        auto room_members = cache::roomMembers(room_id);
+                        if (std::find(room_members.begin(),
+                                      room_members.end(),
+                                      (userid).toStdString()) != room_members.end()) {
+                                auto model = models.value(QString::fromStdString(room_id));
+                                auto flow  = DeviceVerificationFlow::InitiateUserVerification(
+                                  this, model.data(), userid);
+                                connect(model.data(),
+                                        &TimelineModel::updateFlowEventId,
+                                        this,
+                                        [this, flow](std::string eventId) {
+                                                dvList[QString::fromStdString(eventId)] = flow;
+                                        });
+                                emit newDeviceVerificationRequest(flow.data());
+                                return;
+                        }
+                }
+        }
+
+        emit ChatPage::instance()->showNotification(
+          tr("No share room with this user found. Create an "
+             "encrypted room with this user and try again."));
+}
+void
+TimelineViewManager::verifyDevice(QString userid, QString deviceid)
+{
+        auto flow = DeviceVerificationFlow::InitiateDeviceVerification(this, userid, deviceid);
+        this->dvList[flow->transactionId()] = flow;
+        emit newDeviceVerificationRequest(flow.data());
+}
+
 void
 TimelineViewManager::updateReadReceipts(const QString &room_id,
                                         const std::vector &event_ids)
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 4779d3cd..12e49080 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -24,20 +24,6 @@ class ColorImageProvider;
 class UserSettings;
 class ChatPage;
 
-class DeviceVerificationList : public QObject
-{
-        Q_OBJECT
-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;
-};
-
 class TimelineViewManager : public QObject
 {
         Q_OBJECT
@@ -77,6 +63,9 @@ public:
         Q_INVOKABLE void openLeaveRoomDialog() const;
         Q_INVOKABLE void openRoomSettings() const;
 
+        void verifyUser(QString userid);
+        void verifyDevice(QString userid, QString deviceid);
+
 signals:
         void clearRoomMessageCount(QString roomid);
         void updateRoomsLastMessage(QString roomid, const DescInfo &info);
@@ -84,11 +73,7 @@ signals:
         void initialSyncChanged(bool isInitialSync);
         void replyingEventChanged(QString replyingEvent);
         void replyClosed();
-        void newDeviceVerificationRequest(DeviceVerificationFlow *flow,
-                                          QString transactionId,
-                                          QString userId,
-                                          QString deviceId,
-                                          bool isRequest = false);
+        void newDeviceVerificationRequest(DeviceVerificationFlow *flow);
         void inviteUsers(QStringList users);
         void showRoomList();
         void narrowViewChanged();
@@ -180,7 +165,7 @@ private:
         QSharedPointer settings;
         QHash userColors;
 
-        DeviceVerificationList *dvList;
+        QHash> dvList;
 };
 Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationAccept)
 Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationCancel)
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 2ea3f7b6..2a1eecdf 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -6,13 +6,18 @@
 #include "Utils.h"
 #include "mtx/responses/crypto.hpp"
 #include "timeline/TimelineModel.h"
+#include "timeline/TimelineViewManager.h"
 
 #include  // only for debugging
 
-UserProfile::UserProfile(QString roomid, QString userid, TimelineModel *parent)
+UserProfile::UserProfile(QString roomid,
+                         QString userid,
+                         TimelineViewManager *manager_,
+                         TimelineModel *parent)
   : QObject(parent)
   , roomid_(roomid)
   , userid_(userid)
+  , manager(manager_)
   , model(parent)
 {
         fetchDeviceList(this->userid_);
@@ -270,44 +275,18 @@ UserProfile::startChat()
         emit ChatPage::instance()->createRoom(req);
 }
 
-DeviceVerificationFlow *
-UserProfile::createFlow(bool isVerifyUser)
+void
+UserProfile::verify(QString device)
 {
-        if (!isVerifyUser)
-                return (new DeviceVerificationFlow(this, DeviceVerificationFlow::Type::ToDevice));
+        if (!device.isEmpty())
+                manager->verifyDevice(userid_, device);
         else {
-                std::cout << "CHECKING IF IT TO START ROOM_VERIFICATION OR TO_DEVICE VERIFICATION"
-                          << std::endl;
-                auto joined_rooms = cache::joinedRooms();
-                auto room_infos   = cache::getRoomInfo(joined_rooms);
-
-                for (std::string room_id : joined_rooms) {
-                        if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
-                            cache::isRoomEncrypted(room_id)) {
-                                auto room_members = cache::roomMembers(room_id);
-                                if (std::find(room_members.begin(),
-                                              room_members.end(),
-                                              (this->userid()).toStdString()) !=
-                                    room_members.end()) {
-                                        std::cout
-                                          << "FOUND A ENCRYPTED ROOM WITH THIS USER : " << room_id
-                                          << std::endl;
-                                        if (this->roomid_.toStdString() == room_id) {
-                                                auto newflow = new DeviceVerificationFlow(
-                                                  this,
-                                                  DeviceVerificationFlow::Type::RoomMsg,
-                                                  this->model);
-                                                return (std::move(newflow));
-                                        } else {
-                                                std::cout << "FOUND A ENCRYPTED ROOM BUT CURRENTLY "
-                                                             "NOT IN THAT ROOM : "
-                                                          << room_id << std::endl;
-                                        }
-                                }
-                        }
-                }
-
-                std::cout << "DIDN'T FIND A ENCRYPTED ROOM WITH THIS USER" << std::endl;
-                return (new DeviceVerificationFlow(this, DeviceVerificationFlow::Type::ToDevice));
+                manager->verifyUser(userid_);
         }
 }
+
+void
+UserProfile::unverify(QString device)
+{
+        cache::markDeviceUnverified(userid_.toStdString(), device.toStdString());
+}
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index de55b6ab..18933727 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -21,6 +21,7 @@ Q_ENUM_NS(Status)
 
 class DeviceVerificationFlow;
 class TimelineModel;
+class TimelineViewManager;
 
 class DeviceInfo
 {
@@ -84,7 +85,10 @@ class UserProfile : public QObject
         Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
         Q_PROPERTY(bool isUserVerified READ getUserStatus CONSTANT)
 public:
-        UserProfile(QString roomid, QString userid, TimelineModel *parent = nullptr);
+        UserProfile(QString roomid,
+                    QString userid,
+                    TimelineViewManager *manager_,
+                    TimelineModel *parent = nullptr);
 
         DeviceInfoModel *deviceList();
 
@@ -93,7 +97,8 @@ public:
         QString avatarUrl();
         bool getUserStatus();
 
-        Q_INVOKABLE DeviceVerificationFlow *createFlow(bool isVerifyUser);
+        Q_INVOKABLE void verify(QString device = "");
+        Q_INVOKABLE void unverify(QString device = "");
         Q_INVOKABLE void fetchDeviceList(const QString &userID);
         Q_INVOKABLE void banUser();
         // Q_INVOKABLE void ignoreUser();
@@ -105,6 +110,7 @@ private:
         std::optional cross_verified;
         DeviceInfoModel deviceList_;
         bool isUserVerified = false;
+        TimelineViewManager *manager;
         TimelineModel *model;
 
         void callback_fn(const mtx::responses::QueryKeys &res,
-- 
cgit 1.5.1


From 8a4d85f801368137a0b1c17621947b334e280257 Mon Sep 17 00:00:00 2001
From: Nicolas Werner 
Date: Mon, 5 Oct 2020 22:58:07 +0200
Subject: Show different verification errors

---
 .../qml/device-verification/DeviceVerification.qml |  1 -
 resources/qml/device-verification/Failed.qml       | 28 ++++++++++++----------
 resources/qml/device-verification/Waiting.qml      |  4 ++--
 src/DeviceVerificationFlow.cpp                     |  5 ++--
 src/DeviceVerificationFlow.h                       |  4 ++--
 src/timeline/TimelineViewManager.cpp               | 12 ++++++++++
 src/timeline/TimelineViewManager.h                 |  1 +
 7 files changed, 35 insertions(+), 20 deletions(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index 4e93df06..64f10b35 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -6,7 +6,6 @@ import im.nheko 1.0
 
 ApplicationWindow {
 	property var flow
-	property var tran_id
 
 	title: stack.currentItem.title
 	id: dialog
diff --git a/resources/qml/device-verification/Failed.qml b/resources/qml/device-verification/Failed.qml
index 6b5d57ef..fcff7893 100644
--- a/resources/qml/device-verification/Failed.qml
+++ b/resources/qml/device-verification/Failed.qml
@@ -2,23 +2,29 @@ import QtQuick 2.3
 import QtQuick.Controls 2.10
 import QtQuick.Layouts 1.10
 
+import im.nheko 1.0
+
 Pane {
-	property string title: qsTr("Verification timed out")
+	property string title: qsTr("Verification failed")
 	ColumnLayout {
 		spacing: 16
 		Text {
+			id: content
+
 			Layout.maximumWidth: 400
 			Layout.fillHeight: true
 			Layout.fillWidth: true
+
 			wrapMode: Text.Wrap
-			id: content
 			text: switch (flow.error) {
-				case VerificationStatus.UnknownMethod: return qsTr("Device verification timed out.")
-				case VerificationStatus.MismatchedCommitment: return qsTr("Device verification timed out.")
-				case VerificationStatus.MismatchedSAS: return qsTr("Device verification timed out.")
-				case VerificationStatus.KeyMismatch: return qsTr("Device verification timed out.")
-				case VerificationStatus.Timeout: return qsTr("Device verification timed out.")
-				case VerificationStatus.OutOfOrder: return qsTr("Device verification timed out.")
+				case DeviceVerificationFlow.UnknownMethod: return qsTr("Other client does not support our verification protocol.")
+				case DeviceVerificationFlow.MismatchedCommitment:
+				case DeviceVerificationFlow.MismatchedSAS:
+				case DeviceVerificationFlow.KeyMismatch: return qsTr("Key mismatch detected!")
+				case DeviceVerificationFlow.Timeout: return qsTr("Device verification timed out.")
+				case DeviceVerificationFlow.User: return qsTr("Other party canceled the verification.")
+				case DeviceVerificationFlow.OutOfOrder: return qsTr("Device verification timed out.")
+				default: return "Unknown verification error.";
 			}
 			color:colors.text
 			verticalAlignment: Text.AlignVCenter
@@ -31,11 +37,7 @@ Pane {
 				Layout.alignment: Qt.AlignRight
 				text: qsTr("Close")
 
-				onClicked: {
-					deviceVerificationList.remove(tran_id);
-					flow.deleteFlow();
-					dialog.close()
-				}
+				onClicked: dialog.close()
 			}
 		}
 	}
diff --git a/resources/qml/device-verification/Waiting.qml b/resources/qml/device-verification/Waiting.qml
index f36910e7..38abf767 100644
--- a/resources/qml/device-verification/Waiting.qml
+++ b/resources/qml/device-verification/Waiting.qml
@@ -20,12 +20,12 @@ Pane {
 				case "WaitingForMac": return qsTr("Waiting for other side to complete the verification request.")
 			}
 
-			color:colors.text
+			color: colors.text
 			verticalAlignment: Text.AlignVCenter
 		}
 		BusyIndicator {
 			Layout.alignment: Qt.AlignHCenter
-			palette: color
+			palette: colors
 		}
 		RowLayout {
 			Button {
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index 99fd7bed..79f1de84 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -64,7 +64,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
         }
 
         connect(timeout, &QTimer::timeout, this, [this]() {
-                this->cancelVerification(DeviceVerificationFlow::Error::Timeout);
+                if (state_ != Success && state_ != Failed)
+                        this->cancelVerification(DeviceVerificationFlow::Error::Timeout);
         });
 
         connect(ChatPage::instance(),
@@ -114,7 +115,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                                         return;
                         }
                         error_ = User;
-                        emit errorChanged();
+                        Emit errorChanged();
                         setState(Failed);
                 });
 
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index 1fe3919b..a1ceaf80 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -58,7 +58,7 @@ class DeviceVerificationFlow : public QObject
         Q_OBJECT
         // Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
         Q_PROPERTY(QString state READ state NOTIFY stateChanged)
-        Q_PROPERTY(Error error READ error CONSTANT)
+        Q_PROPERTY(Error error READ error NOTIFY errorChanged)
         Q_PROPERTY(QString userId READ getUserId CONSTANT)
         Q_PROPERTY(QString deviceId READ getDeviceId CONSTANT)
         Q_PROPERTY(bool sender READ getSender CONSTANT)
@@ -203,7 +203,7 @@ private:
         mtx::common::RelatesTo relation;
 
         State state_ = PromptStartVerification;
-        Error error_;
+        Error error_ = UnknownMethod;
 
         bool isMacVerified = false;
 
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 250cd5f0..ed720056 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -396,6 +396,18 @@ TimelineViewManager::verifyUser(QString userid)
           tr("No share room with this user found. Create an "
              "encrypted room with this user and try again."));
 }
+
+void
+TimelineViewManager::removeVerificationFlow(DeviceVerificationFlow *flow)
+{
+        for (auto it = dvList.keyValueBegin(); it != dvList.keyValueEnd(); ++it) {
+                if (it->second == flow) {
+                        dvList.remove(it->first);
+                        return;
+                }
+        }
+}
+
 void
 TimelineViewManager::verifyDevice(QString userid, QString deviceid)
 {
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 12e49080..a8bd2e06 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -62,6 +62,7 @@ public:
         Q_INVOKABLE void openMemberListDialog() const;
         Q_INVOKABLE void openLeaveRoomDialog() const;
         Q_INVOKABLE void openRoomSettings() const;
+        Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
 
         void verifyUser(QString userid);
         void verifyDevice(QString userid, QString deviceid);
-- 
cgit 1.5.1


From 08d5a84cbdbb8937dbe4d43817e01d8ae00760cc Mon Sep 17 00:00:00 2001
From: Nicolas Werner 
Date: Thu, 8 Oct 2020 17:26:07 +0200
Subject: Fix issues with old qt and bump to 5.10

---
 .travis.yml                          | 32 ++++++++++++++++----------------
 CMakeLists.txt                       |  4 ++--
 README.md                            |  2 +-
 src/timeline/TimelineViewManager.cpp | 12 +++++++-----
 4 files changed, 26 insertions(+), 24 deletions(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/.travis.yml b/.travis.yml
index eec32290..49c6eb17 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -63,21 +63,21 @@ matrix:
           env:
               - CXX=g++-8
               - CC=gcc-8
-              - QT_PKG=59
+              - QT_PKG=510
           addons:
               apt:
                   sources: 
                     - ubuntu-toolchain-r-test
-                    - sourceline: 'ppa:beineri/opt-qt597-xenial'
+                    - sourceline: 'ppa:beineri/opt-qt-5.10.1-xenial'
                   packages: 
                     - g++-8 
                     - ninja-build
-                    - qt59base
-                    - qt59tools
-                    - qt59svg
-                    - qt59multimedia
-                    - qt59quickcontrols2
-                    - qt59graphicaleffects
+                    - qt510base
+                    - qt510tools
+                    - qt510svg
+                    - qt510multimedia
+                    - qt510quickcontrols2
+                    - qt510graphicaleffects
                     - liblmdb-dev
                     - libgl1-mesa-dev # needed for missing gl.h
         - os: linux
@@ -85,23 +85,23 @@ matrix:
           env:
               - CXX=clang++-6.0
               - CC=clang-6.0
-              - QT_PKG=59
+              - QT_PKG=510
           addons:
               apt:
                   sources: 
                     - ubuntu-toolchain-r-test
                     - llvm-toolchain-xenial-6.0
-                    - sourceline: 'ppa:beineri/opt-qt597-xenial'
+                    - sourceline: 'ppa:beineri/opt-qt-5.10.1-xenial'
                   packages: 
                     - clang++-6.0
                     - g++-7 
                     - ninja-build
-                    - qt59base
-                    - qt59tools
-                    - qt59svg
-                    - qt59multimedia
-                    - qt59quickcontrols2
-                    - qt59graphicaleffects
+                    - qt510base
+                    - qt510tools
+                    - qt510svg
+                    - qt510multimedia
+                    - qt510quickcontrols2
+                    - qt510graphicaleffects
                     - liblmdb-dev
                     - libgl1-mesa-dev # needed for missing gl.h
         - os: linux
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4348e819..2f83a865 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -142,9 +142,9 @@ if (APPLE)
 endif(APPLE)
 
 if (Qt5Widgets_FOUND)
-	if (Qt5Widgets_VERSION VERSION_LESS 5.9.0)
+	if (Qt5Widgets_VERSION VERSION_LESS 5.10.0)
 		message(STATUS "Qt version ${Qt5Widgets_VERSION}")
-		message(WARNING "Minimum supported Qt5 version is 5.9!")
+		message(WARNING "Minimum supported Qt5 version is 5.10!")
 	endif()
 endif(Qt5Widgets_FOUND)
 
diff --git a/README.md b/README.md
index 2d24165c..92b55460 100644
--- a/README.md
+++ b/README.md
@@ -174,7 +174,7 @@ sudo pacman -S qt5-base \
 ##### Gentoo Linux
 
 ```bash
-sudo emerge -a ">=dev-qt/qtgui-5.9.0" media-libs/fontconfig
+sudo emerge -a ">=dev-qt/qtgui-5.10.0" media-libs/fontconfig
 ```
 
 ##### Ubuntu 20.04
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 18151173..b11c4965 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -125,11 +125,13 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
           0,
           "UserProfileModel",
           "UserProfile needs to be instantiated on the C++ side");
+
+        static auto self = this;
         qmlRegisterSingletonType(
-          "im.nheko", 1, 0, "TimelineManager", [this](QQmlEngine *, QJSEngine *) { return this; });
+          "im.nheko", 1, 0, "TimelineManager", [](QQmlEngine *, QJSEngine *) { return self; });
         qmlRegisterSingletonType(
-          "im.nheko", 1, 0, "Settings", [this](QQmlEngine *, QJSEngine *) {
-                  return this->settings.data();
+          "im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) {
+                  return self->settings.data();
           });
 
         qRegisterMetaType();
@@ -413,8 +415,8 @@ void
 TimelineViewManager::removeVerificationFlow(DeviceVerificationFlow *flow)
 {
         for (auto it = dvList.keyValueBegin(); it != dvList.keyValueEnd(); ++it) {
-                if (it->second == flow) {
-                        dvList.remove(it->first);
+                if ((*it).second == flow) {
+                        dvList.remove((*it).first);
                         return;
                 }
         }
-- 
cgit 1.5.1


From e5fb9a25ea06f03129961a0df507361baae4b67a Mon Sep 17 00:00:00 2001
From: Nicolas Werner 
Date: Thu, 8 Oct 2020 18:16:30 +0200
Subject: Try to please the CI gods

---
 src/DeviceVerificationFlow.h         | 2 +-
 src/timeline/TimelineViewManager.cpp | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

(limited to 'src/timeline/TimelineViewManager.cpp')

diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index 9ca45a94..d70374d9 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -211,7 +211,7 @@ private:
                         body[this->toClient][deviceId.toStdString()] = msg;
 
                         http::client()->send_to_device(
-                          this->transaction_id, body, [this](mtx::http::RequestErr err) {
+                          this->transaction_id, body, [](mtx::http::RequestErr err) {
                                   if (err)
                                           nhlog::net()->warn(
                                             "failed to send verification to_device message: {} {}",
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index b11c4965..7c81ca8f 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -128,9 +128,11 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin
 
         static auto self = this;
         qmlRegisterSingletonType(
-          "im.nheko", 1, 0, "TimelineManager", [](QQmlEngine *, QJSEngine *) { return self; });
+          "im.nheko", 1, 0, "TimelineManager", [](QQmlEngine *, QJSEngine *) -> QObject * {
+                  return self;
+          });
         qmlRegisterSingletonType(
-          "im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) {
+          "im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
                   return self->settings.data();
           });
 
-- 
cgit 1.5.1