1#include <cstdint>
2#include <string>
3
4#include <nlohmann/json.hpp>
5
6#include "mtx/events/encrypted.hpp"
7
8static constexpr auto OLM_ALGO = "m.olm.v1.curve25519-aes-sha2";
9
10namespace mtx {
11namespace events {
12namespace msg {
13
14void
15to_json(nlohmann::json &obj, const SASMethods &method)
16{
17 switch (method) {
18 case SASMethods::Decimal:
19 obj = "decimal";
20 break;
21 case SASMethods::Emoji:
22 obj = "emoji";
23 break;
24 case SASMethods::Unsupported:
25 default:
26 obj = "unsupported";
27 break;
28 }
29}
30
31void
32from_json(const nlohmann::json &obj, SASMethods &method)
33{
34 if (obj.get<std::string>() == "decimal")
35 method = SASMethods::Decimal;
36 else if (obj.get<std::string>() == "emoji")
37 method = SASMethods::Emoji;
38 else
39 method = SASMethods::Unsupported;
40}
41
42void
43to_json(nlohmann::json &obj, const VerificationMethods &method)
44{
45 switch (method) {
46 case VerificationMethods::SASv1:
47 obj = "m.sas.v1";
48 break;
49 case VerificationMethods::Unsupported:
50 default:
51 obj = "unsupported";
52 break;
53 }
54}
55
56void
57from_json(const nlohmann::json &obj, VerificationMethods &method)
58{
59 if (obj.get<std::string>() == "m.sas.v1")
60 method = VerificationMethods::SASv1;
61 else
62 method = VerificationMethods::Unsupported;
63}
64
65void
66from_json(const nlohmann::json &obj, OlmCipherContent &msg)
67{
68 msg.body = obj.at(key: "body").get<std::string>();
69 msg.type = obj.at(key: "type").get<uint8_t>();
70}
71
72void
73to_json(nlohmann::json &obj, const OlmCipherContent &msg)
74{
75 obj["body"] = msg.body;
76 obj["type"] = msg.type;
77}
78
79void
80from_json(const nlohmann::json &obj, OlmEncrypted &msg)
81{
82 msg.algorithm = OLM_ALGO;
83 msg.sender_key = obj.at(key: "sender_key").get<std::string>();
84 msg.ciphertext =
85 obj.at(key: "ciphertext").get<std::map<OlmEncrypted::RecipientKey, OlmCipherContent>>();
86}
87
88void
89to_json(nlohmann::json &obj, const OlmEncrypted &msg)
90{
91 obj["algorithm"] = msg.algorithm;
92 obj["sender_key"] = msg.sender_key;
93 obj["ciphertext"] = msg.ciphertext;
94}
95
96void
97from_json(const nlohmann::json &obj, Encrypted &content)
98{
99 content.algorithm = obj.at(key: "algorithm").get<std::string>();
100 content.ciphertext = obj.at(key: "ciphertext").get<std::string>();
101 content.session_id = obj.at(key: "session_id").get<std::string>();
102
103 // MSC3700
104 content.device_id = obj.value(key: "device_id", default_value: "");
105 content.sender_key = obj.value(key: "sender_key", default_value: "");
106
107 content.relations = common::parse_relations(obj);
108}
109
110void
111to_json(nlohmann::json &obj, const Encrypted &content)
112{
113 obj["algorithm"] = content.algorithm;
114 obj["ciphertext"] = content.ciphertext;
115
116 // MSC3700
117 if (!content.device_id.empty())
118 obj["device_id"] = content.device_id;
119 if (!content.sender_key.empty())
120 obj["sender_key"] = content.sender_key;
121
122 obj["session_id"] = content.session_id;
123
124 // For encrypted events, only add releations, don't generate new_content and friends
125 common::add_relations(obj, relations: content.relations);
126}
127
128void
129from_json(const nlohmann::json &, Dummy &)
130{
131}
132
133void
134to_json(nlohmann::json &obj, const Dummy &)
135{
136 obj = nlohmann::json::object();
137}
138
139void
140from_json(const nlohmann::json &obj, RoomKey &event)
141{
142 event.algorithm = obj.at(key: "algorithm").get<std::string>();
143 event.room_id = obj.at(key: "room_id").get<std::string>();
144 event.session_id = obj.at(key: "session_id").get<std::string>();
145 event.session_key = obj.at(key: "session_key").get<std::string>();
146}
147
148void
149to_json(nlohmann::json &obj, const RoomKey &event)
150{
151 obj["algorithm"] = event.algorithm;
152 obj["room_id"] = event.room_id;
153 obj["session_id"] = event.session_id;
154 obj["session_key"] = event.session_key;
155}
156
157void
158from_json(const nlohmann::json &obj, ForwardedRoomKey &event)
159{
160 event.algorithm = obj.at(key: "algorithm").get<std::string>();
161 event.room_id = obj.at(key: "room_id").get<std::string>();
162 event.session_id = obj.at(key: "session_id").get<std::string>();
163 event.session_key = obj.at(key: "session_key").get<std::string>();
164 event.sender_key = obj.at(key: "sender_key").get<std::string>();
165 event.sender_claimed_ed25519_key = obj.at(key: "sender_claimed_ed25519_key").get<std::string>();
166 event.forwarding_curve25519_key_chain =
167 obj.at(key: "forwarding_curve25519_key_chain").get<std::vector<std::string>>();
168}
169
170void
171to_json(nlohmann::json &obj, const ForwardedRoomKey &event)
172{
173 obj["algorithm"] = event.algorithm;
174 obj["room_id"] = event.room_id;
175 obj["session_id"] = event.session_id;
176 obj["session_key"] = event.session_key;
177 obj["sender_key"] = event.sender_key;
178 obj["sender_claimed_ed25519_key"] = event.sender_claimed_ed25519_key;
179 obj["forwarding_curve25519_key_chain"] = event.forwarding_curve25519_key_chain;
180}
181
182void
183from_json(const nlohmann::json &obj, KeyRequest &event)
184{
185 event.request_id = obj.at(key: "request_id").get<std::string>();
186 event.requesting_device_id = obj.at(key: "requesting_device_id").get<std::string>();
187
188 auto action = obj.at(key: "action").get<std::string>();
189 if (action == "request") {
190 event.action = RequestAction::Request;
191 event.room_id = obj.at(key: "body").at(key: "room_id").get<std::string>();
192 event.sender_key = obj.at(key: "body").value(key: "sender_key", default_value: "");
193 event.session_id = obj.at(key: "body").at(key: "session_id").get<std::string>();
194 event.algorithm = obj.at(key: "body").at(key: "algorithm").get<std::string>();
195 } else if (action == "request_cancellation") {
196 event.action = RequestAction::Cancellation;
197 }
198}
199
200void
201to_json(nlohmann::json &obj, const KeyRequest &event)
202{
203 obj = nlohmann::json::object();
204
205 obj = nlohmann::json::object();
206
207 obj["request_id"] = event.request_id;
208 obj["requesting_device_id"] = event.requesting_device_id;
209
210 switch (event.action) {
211 case RequestAction::Request: {
212 obj["body"] = nlohmann::json::object();
213
214 obj["body"]["room_id"] = event.room_id;
215
216 // MSC3070
217 if (!event.sender_key.empty())
218 obj["body"]["sender_key"] = event.sender_key;
219
220 obj["body"]["session_id"] = event.session_id;
221 obj["body"]["algorithm"] = "m.megolm.v1.aes-sha2";
222
223 obj["action"] = "request";
224 break;
225 }
226 case RequestAction::Cancellation: {
227 obj["action"] = "request_cancellation";
228 break;
229 }
230 default:
231 break;
232 }
233}
234
235void
236from_json(const nlohmann::json &obj, KeyVerificationRequest &event)
237{
238 if (obj.count(key: "body") != 0) {
239 event.body = obj.at(key: "body").get<std::string>();
240 }
241 event.from_device = obj.at(key: "from_device").get<std::string>();
242 event.methods = obj.at(key: "methods").get<std::vector<VerificationMethods>>();
243 if (obj.count(key: "timestamp") != 0) {
244 event.timestamp = obj.at(key: "timestamp").get<uint64_t>();
245 }
246 if (obj.count(key: "msgtype") != 0) {
247 event.msgtype = obj.at(key: "msgtype").get<std::string>();
248 }
249 if (obj.count(key: "to") != 0) {
250 event.to = obj.at(key: "to").get<std::string>();
251 }
252 if (obj.count(key: "transaction_id") != 0) {
253 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
254 }
255}
256
257void
258to_json(nlohmann::json &obj, const KeyVerificationRequest &event)
259{
260 if (event.body.has_value())
261 obj["body"] = event.body.value();
262 obj["from_device"] = event.from_device;
263 obj["methods"] = event.methods;
264 if (event.msgtype.has_value())
265 obj["msgtype"] = "m.key.verification.request";
266 if (event.timestamp.has_value())
267 obj["timestamp"] = event.timestamp.value();
268 if (event.to.has_value())
269 obj["to"] = event.to.value();
270 if (event.transaction_id.has_value())
271 obj["transaction_id"] = event.transaction_id.value();
272}
273
274void
275from_json(const nlohmann::json &obj, KeyVerificationStart &event)
276{
277 event.from_device = obj.at(key: "from_device").get<std::string>();
278 if (obj.count(key: "transaction_id") != 0) {
279 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
280 }
281 event.method = obj.at(key: "method").get<VerificationMethods>();
282 if (obj.count(key: "next_method") != 0) {
283 event.next_method = obj.at(key: "next_method").get<std::string>();
284 }
285 event.key_agreement_protocols =
286 obj.at(key: "key_agreement_protocols").get<std::vector<std::string>>();
287 event.hashes = obj.at(key: "hashes").get<std::vector<std::string>>();
288 event.message_authentication_codes =
289 obj.at(key: "message_authentication_codes").get<std::vector<std::string>>();
290 event.short_authentication_string =
291 obj.at(key: "short_authentication_string").get<std::vector<SASMethods>>();
292 event.relations = common::parse_relations(obj);
293}
294
295void
296to_json(nlohmann::json &obj, const KeyVerificationStart &event)
297{
298 obj["from_device"] = event.from_device;
299 obj["method"] = event.method;
300 if (event.transaction_id.has_value())
301 obj["transaction_id"] = event.transaction_id.value();
302 if (event.next_method.has_value())
303 obj["next_method"] = event.next_method.value();
304 obj["key_agreement_protocols"] = event.key_agreement_protocols;
305 obj["hashes"] = event.hashes;
306 obj["message_authentication_codes"] = event.message_authentication_codes;
307 obj["short_authentication_string"] = event.short_authentication_string;
308 common::apply_relations(obj, relations: event.relations);
309}
310
311void
312from_json(const nlohmann::json &obj, KeyVerificationReady &event)
313{
314 if (obj.count(key: "transaction_id") != 0) {
315 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
316 }
317 event.methods = obj.at(key: "methods").get<std::vector<VerificationMethods>>();
318 event.from_device = obj.at(key: "from_device").get<std::string>();
319 event.relations = common::parse_relations(obj);
320}
321
322void
323to_json(nlohmann::json &obj, const KeyVerificationReady &event)
324{
325 obj["methods"] = event.methods;
326 if (event.transaction_id.has_value())
327 obj["transaction_id"] = event.transaction_id.value();
328 obj["from_device"] = event.from_device;
329 common::apply_relations(obj, relations: event.relations);
330}
331
332void
333from_json(const nlohmann::json &obj, KeyVerificationDone &event)
334{
335 if (obj.count(key: "transaction_id") != 0) {
336 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
337 }
338 event.relations = common::parse_relations(obj);
339}
340
341void
342to_json(nlohmann::json &obj, const KeyVerificationDone &event)
343{
344 if (event.transaction_id.has_value())
345 obj["transaction_id"] = event.transaction_id.value();
346 common::apply_relations(obj, relations: event.relations);
347}
348
349void
350from_json(const nlohmann::json &obj, KeyVerificationAccept &event)
351{
352 if (obj.count(key: "transaction_id") != 0) {
353 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
354 }
355 event.key_agreement_protocol = obj.at(key: "key_agreement_protocol").get<std::string>();
356 event.hash = obj.at(key: "hash").get<std::string>();
357 event.message_authentication_code = obj.at(key: "message_authentication_code").get<std::string>();
358 event.short_authentication_string =
359 obj.at(key: "short_authentication_string").get<std::vector<SASMethods>>();
360 event.commitment = obj.at(key: "commitment").get<std::string>();
361 event.method = obj.value(key: "method", default_value: VerificationMethods::SASv1);
362 event.relations = common::parse_relations(obj);
363}
364
365void
366to_json(nlohmann::json &obj, const KeyVerificationAccept &event)
367{
368 if (event.transaction_id.has_value())
369 obj["transaction_id"] = event.transaction_id.value();
370 obj["key_agreement_protocol"] = event.key_agreement_protocol;
371 obj["hash"] = event.hash;
372 obj["message_authentication_code"] = event.message_authentication_code;
373 obj["short_authentication_string"] = event.short_authentication_string;
374 obj["commitment"] = event.commitment;
375 obj["method"] = event.method;
376 common::apply_relations(obj, relations: event.relations);
377}
378
379void
380from_json(const nlohmann::json &obj, KeyVerificationCancel &event)
381{
382 if (obj.count(key: "transaction_id") != 0) {
383 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
384 }
385 event.reason = obj.value(key: "reason", default_value: "");
386 event.code = obj.value(key: "code", default_value: "");
387 event.relations = common::parse_relations(obj);
388}
389
390void
391to_json(nlohmann::json &obj, const KeyVerificationCancel &event)
392{
393 if (event.transaction_id.has_value())
394 obj["transaction_id"] = event.transaction_id.value();
395 obj["reason"] = event.reason;
396 obj["code"] = event.code;
397 common::apply_relations(obj, relations: event.relations);
398}
399
400void
401from_json(const nlohmann::json &obj, KeyVerificationKey &event)
402{
403 if (obj.count(key: "transaction_id") != 0) {
404 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
405 }
406 event.key = obj.at(key: "key").get<std::string>();
407 event.relations = common::parse_relations(obj);
408}
409
410void
411to_json(nlohmann::json &obj, const KeyVerificationKey &event)
412{
413 if (event.transaction_id.has_value())
414 obj["transaction_id"] = event.transaction_id.value();
415 obj["key"] = event.key;
416 common::apply_relations(obj, relations: event.relations);
417}
418
419void
420from_json(const nlohmann::json &obj, KeyVerificationMac &event)
421{
422 if (obj.count(key: "transaction_id") != 0) {
423 event.transaction_id = obj.at(key: "transaction_id").get<std::string>();
424 }
425 event.mac = obj.at(key: "mac").get<std::map<std::string, std::string>>();
426 event.keys = obj.at(key: "keys").get<std::string>();
427 event.relations = common::parse_relations(obj);
428}
429
430void
431to_json(nlohmann::json &obj, const KeyVerificationMac &event)
432{
433 if (event.transaction_id.has_value())
434 obj["transaction_id"] = event.transaction_id.value();
435 obj["mac"] = event.mac;
436 obj["keys"] = event.keys;
437 common::apply_relations(obj, relations: event.relations);
438}
439
440void
441from_json(const nlohmann::json &obj, SecretRequest &event)
442{
443 event.action = RequestAction::Unknown;
444 auto action = obj.value(key: "action", default_value: "");
445 if (action == "request") {
446 event.action = RequestAction::Request;
447 } else if (action == "request_cancellation") {
448 event.action = RequestAction::Cancellation;
449 }
450
451 event.name = obj.value(key: "name", default_value: "");
452
453 event.request_id = obj.value(key: "request_id", default_value: "");
454 event.requesting_device_id = obj.value(key: "requesting_device_id", default_value: "");
455}
456
457void
458to_json(nlohmann::json &obj, const SecretRequest &event)
459{
460 switch (event.action) {
461 case RequestAction::Request:
462 obj["action"] = "request";
463 break;
464 case RequestAction::Cancellation:
465 obj["action"] = "request_cancellation";
466 break;
467 default:
468 throw std::invalid_argument("Unknown secret request action type");
469 }
470
471 if (!event.name.empty())
472 obj["name"] = event.name;
473
474 obj["request_id"] = event.request_id;
475 obj["requesting_device_id"] = event.requesting_device_id;
476}
477
478void
479from_json(const nlohmann::json &obj, SecretSend &event)
480{
481 event.request_id = obj.value(key: "request_id", default_value: "");
482 event.secret = obj.value(key: "secret", default_value: "");
483}
484
485void
486to_json(nlohmann::json &obj, const SecretSend &event)
487{
488 obj["request_id"] = event.request_id;
489 obj["secret"] = event.secret;
490}
491} // namespace msg
492} // namespace events
493} // namespace mtx
494