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());
+ }
};
|