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: [PATCH] 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 | 641 +++++++++++--------- 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, 774 insertions(+), 348 deletions(-) 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(), + [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; + } + 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.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, - 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(); + 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, - 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); - } else { - this->cancelVerification( - DeviceVerificationFlow::Error::MismatchedCommitment); - } - } - } - }); 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; + [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.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; - } + 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::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; + if (this->type == DeviceVerificationFlow::Type::ToDevice) { + mtx::requests::ToDeviceMessages body; + req.transaction_id = this->transaction_id; - 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)); - }); + 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}; + req.from_device = http::client()->device_id(); + req.methods = {mtx::events::msg::VerificationMethods::SASv1}; - body[this->toClient][this->deviceId.toStdString()] = req; + if (this->type == DeviceVerificationFlow::Type::ToDevice) { + req.transaction_id = this->transaction_id; + mtx::requests::ToDeviceMessages body; - 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)); - }); + 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; + if (this->type == DeviceVerificationFlow::Type::ToDevice) { + mtx::requests::ToDeviceMessages body; + req.transaction_id = this->transaction_id; - body[this->toClient][this->deviceId.toStdString()] = req; + 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)); - }); + 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); + 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)); - }); + 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; + if (this->type == DeviceVerificationFlow::Type::ToDevice) { + QDateTime CurrentTime = QDateTime::currentDateTimeUtc(); - 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)); - }); + 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; + req.key = this->sas->public_key(); - body[this->toClient][deviceId.toStdString()] = req; + if (this->type == DeviceVerificationFlow::Type::ToDevice) { + mtx::requests::ToDeviceMessages body; + req.transaction_id = this->transaction_id; - 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)); - }); + 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; + 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)); + 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->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,