summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2024-01-15 02:16:04 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2024-01-15 02:17:18 +0100
commit51236c32600ab456b0beab420e641c7583c4241b (patch)
tree53eaf948156dcf3a1035e53efdcfb906033e3595
parentFix gstreamer deinit (diff)
downloadnheko-51236c32600ab456b0beab420e641c7583c4241b.tar.xz
Fix verification with multiple devices in parallel
Fixes #1125
-rw-r--r--resources/qml/device-verification/Failed.qml2
-rw-r--r--src/encryption/DeviceVerificationFlow.cpp41
-rw-r--r--src/encryption/DeviceVerificationFlow.h1
3 files changed, 39 insertions, 5 deletions
diff --git a/resources/qml/device-verification/Failed.qml b/resources/qml/device-verification/Failed.qml
index 5847894b..baf8900b 100644
--- a/resources/qml/device-verification/Failed.qml
+++ b/resources/qml/device-verification/Failed.qml
@@ -29,6 +29,8 @@ ColumnLayout {
                 return qsTr("Device verification timed out.");
                 case DeviceVerificationFlow.User:
                 return qsTr("Other party canceled the verification.");
+                case DeviceVerificationFlow.AcceptedOnOtherDevice:
+                return qsTr("The verification was accepted by a different device.");
                 case DeviceVerificationFlow.OutOfOrder:
                 return qsTr("Verification messages received out of order!");
                 default:
diff --git a/src/encryption/DeviceVerificationFlow.cpp b/src/encryption/DeviceVerificationFlow.cpp
index 0c488f20..3de14658 100644
--- a/src/encryption/DeviceVerificationFlow.cpp
+++ b/src/encryption/DeviceVerificationFlow.cpp
@@ -105,6 +105,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
             &ChatPage::receivedDeviceVerificationAccept,
             this,
             [this](const mtx::events::msg::KeyVerificationAccept &msg) {
+                if (state_ == Failed || state_ == Success)
+                    return;
+
                 nhlog::crypto()->info("verification: received accept with mac methods {}",
                                       fmt::join(msg.message_authentication_code, ", "));
                 if (msg.transaction_id.has_value()) {
@@ -114,6 +117,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                     if (msg.relations.references() != this->relation.event_id)
                         return;
                 }
+
                 if (msg.key_agreement_protocol == "curve25519-hkdf-sha256" &&
                     msg.hash == "sha256" &&
                     (msg.message_authentication_code == mac_method_alg_v1 ||
@@ -157,6 +161,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
       &ChatPage::receivedDeviceVerificationKey,
       this,
       [this](const mtx::events::msg::KeyVerificationKey &msg) {
+          if (state_ == Failed || state_ == Success)
+              return;
+
           nhlog::crypto()->info(
             "verification: received key, sender {}, state {}", sender, state().toStdString());
           if (msg.transaction_id.has_value()) {
@@ -219,6 +226,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
       &ChatPage::receivedDeviceVerificationMac,
       this,
       [this](const mtx::events::msg::KeyVerificationMac &msg) {
+          if (state_ == Failed || state_ == Success)
+              return;
+
           nhlog::crypto()->info("verification: received mac");
           if (msg.transaction_id.has_value()) {
               if (msg.transaction_id.value() != this->transaction_id)
@@ -326,6 +336,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
               }
 
               if (!req.signatures.empty()) {
+                  nhlog::crypto()->debug("Signatures to send: {}", nlohmann::json(req).dump(2));
                   http::client()->keys_signatures_upload(
                     req,
                     [](const mtx::responses::KeySignaturesUpload &res, mtx::http::RequestErr err) {
@@ -374,12 +385,16 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
       &ChatPage::receivedDeviceVerificationReady,
       this,
       [this](const mtx::events::msg::KeyVerificationReady &msg) {
+          if (state_ == Failed || state_ == Success)
+              return;
+
           nhlog::crypto()->info("verification: received ready {}", (void *)this);
           if (!sender) {
-              if (msg.from_device != http::client()->device_id()) {
-                  error_ = User;
-                  emit errorChanged();
-                  setState(Failed);
+              if (msg.from_device != this->deviceId.toStdString()) {
+                  nhlog::crypto()->debug("Accepted by {}, we are communicating with {}",
+                                         msg.from_device,
+                                         this->deviceId.toStdString());
+                  cancelVerification(AcceptedOnOtherDevice);
               }
 
               return;
@@ -558,6 +573,9 @@ void
 DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificationStart &msg,
                                            std::string)
 {
+    if (state_ == Failed || state_ == Success)
+        return;
+
     if (msg.transaction_id.has_value()) {
         if (msg.transaction_id.value() != this->transaction_id)
             return;
@@ -568,6 +586,14 @@ DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificati
         return;
     }
 
+    if (state_ == Failed)
+        return;
+
+    if (msg.from_device != this->deviceId.toStdString()) {
+        cancelVerification(AcceptedOnOtherDevice);
+        return;
+    }
+
     nhlog::crypto()->info("verification: received start with mac methods {}",
                           fmt::join(msg.message_authentication_codes, ", "));
 
@@ -625,6 +651,9 @@ DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificati
 void
 DeviceVerificationFlow::acceptVerificationRequest()
 {
+    if (state_ == Failed || state_ == Success)
+        return;
+
     if (acceptSent)
         return;
 
@@ -769,7 +798,9 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
     this->setState(Failed);
     emit errorChanged();
 
-    send(req);
+    // Don't cancel if the user accepted the request elsewhere, instead just silently stop
+    if (error_code != AcceptedOnOtherDevice)
+        send(req);
 }
 //! sends the verification key
 void
diff --git a/src/encryption/DeviceVerificationFlow.h b/src/encryption/DeviceVerificationFlow.h
index e64eab96..6f8f413e 100644
--- a/src/encryption/DeviceVerificationFlow.h
+++ b/src/encryption/DeviceVerificationFlow.h
@@ -104,6 +104,7 @@ public:
         KeyMismatch,
         Timeout,
         User,
+        AcceptedOnOtherDevice,
         OutOfOrder,
     };
     Q_ENUM(Error)