summary refs log tree commit diff
path: root/src/DeviceVerificationFlow.h
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2020-10-05 22:12:10 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2020-10-05 22:12:10 +0200
commitbca29a4227a871caac21236c29430b69264018ce (patch)
treedc5bf6b5ecc0ceed9d31d1210fc45693ad295b14 /src/DeviceVerificationFlow.h
parentDon't fail on missing key for a device and /rotate-megolm-session command (diff)
downloadnheko-bca29a4227a871caac21236c29430b69264018ce.tar.xz
Make steps in verification flow explicit
Diffstat (limited to 'src/DeviceVerificationFlow.h')
-rw-r--r--src/DeviceVerificationFlow.h215
1 files changed, 160 insertions, 55 deletions
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 <mtx/responses/crypto.hpp>
 
 #include "CacheCryptoStructs.h"
+#include "Logging.h"
 #include "MatrixClient.h"
 #include "Olm.h"
+#include "timeline/TimelineModel.h"
 
 class QTimer;
 
 using sas_ptr = std::unique_ptr<mtx::crypto::SAS>;
 
-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<int> 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<DeviceVerificationFlow> NewInRoomVerification(
+          QObject *parent_,
+          TimelineModel *timelineModel_,
+          const mtx::events::msg::KeyVerificationRequest &msg,
+          QString other_user_,
+          QString event_id_);
+        static QSharedPointer<DeviceVerificationFlow> NewToDeviceVerification(
+          QObject *parent_,
+          const mtx::events::msg::KeyVerificationRequest &msg,
+          QString other_user_,
+          QString txn_id_);
+        static QSharedPointer<DeviceVerificationFlow> NewToDeviceVerification(
+          QObject *parent_,
+          const mtx::events::msg::KeyVerificationStart &msg,
+          QString other_user_,
+          QString txn_id_);
+        static QSharedPointer<DeviceVerificationFlow>
+        InitiateUserVerification(QObject *parent_, TimelineModel *timelineModel_, QString userid);
+        static QSharedPointer<DeviceVerificationFlow> 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<int> getSasList();
         bool getSender();
+        std::vector<int> 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<std::string> room_id;
+        std::optional<std::string> 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<int> sasList;
         std::map<std::string, std::string> device_keys;
-        // for to_device messages
-        std::string transaction_id;
-        // for room messages
-        std::optional<std::string> room_id;
-        std::optional<std::string> event_id;
         TimelineModel *model_;
         mtx::common::RelatesTo relation;
+
+        State state_ = PromptStartVerification;
+        Error error_;
+
+        bool isMacVerified = false;
+
+        template<typename T>
+        void send(T msg)
+        {
+                if (this->type == DeviceVerificationFlow::Type::ToDevice) {
+                        mtx::requests::ToDeviceMessages<T> body;
+                        msg.transaction_id                           = this->transaction_id;
+                        body[this->toClient][deviceId.toStdString()] = msg;
+
+                        http::client()->send_to_device<T>(
+                          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<int>(err->status_code));
+                          });
+                } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
+                        if constexpr (!std::is_same_v<T, mtx::events::msg::KeyVerificationRequest>)
+                                msg.relates_to = this->relation;
+                        (model_)->sendMessageEvent(msg, mtx::events::to_device_content_to_type<T>);
+                }
+
+                nhlog::net()->debug(
+                  "Sent verification step: {} in state: {}",
+                  mtx::events::to_string(mtx::events::to_device_content_to_type<T>),
+                  state().toStdString());
+        }
 };