libQuotient
A Qt library for building matrix clients
keyverificationsession.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
2 // SPDX-License-Identifier: LGPL-2.1-or-later
3 
4 #pragma once
5 
6 #include "events/keyverificationevent.h"
7 #include "events/roommessageevent.h"
8 
9 #include <QtCore/QObject>
10 #include <QtCore/QPointer>
11 
12 struct OlmSAS;
13 
14 namespace Quotient {
15 class Connection;
16 class Room;
17 
18 struct QUOTIENT_API EmojiEntry {
19  QString emoji;
20  QString description;
21 
22  Q_GADGET
23  Q_PROPERTY(QString emoji MEMBER emoji CONSTANT)
24  Q_PROPERTY(QString description MEMBER description CONSTANT)
25 
26 public:
27  friend bool operator==(const EmojiEntry&, const EmojiEntry&) = default;
28 };
29 
30 /** A key verification session. Listen for incoming sessions by connecting to Connection::newKeyVerificationSession.
31  Start a new session using Connection::startKeyVerificationSession.
32  The object is delete after finished is emitted.
33 */
34 class QUOTIENT_API KeyVerificationSession : public QObject
35 {
36  Q_OBJECT
37 
38 public:
39  enum State {
40  INCOMING, ///< There is a request for verification incoming
41  //! We sent a request for verification and are waiting for ready
42  WAITINGFORREADY,
43  //! Either party sent a ready as a response to a request; the user
44  //! selects a method
45  READY,
46  WAITINGFORACCEPT, ///< We sent a start and are waiting for an accept
47  ACCEPTED, ///< The other party sent an accept and is waiting for a key
48  WAITINGFORKEY, ///< We're waiting for a key
49  //! We're waiting for the *user* to verify the emojis
50  WAITINGFORVERIFICATION,
51  WAITINGFORMAC, ///< We're waiting for the mac
52  CANCELED, ///< The session has been canceled
53  DONE, ///< The verification is done
54  };
55  Q_ENUM(State)
56 
57  enum Error {
58  NONE,
59  TIMEOUT,
60  REMOTE_TIMEOUT,
61  USER,
62  REMOTE_USER,
63  UNEXPECTED_MESSAGE,
64  REMOTE_UNEXPECTED_MESSAGE,
65  UNKNOWN_TRANSACTION,
66  REMOTE_UNKNOWN_TRANSACTION,
67  UNKNOWN_METHOD,
68  REMOTE_UNKNOWN_METHOD,
69  KEY_MISMATCH,
70  REMOTE_KEY_MISMATCH,
71  USER_MISMATCH,
72  REMOTE_USER_MISMATCH,
73  INVALID_MESSAGE,
74  REMOTE_INVALID_MESSAGE,
75  SESSION_ACCEPTED,
76  REMOTE_SESSION_ACCEPTED,
77  MISMATCHED_COMMITMENT,
78  REMOTE_MISMATCHED_COMMITMENT,
79  MISMATCHED_SAS,
80  REMOTE_MISMATCHED_SAS,
81  };
82  Q_ENUM(Error)
83 
84  Q_PROPERTY(QString remoteDeviceId MEMBER m_remoteDeviceId CONSTANT)
85  Q_PROPERTY(QString remoteUserId MEMBER m_remoteUserId CONSTANT)
86  Q_PROPERTY(QVector<EmojiEntry> sasEmojis READ sasEmojis NOTIFY sasEmojisChanged)
87  Q_PROPERTY(State state READ state NOTIFY stateChanged)
88  Q_PROPERTY(Error error READ error NOTIFY errorChanged)
89  // Whether this is a user verification (in contrast to a device verification)
90  Q_PROPERTY(bool userVerification READ userVerification CONSTANT)
91 
92  // Incoming device verification
93  KeyVerificationSession(QString remoteUserId,
94  const KeyVerificationRequestEvent& event,
95  Connection* connection, bool encrypted);
96 
97  // Outgoing device verification
98  KeyVerificationSession(QString userId, QString deviceId,
99  Connection* connection);
100 
101  // Incoming user verification
102  KeyVerificationSession(const RoomMessageEvent *event, Room *room);
103 
104  // Outgoing user verification
105  explicit KeyVerificationSession(Room *room);
106 
107  void handleEvent(const KeyVerificationEvent& baseEvent);
108 
109  QVector<EmojiEntry> sasEmojis() const;
110  State state() const;
111 
112  Error error() const;
113 
114  QString remoteDeviceId() const;
115  QString transactionId() const;
116  bool userVerification() const;
117 
118  void setRequestEventId(const QString &eventId);
119 
120 public Q_SLOTS:
121  void sendRequest();
122  void sendReady();
123  void sendMac();
124  void sendStartSas();
125  void sendKey();
126  void sendDone();
127  void cancelVerification(Error error);
128 
129 Q_SIGNALS:
130  void keyReceived();
131  void sasEmojisChanged();
132  void stateChanged();
133  void errorChanged();
134  void finished();
135 
136 private:
137  // Internal delegating constructors
138 
139  KeyVerificationSession(QString remoteUserId, Connection* connection, QString remoteDeviceId,
140  bool encrypted, QStringList methods, QDateTime startTimestamp,
141  QString transactionId, Room* room = nullptr, QString requestEventId = {});
142  KeyVerificationSession(QString remoteUserId, Connection* connection, Room* room,
143  QString remoteDeviceId = {}, QString transactionId = {});
144 
145  Connection* const m_connection;
146  QPointer<Room> m_room;
147  const QString m_remoteUserId;
148  QString m_remoteDeviceId;
149  QString m_transactionId;
150  bool m_encrypted = false;
151  QStringList m_remoteSupportedMethods{};
152  QStringList m_commonMacCodes{};
153 
154  CStructPtr<OlmSAS> olmDataHolder = makeOlmData();
155  OlmSAS* olmData = olmDataHolder.get();
156  QVector<EmojiEntry> m_sasEmojis;
157  bool startSentByUs = false;
158  State m_state = INCOMING;
159  Error m_error = NONE;
160  QString m_startEvent{};
161  QString m_commitment{};
162  bool macReceived = false;
163  bool m_verified = false;
164  QString m_pendingEdKeyId{};
165  QString m_pendingMasterKey{};
166  QString m_requestEventId{};
167 
168  static CStructPtr<OlmSAS> makeOlmData();
169  void handleReady(const KeyVerificationReadyEvent& event);
170  void handleStart(const KeyVerificationStartEvent& event);
171  void handleKey(const KeyVerificationKeyEvent& event);
172  void handleMac(const KeyVerificationMacEvent& event);
173  void setupTimeout(std::chrono::milliseconds timeout);
174  void setState(State state);
175  void setError(Error error);
176  static QString errorToString(Error error);
177  static Error stringToError(const QString& error);
178  void trustKeys();
179  void sendEvent(const QString &userId, const QString &deviceId, const KeyVerificationEvent &event, bool encrypted);
180 
181  QByteArray macInfo(bool verifying, const QString& key = "KEY_IDS"_L1);
182  QString calculateMac(const QString& input, bool verifying, const QString& keyId= "KEY_IDS"_L1);
183 };
184 
185 } // namespace Quotient
186 Q_DECLARE_METATYPE(Quotient::EmojiEntry)