diff options
author | Nicolas Werner <nicolas.werner@hotmail.de> | 2020-10-05 22:12:10 +0200 |
---|---|---|
committer | Nicolas Werner <nicolas.werner@hotmail.de> | 2020-10-05 22:12:10 +0200 |
commit | bca29a4227a871caac21236c29430b69264018ce (patch) | |
tree | dc5bf6b5ecc0ceed9d31d1210fc45693ad295b14 /src/DeviceVerificationFlow.h | |
parent | Don't fail on missing key for a device and /rotate-megolm-session command (diff) | |
download | nheko-bca29a4227a871caac21236c29430b69264018ce.tar.xz |
Make steps in verification flow explicit
Diffstat (limited to 'src/DeviceVerificationFlow.h')
-rw-r--r-- | src/DeviceVerificationFlow.h | 215 |
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()); + } }; |