1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
|
// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
#include "event.h"
namespace Quotient {
static constexpr auto SasV1Method = "m.sas.v1"_ls;
/// Requests a key verification with another user's devices.
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationRequestEvent : public Event {
public:
QUO_EVENT(KeyVerificationRequestEvent, "m.key.verification.request")
using Event::Event;
KeyVerificationRequestEvent(const QString& transactionId,
const QString& fromDevice,
const QStringList& methods,
const QDateTime& timestamp)
: KeyVerificationRequestEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId },
{ "from_device"_ls, fromDevice },
{ "methods"_ls, toJson(methods) },
{ "timestamp"_ls, toJson(timestamp) } }))
{}
/// The device ID which is initiating the request.
QUO_CONTENT_GETTER(QString, fromDevice)
/// An opaque identifier for the verification request. Must
/// be unique with respect to the devices involved.
QUO_CONTENT_GETTER(QString, transactionId)
/// The verification methods supported by the sender.
QUO_CONTENT_GETTER(QStringList, methods)
/// The POSIX timestamp in milliseconds for when the request was
/// made. If the request is in the future by more than 5 minutes or
/// more than 10 minutes in the past, the message should be ignored
/// by the receiver.
QUO_CONTENT_GETTER(QDateTime, timestamp)
};
class QUOTIENT_API KeyVerificationReadyEvent : public Event {
public:
QUO_EVENT(KeyVerificationReadyEvent, "m.key.verification.ready")
using Event::Event;
KeyVerificationReadyEvent(const QString& transactionId,
const QString& fromDevice,
const QStringList& methods)
: KeyVerificationReadyEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId },
{ "from_device"_ls, fromDevice },
{ "methods"_ls, toJson(methods) } }))
{}
/// The device ID which is accepting the request.
QUO_CONTENT_GETTER(QString, fromDevice)
/// The transaction id of the verification request
QUO_CONTENT_GETTER(QString, transactionId)
/// The verification methods supported by the sender.
QUO_CONTENT_GETTER(QStringList, methods)
};
/// Begins a key verification process.
class QUOTIENT_API KeyVerificationStartEvent : public Event {
public:
QUO_EVENT(KeyVerificationStartEvent, "m.key.verification.start")
using Event::Event;
KeyVerificationStartEvent(const QString& transactionId,
const QString& fromDevice)
: KeyVerificationStartEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId },
{ "from_device"_ls, fromDevice },
{ "method"_ls, SasV1Method },
{ "hashes"_ls, QJsonArray{ "sha256"_ls } },
{ "key_agreement_protocols"_ls,
QJsonArray{ "curve25519-hkdf-sha256"_ls } },
{ "message_authentication_codes"_ls,
QJsonArray{ "hkdf-hmac-sha256"_ls } },
{ "short_authentication_string"_ls,
QJsonArray{ "decimal"_ls, "emoji"_ls } } }))
{}
/// The device ID which is initiating the process.
QUO_CONTENT_GETTER(QString, fromDevice)
/// An opaque identifier for the verification request. Must
/// be unique with respect to the devices involved.
QUO_CONTENT_GETTER(QString, transactionId)
/// The verification method to use.
QUO_CONTENT_GETTER(QString, method)
/// Optional method to use to verify the other user's key with.
QUO_CONTENT_GETTER(Omittable<QString>, nextMethod)
// SAS.V1 methods
/// The key agreement protocols the sending device understands.
/// \note Only exist if method is m.sas.v1
QStringList keyAgreementProtocols() const
{
Q_ASSERT(method() == SasV1Method);
return contentPart<QStringList>("key_agreement_protocols"_ls);
}
/// The hash methods the sending device understands.
/// \note Only exist if method is m.sas.v1
QStringList hashes() const
{
Q_ASSERT(method() == SasV1Method);
return contentPart<QStringList>("hashes"_ls);
}
/// The message authentication codes that the sending device understands.
/// \note Only exist if method is m.sas.v1
QStringList messageAuthenticationCodes() const
{
Q_ASSERT(method() == SasV1Method);
return contentPart<QStringList>("message_authentication_codes"_ls);
}
/// The SAS methods the sending device (and the sending device's
/// user) understands.
/// \note Only exist if method is m.sas.v1
QString shortAuthenticationString() const
{
Q_ASSERT(method() == SasV1Method);
return contentPart<QString>("short_authentification_string"_ls);
}
};
/// Accepts a previously sent m.key.verification.start message.
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationAcceptEvent : public Event {
public:
QUO_EVENT(KeyVerificationAcceptEvent, "m.key.verification.accept")
using Event::Event;
KeyVerificationAcceptEvent(const QString& transactionId,
const QString& commitment)
: KeyVerificationAcceptEvent(basicJson(
TypeId, { { "transaction_id"_ls, transactionId },
{ "method"_ls, SasV1Method },
{ "key_agreement_protocol"_ls, "curve25519-hkdf-sha256" },
{ "hash"_ls, "sha256" },
{ "message_authentication_code"_ls, "hkdf-hmac-sha256" },
{ "short_authentication_string"_ls,
QJsonArray{ "decimal"_ls, "emoji"_ls, } },
{ "commitment"_ls, commitment } }))
{}
/// An opaque identifier for the verification process.
QUO_CONTENT_GETTER(QString, transactionId)
/// The verification method to use. Must be 'm.sas.v1'.
QUO_CONTENT_GETTER(QString, method)
/// The key agreement protocol the device is choosing to use, out of
/// the options in the m.key.verification.start message.
QUO_CONTENT_GETTER(QString, keyAgreementProtocol)
/// The hash method the device is choosing to use, out of the
/// options in the m.key.verification.start message.
QString hashData() const
{
return contentPart<QString>("hash"_ls);
}
/// The message authentication code the device is choosing to use, out
/// of the options in the m.key.verification.start message.
QUO_CONTENT_GETTER(QString, messageAuthenticationCode)
/// The SAS methods both devices involved in the verification process understand.
QUO_CONTENT_GETTER(QStringList, shortAuthenticationString)
/// The hash (encoded as unpadded base64) of the concatenation of the
/// device's ephemeral public key (encoded as unpadded base64) and the
/// canonical JSON representation of the m.key.verification.start message.
QUO_CONTENT_GETTER(QString, commitment)
};
class QUOTIENT_API KeyVerificationCancelEvent : public Event {
public:
QUO_EVENT(KeyVerificationCancelEvent, "m.key.verification.cancel")
using Event::Event;
KeyVerificationCancelEvent(const QString& transactionId,
const QString& reason)
: KeyVerificationCancelEvent(
basicJson(TypeId, {
{ "transaction_id"_ls, transactionId },
{ "reason"_ls, reason },
{ "code"_ls, reason } // Not a typo
}))
{}
/// An opaque identifier for the verification process.
QUO_CONTENT_GETTER(QString, transactionId)
/// A human readable description of the code. The client should only
/// rely on this string if it does not understand the code.
QUO_CONTENT_GETTER(QString, reason)
/// The error code for why the process/request was cancelled by the user.
QUO_CONTENT_GETTER(QString, code)
};
/// Sends the ephemeral public key for a device to the partner device.
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationKeyEvent : public Event {
public:
QUO_EVENT(KeyVerificationKeyEvent, "m.key.verification.key")
using Event::Event;
KeyVerificationKeyEvent(const QString& transactionId, const QString& key)
: KeyVerificationKeyEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId },
{ "key"_ls, key } }))
{}
/// An opaque identifier for the verification process.
QUO_CONTENT_GETTER(QString, transactionId)
/// The device's ephemeral public key, encoded as unpadded base64.
QUO_CONTENT_GETTER(QString, key)
};
/// Sends the MAC of a device's key to the partner device.
class QUOTIENT_API KeyVerificationMacEvent : public Event {
public:
QUO_EVENT(KeyVerificationMacEvent, "m.key.verification.mac")
using Event::Event;
KeyVerificationMacEvent(const QString& transactionId, const QString& keys,
const QJsonObject& mac)
: KeyVerificationMacEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId },
{ "keys"_ls, keys },
{ "mac"_ls, mac } }))
{}
/// An opaque identifier for the verification process.
QUO_CONTENT_GETTER(QString, transactionId)
/// The device's ephemeral public key, encoded as unpadded base64.
QUO_CONTENT_GETTER(QString, keys)
QHash<QString, QString> mac() const
{
return contentPart<QHash<QString, QString>>("mac"_ls);
}
};
class QUOTIENT_API KeyVerificationDoneEvent : public Event {
public:
QUO_EVENT(KeyVerificationDoneEvent, "m.key.verification.done")
using Event::Event;
explicit KeyVerificationDoneEvent(const QString& transactionId)
: KeyVerificationDoneEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId } }))
{}
/// The same transactionId as before
QUO_CONTENT_GETTER(QString, transactionId)
};
} // namespace Quotient
|