matrix_sdk_crypto/verification/
event_enums.rs

1// Copyright 2020 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::BTreeMap;
16
17use as_variant::as_variant;
18use ruma::{
19    events::{
20        key::verification::{
21            accept::{
22                AcceptMethod, KeyVerificationAcceptEventContent,
23                ToDeviceKeyVerificationAcceptEventContent,
24            },
25            cancel::{
26                CancelCode, KeyVerificationCancelEventContent,
27                ToDeviceKeyVerificationCancelEventContent,
28            },
29            done::{KeyVerificationDoneEventContent, ToDeviceKeyVerificationDoneEventContent},
30            key::{KeyVerificationKeyEventContent, ToDeviceKeyVerificationKeyEventContent},
31            mac::{KeyVerificationMacEventContent, ToDeviceKeyVerificationMacEventContent},
32            ready::{KeyVerificationReadyEventContent, ToDeviceKeyVerificationReadyEventContent},
33            request::ToDeviceKeyVerificationRequestEventContent,
34            start::{
35                KeyVerificationStartEventContent, StartMethod,
36                ToDeviceKeyVerificationStartEventContent,
37            },
38            VerificationMethod,
39        },
40        room::message::{KeyVerificationRequestEventContent, MessageType},
41        AnyMessageLikeEvent, AnyMessageLikeEventContent, AnyToDeviceEventContent, MessageLikeEvent,
42    },
43    serde::Base64,
44    CanonicalJsonValue, DeviceId, MilliSecondsSinceUnixEpoch, OwnedRoomId, UserId,
45};
46
47use super::FlowId;
48
49#[derive(Debug)]
50pub enum AnyEvent<'a> {
51    Room(&'a AnyMessageLikeEvent),
52    ToDevice(&'a ToDeviceEvents),
53}
54
55impl AnyEvent<'_> {
56    pub fn event_type(&self) -> String {
57        match self {
58            Self::Room(e) => e.event_type().to_string(),
59            Self::ToDevice(e) => e.event_type().to_string(),
60        }
61    }
62
63    pub fn sender(&self) -> &UserId {
64        match self {
65            Self::Room(e) => e.sender(),
66            Self::ToDevice(e) => e.sender(),
67        }
68    }
69
70    pub fn timestamp(&self) -> Option<MilliSecondsSinceUnixEpoch> {
71        match self {
72            AnyEvent::Room(e) => Some(e.origin_server_ts()),
73            AnyEvent::ToDevice(e) => {
74                as_variant!(e, ToDeviceEvents::KeyVerificationRequest(e) => e.content.timestamp)
75            }
76        }
77    }
78
79    pub fn is_room_event(&self) -> bool {
80        matches!(self, AnyEvent::Room(_))
81    }
82
83    pub fn verification_content(&self) -> Option<AnyVerificationContent<'_>> {
84        match self {
85            AnyEvent::Room(e) => match e {
86                AnyMessageLikeEvent::RoomMessage(MessageLikeEvent::Original(m)) => {
87                    as_variant!(&m.content.msgtype, MessageType::VerificationRequest)
88                        .map(|v| RequestContent::from(v).into())
89                }
90                AnyMessageLikeEvent::KeyVerificationReady(MessageLikeEvent::Original(e)) => {
91                    Some(ReadyContent::from(&e.content).into())
92                }
93                AnyMessageLikeEvent::KeyVerificationStart(MessageLikeEvent::Original(e)) => {
94                    Some(StartContent::from(&e.content).into())
95                }
96                AnyMessageLikeEvent::KeyVerificationCancel(MessageLikeEvent::Original(e)) => {
97                    Some(CancelContent::from(&e.content).into())
98                }
99                AnyMessageLikeEvent::KeyVerificationAccept(MessageLikeEvent::Original(e)) => {
100                    Some(AcceptContent::from(&e.content).into())
101                }
102                AnyMessageLikeEvent::KeyVerificationKey(MessageLikeEvent::Original(e)) => {
103                    Some(KeyContent::from(&e.content).into())
104                }
105                AnyMessageLikeEvent::KeyVerificationMac(MessageLikeEvent::Original(e)) => {
106                    Some(MacContent::from(&e.content).into())
107                }
108                AnyMessageLikeEvent::KeyVerificationDone(MessageLikeEvent::Original(e)) => {
109                    Some(DoneContent::from(&e.content).into())
110                }
111                _ => None,
112            },
113            AnyEvent::ToDevice(e) => match e {
114                ToDeviceEvents::KeyVerificationRequest(e) => {
115                    Some(RequestContent::from(&e.content).into())
116                }
117                ToDeviceEvents::KeyVerificationReady(e) => {
118                    Some(ReadyContent::from(&e.content).into())
119                }
120                ToDeviceEvents::KeyVerificationStart(e) => {
121                    Some(StartContent::from(&e.content).into())
122                }
123                ToDeviceEvents::KeyVerificationCancel(e) => {
124                    Some(CancelContent::from(&e.content).into())
125                }
126                ToDeviceEvents::KeyVerificationAccept(e) => {
127                    Some(AcceptContent::from(&e.content).into())
128                }
129                ToDeviceEvents::KeyVerificationKey(e) => Some(KeyContent::from(&e.content).into()),
130                ToDeviceEvents::KeyVerificationMac(e) => Some(MacContent::from(&e.content).into()),
131                ToDeviceEvents::KeyVerificationDone(e) => {
132                    Some(DoneContent::from(&e.content).into())
133                }
134                _ => None,
135            },
136        }
137    }
138}
139
140impl<'a> From<&'a AnyMessageLikeEvent> for AnyEvent<'a> {
141    fn from(e: &'a AnyMessageLikeEvent) -> Self {
142        Self::Room(e)
143    }
144}
145
146impl<'a> From<&'a ToDeviceEvents> for AnyEvent<'a> {
147    fn from(e: &'a ToDeviceEvents) -> Self {
148        Self::ToDevice(e)
149    }
150}
151
152impl TryFrom<&AnyEvent<'_>> for FlowId {
153    type Error = ();
154
155    fn try_from(value: &AnyEvent<'_>) -> Result<Self, Self::Error> {
156        match value {
157            AnyEvent::Room(e) => FlowId::try_from(*e),
158            AnyEvent::ToDevice(e) => FlowId::try_from(*e),
159        }
160    }
161}
162
163impl TryFrom<&AnyMessageLikeEvent> for FlowId {
164    type Error = ();
165
166    fn try_from(value: &AnyMessageLikeEvent) -> Result<Self, Self::Error> {
167        match value {
168            AnyMessageLikeEvent::KeyVerificationReady(MessageLikeEvent::Original(e)) => {
169                Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
170            }
171            AnyMessageLikeEvent::RoomMessage(MessageLikeEvent::Original(e)) => {
172                Ok(FlowId::from((&*e.room_id, &*e.event_id)))
173            }
174            AnyMessageLikeEvent::KeyVerificationStart(MessageLikeEvent::Original(e)) => {
175                Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
176            }
177            AnyMessageLikeEvent::KeyVerificationCancel(MessageLikeEvent::Original(e)) => {
178                Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
179            }
180            AnyMessageLikeEvent::KeyVerificationAccept(MessageLikeEvent::Original(e)) => {
181                Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
182            }
183            AnyMessageLikeEvent::KeyVerificationKey(MessageLikeEvent::Original(e)) => {
184                Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
185            }
186            AnyMessageLikeEvent::KeyVerificationMac(MessageLikeEvent::Original(e)) => {
187                Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
188            }
189            AnyMessageLikeEvent::KeyVerificationDone(MessageLikeEvent::Original(e)) => {
190                Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
191            }
192            _ => Err(()),
193        }
194    }
195}
196
197impl TryFrom<&ToDeviceEvents> for FlowId {
198    type Error = ();
199
200    fn try_from(value: &ToDeviceEvents) -> Result<Self, Self::Error> {
201        match value {
202            ToDeviceEvents::KeyVerificationRequest(e) => {
203                Ok(FlowId::from(e.content.transaction_id.to_owned()))
204            }
205            ToDeviceEvents::KeyVerificationReady(e) => {
206                Ok(FlowId::from(e.content.transaction_id.to_owned()))
207            }
208            ToDeviceEvents::KeyVerificationStart(e) => {
209                Ok(FlowId::from(e.content.transaction_id.to_owned()))
210            }
211            ToDeviceEvents::KeyVerificationCancel(e) => {
212                Ok(FlowId::from(e.content.transaction_id.to_owned()))
213            }
214            ToDeviceEvents::KeyVerificationAccept(e) => {
215                Ok(FlowId::from(e.content.transaction_id.to_owned()))
216            }
217            ToDeviceEvents::KeyVerificationKey(e) => {
218                Ok(FlowId::from(e.content.transaction_id.to_owned()))
219            }
220            ToDeviceEvents::KeyVerificationMac(e) => {
221                Ok(FlowId::from(e.content.transaction_id.to_owned()))
222            }
223            ToDeviceEvents::KeyVerificationDone(e) => {
224                Ok(FlowId::from(e.content.transaction_id.to_owned()))
225            }
226            _ => Err(()),
227        }
228    }
229}
230
231#[derive(Debug)]
232pub enum AnyVerificationContent<'a> {
233    Request(RequestContent<'a>),
234    Ready(ReadyContent<'a>),
235    Cancel(CancelContent<'a>),
236    Start(StartContent<'a>),
237    Done(DoneContent<'a>),
238    Accept(AcceptContent<'a>),
239    Key(KeyContent<'a>),
240    Mac(MacContent<'a>),
241}
242
243#[derive(Debug)]
244pub enum RequestContent<'a> {
245    ToDevice(&'a ToDeviceKeyVerificationRequestEventContent),
246    Room(&'a KeyVerificationRequestEventContent),
247}
248
249impl RequestContent<'_> {
250    #[allow(clippy::wrong_self_convention)]
251    pub fn from_device(&self) -> &DeviceId {
252        match self {
253            Self::ToDevice(t) => &t.from_device,
254            Self::Room(r) => &r.from_device,
255        }
256    }
257
258    pub fn methods(&self) -> &[VerificationMethod] {
259        match self {
260            Self::ToDevice(t) => &t.methods,
261            Self::Room(r) => &r.methods,
262        }
263    }
264}
265
266#[derive(Debug)]
267pub enum ReadyContent<'a> {
268    ToDevice(&'a ToDeviceKeyVerificationReadyEventContent),
269    Room(&'a KeyVerificationReadyEventContent),
270}
271
272impl ReadyContent<'_> {
273    #[allow(clippy::wrong_self_convention)]
274    pub fn from_device(&self) -> &DeviceId {
275        match self {
276            Self::ToDevice(t) => &t.from_device,
277            Self::Room(r) => &r.from_device,
278        }
279    }
280
281    pub fn methods(&self) -> &[VerificationMethod] {
282        match self {
283            Self::ToDevice(t) => &t.methods,
284            Self::Room(r) => &r.methods,
285        }
286    }
287}
288
289macro_rules! from_for_enum {
290    ($type: ident, $enum_variant: ident, $enum: ident) => {
291        impl<'a> From<$type<'a>> for $enum<'a> {
292            fn from(c: $type<'a>) -> Self {
293                Self::$enum_variant(c)
294            }
295        }
296    };
297}
298
299macro_rules! from_borrow_for_enum {
300    ($type: ident, $enum_variant: ident, $enum: ident) => {
301        impl<'a> From<&'a $type> for $enum<'a> {
302            fn from(c: &'a $type) -> Self {
303                Self::$enum_variant(c)
304            }
305        }
306    };
307}
308
309from_for_enum!(RequestContent, Request, AnyVerificationContent);
310from_for_enum!(ReadyContent, Ready, AnyVerificationContent);
311from_for_enum!(CancelContent, Cancel, AnyVerificationContent);
312from_for_enum!(StartContent, Start, AnyVerificationContent);
313from_for_enum!(DoneContent, Done, AnyVerificationContent);
314from_for_enum!(AcceptContent, Accept, AnyVerificationContent);
315from_for_enum!(KeyContent, Key, AnyVerificationContent);
316from_for_enum!(MacContent, Mac, AnyVerificationContent);
317
318from_borrow_for_enum!(ToDeviceKeyVerificationRequestEventContent, ToDevice, RequestContent);
319from_borrow_for_enum!(KeyVerificationRequestEventContent, Room, RequestContent);
320from_borrow_for_enum!(KeyVerificationReadyEventContent, Room, ReadyContent);
321from_borrow_for_enum!(ToDeviceKeyVerificationReadyEventContent, ToDevice, ReadyContent);
322from_borrow_for_enum!(KeyVerificationStartEventContent, Room, StartContent);
323from_borrow_for_enum!(ToDeviceKeyVerificationStartEventContent, ToDevice, StartContent);
324from_borrow_for_enum!(KeyVerificationAcceptEventContent, Room, AcceptContent);
325from_borrow_for_enum!(ToDeviceKeyVerificationAcceptEventContent, ToDevice, AcceptContent);
326from_borrow_for_enum!(KeyVerificationKeyEventContent, Room, KeyContent);
327from_borrow_for_enum!(ToDeviceKeyVerificationKeyEventContent, ToDevice, KeyContent);
328from_borrow_for_enum!(KeyVerificationMacEventContent, Room, MacContent);
329from_borrow_for_enum!(ToDeviceKeyVerificationMacEventContent, ToDevice, MacContent);
330from_borrow_for_enum!(KeyVerificationCancelEventContent, Room, CancelContent);
331from_borrow_for_enum!(ToDeviceKeyVerificationCancelEventContent, ToDevice, CancelContent);
332
333macro_rules! try_from_outgoing_content {
334    ($type: ident, $enum_variant: ident) => {
335        impl<'a> TryFrom<&'a OutgoingContent> for $type<'a> {
336            type Error = ();
337
338            fn try_from(value: &'a OutgoingContent) -> Result<Self, Self::Error> {
339                match value {
340                    OutgoingContent::Room(_, c) => {
341                        if let AnyMessageLikeEventContent::$enum_variant(c) = c {
342                            Ok(Self::Room(c))
343                        } else {
344                            Err(())
345                        }
346                    }
347                    OutgoingContent::ToDevice(c) => {
348                        if let AnyToDeviceEventContent::$enum_variant(c) = c {
349                            Ok(Self::ToDevice(c))
350                        } else {
351                            Err(())
352                        }
353                    }
354                }
355            }
356        }
357    };
358}
359
360try_from_outgoing_content!(ReadyContent, KeyVerificationReady);
361try_from_outgoing_content!(StartContent, KeyVerificationStart);
362try_from_outgoing_content!(AcceptContent, KeyVerificationAccept);
363try_from_outgoing_content!(KeyContent, KeyVerificationKey);
364try_from_outgoing_content!(MacContent, KeyVerificationMac);
365try_from_outgoing_content!(CancelContent, KeyVerificationCancel);
366try_from_outgoing_content!(DoneContent, KeyVerificationDone);
367
368impl<'a> TryFrom<&'a OutgoingContent> for RequestContent<'a> {
369    type Error = ();
370
371    fn try_from(value: &'a OutgoingContent) -> Result<Self, Self::Error> {
372        match value {
373            OutgoingContent::Room(_, c) => {
374                if let AnyMessageLikeEventContent::RoomMessage(m) = c {
375                    if let MessageType::VerificationRequest(c) = &m.msgtype {
376                        Ok(Self::Room(c))
377                    } else {
378                        Err(())
379                    }
380                } else {
381                    Err(())
382                }
383            }
384            OutgoingContent::ToDevice(c) => {
385                if let AnyToDeviceEventContent::KeyVerificationRequest(c) = c {
386                    Ok(Self::ToDevice(c))
387                } else {
388                    Err(())
389                }
390            }
391        }
392    }
393}
394
395#[derive(Debug)]
396pub enum StartContent<'a> {
397    ToDevice(&'a ToDeviceKeyVerificationStartEventContent),
398    Room(&'a KeyVerificationStartEventContent),
399}
400
401impl StartContent<'_> {
402    #[allow(clippy::wrong_self_convention)]
403    pub fn from_device(&self) -> &DeviceId {
404        match self {
405            Self::ToDevice(c) => &c.from_device,
406            Self::Room(c) => &c.from_device,
407        }
408    }
409
410    pub fn flow_id(&self) -> &str {
411        match self {
412            Self::ToDevice(c) => c.transaction_id.as_str(),
413            Self::Room(c) => c.relates_to.event_id.as_str(),
414        }
415    }
416
417    pub fn method(&self) -> &StartMethod {
418        match self {
419            Self::ToDevice(c) => &c.method,
420            Self::Room(c) => &c.method,
421        }
422    }
423
424    pub fn canonical_json(&self) -> CanonicalJsonValue {
425        let content = match self {
426            Self::ToDevice(c) => serde_json::to_value(c),
427            Self::Room(c) => serde_json::to_value(c),
428        };
429
430        content.expect("Can't serialize content").try_into().expect("Can't canonicalize content")
431    }
432}
433
434impl<'a> From<&'a OwnedStartContent> for StartContent<'a> {
435    fn from(c: &'a OwnedStartContent) -> Self {
436        match c {
437            OwnedStartContent::ToDevice(c) => Self::ToDevice(c),
438            OwnedStartContent::Room(_, c) => Self::Room(c),
439        }
440    }
441}
442
443#[derive(Debug)]
444pub enum DoneContent<'a> {
445    ToDevice(&'a ToDeviceKeyVerificationDoneEventContent),
446    Room(&'a KeyVerificationDoneEventContent),
447}
448
449impl<'a> From<&'a KeyVerificationDoneEventContent> for DoneContent<'a> {
450    fn from(c: &'a KeyVerificationDoneEventContent) -> Self {
451        Self::Room(c)
452    }
453}
454
455impl<'a> From<&'a ToDeviceKeyVerificationDoneEventContent> for DoneContent<'a> {
456    fn from(c: &'a ToDeviceKeyVerificationDoneEventContent) -> Self {
457        Self::ToDevice(c)
458    }
459}
460
461impl DoneContent<'_> {
462    pub fn flow_id(&self) -> &str {
463        match self {
464            Self::ToDevice(c) => c.transaction_id.as_str(),
465            Self::Room(c) => c.relates_to.event_id.as_str(),
466        }
467    }
468}
469
470#[derive(Clone, Debug)]
471pub enum AcceptContent<'a> {
472    ToDevice(&'a ToDeviceKeyVerificationAcceptEventContent),
473    Room(&'a KeyVerificationAcceptEventContent),
474}
475
476impl AcceptContent<'_> {
477    pub fn flow_id(&self) -> &str {
478        match self {
479            Self::ToDevice(c) => c.transaction_id.as_str(),
480            Self::Room(c) => c.relates_to.event_id.as_str(),
481        }
482    }
483
484    pub fn method(&self) -> &AcceptMethod {
485        match self {
486            Self::ToDevice(c) => &c.method,
487            Self::Room(c) => &c.method,
488        }
489    }
490}
491
492impl<'a> From<&'a OwnedAcceptContent> for AcceptContent<'a> {
493    fn from(content: &'a OwnedAcceptContent) -> Self {
494        match content {
495            OwnedAcceptContent::ToDevice(c) => Self::ToDevice(c),
496            OwnedAcceptContent::Room(_, c) => Self::Room(c),
497        }
498    }
499}
500
501#[derive(Clone, Debug)]
502pub enum KeyContent<'a> {
503    ToDevice(&'a ToDeviceKeyVerificationKeyEventContent),
504    Room(&'a KeyVerificationKeyEventContent),
505}
506
507impl KeyContent<'_> {
508    pub fn flow_id(&self) -> &str {
509        match self {
510            Self::ToDevice(c) => c.transaction_id.as_str(),
511            Self::Room(c) => c.relates_to.event_id.as_str(),
512        }
513    }
514
515    pub fn public_key(&self) -> &Base64 {
516        match self {
517            Self::ToDevice(c) => &c.key,
518            Self::Room(c) => &c.key,
519        }
520    }
521}
522
523#[derive(Clone, Debug)]
524pub enum MacContent<'a> {
525    ToDevice(&'a ToDeviceKeyVerificationMacEventContent),
526    Room(&'a KeyVerificationMacEventContent),
527}
528
529impl MacContent<'_> {
530    pub fn flow_id(&self) -> &str {
531        match self {
532            Self::ToDevice(c) => c.transaction_id.as_str(),
533            Self::Room(c) => c.relates_to.event_id.as_str(),
534        }
535    }
536
537    pub fn mac(&self) -> &BTreeMap<String, Base64> {
538        match self {
539            Self::ToDevice(c) => &c.mac,
540            Self::Room(c) => &c.mac,
541        }
542    }
543
544    pub fn keys(&self) -> &Base64 {
545        match self {
546            Self::ToDevice(c) => &c.keys,
547            Self::Room(c) => &c.keys,
548        }
549    }
550}
551
552#[derive(Clone, Debug)]
553pub enum CancelContent<'a> {
554    ToDevice(&'a ToDeviceKeyVerificationCancelEventContent),
555    Room(&'a KeyVerificationCancelEventContent),
556}
557
558impl CancelContent<'_> {
559    pub fn cancel_code(&self) -> &CancelCode {
560        match self {
561            Self::ToDevice(c) => &c.code,
562            Self::Room(c) => &c.code,
563        }
564    }
565}
566
567#[derive(Clone, Debug)]
568pub enum OwnedStartContent {
569    ToDevice(ToDeviceKeyVerificationStartEventContent),
570    Room(OwnedRoomId, KeyVerificationStartEventContent),
571}
572
573impl OwnedStartContent {
574    pub fn method(&self) -> &StartMethod {
575        match self {
576            Self::ToDevice(c) => &c.method,
577            Self::Room(_, c) => &c.method,
578        }
579    }
580
581    pub fn method_mut(&mut self) -> &mut StartMethod {
582        match self {
583            Self::ToDevice(c) => &mut c.method,
584            Self::Room(_, c) => &mut c.method,
585        }
586    }
587
588    pub fn as_start_content(&self) -> StartContent<'_> {
589        match self {
590            Self::ToDevice(c) => StartContent::ToDevice(c),
591            Self::Room(_, c) => StartContent::Room(c),
592        }
593    }
594
595    pub fn flow_id(&self) -> FlowId {
596        match self {
597            Self::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
598            Self::Room(r, c) => FlowId::InRoom(r.clone(), c.relates_to.event_id.clone()),
599        }
600    }
601
602    pub fn canonical_json(self) -> CanonicalJsonValue {
603        let content = match self {
604            Self::ToDevice(c) => serde_json::to_value(c),
605            Self::Room(_, c) => serde_json::to_value(c),
606        };
607
608        content.expect("Can't serialize content").try_into().expect("Can't canonicalize content")
609    }
610}
611
612impl From<(OwnedRoomId, KeyVerificationStartEventContent)> for OwnedStartContent {
613    fn from(tuple: (OwnedRoomId, KeyVerificationStartEventContent)) -> Self {
614        Self::Room(tuple.0, tuple.1)
615    }
616}
617
618impl From<ToDeviceKeyVerificationStartEventContent> for OwnedStartContent {
619    fn from(content: ToDeviceKeyVerificationStartEventContent) -> Self {
620        Self::ToDevice(content)
621    }
622}
623
624#[derive(Clone, Debug)]
625pub enum OwnedAcceptContent {
626    ToDevice(ToDeviceKeyVerificationAcceptEventContent),
627    Room(OwnedRoomId, KeyVerificationAcceptEventContent),
628}
629
630impl From<ToDeviceKeyVerificationAcceptEventContent> for OwnedAcceptContent {
631    fn from(content: ToDeviceKeyVerificationAcceptEventContent) -> Self {
632        Self::ToDevice(content)
633    }
634}
635
636impl From<(OwnedRoomId, KeyVerificationAcceptEventContent)> for OwnedAcceptContent {
637    fn from(content: (OwnedRoomId, KeyVerificationAcceptEventContent)) -> Self {
638        Self::Room(content.0, content.1)
639    }
640}
641
642impl OwnedAcceptContent {
643    pub fn method_mut(&mut self) -> &mut AcceptMethod {
644        match self {
645            Self::ToDevice(c) => &mut c.method,
646            Self::Room(_, c) => &mut c.method,
647        }
648    }
649}
650
651#[derive(Clone, Debug)]
652pub enum OutgoingContent {
653    Room(OwnedRoomId, AnyMessageLikeEventContent),
654    ToDevice(AnyToDeviceEventContent),
655}
656
657impl From<OwnedStartContent> for OutgoingContent {
658    fn from(content: OwnedStartContent) -> Self {
659        match content {
660            OwnedStartContent::Room(r, c) => {
661                (r, AnyMessageLikeEventContent::KeyVerificationStart(c)).into()
662            }
663            OwnedStartContent::ToDevice(c) => {
664                AnyToDeviceEventContent::KeyVerificationStart(c).into()
665            }
666        }
667    }
668}
669
670impl From<AnyToDeviceEventContent> for OutgoingContent {
671    fn from(content: AnyToDeviceEventContent) -> Self {
672        OutgoingContent::ToDevice(content)
673    }
674}
675
676impl From<(OwnedRoomId, AnyMessageLikeEventContent)> for OutgoingContent {
677    fn from(content: (OwnedRoomId, AnyMessageLikeEventContent)) -> Self {
678        OutgoingContent::Room(content.0, content.1)
679    }
680}
681
682use crate::types::{
683    events::ToDeviceEvents,
684    requests::{OutgoingRequest, OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest},
685};
686
687impl TryFrom<OutgoingVerificationRequest> for OutgoingContent {
688    type Error = String;
689
690    fn try_from(request: OutgoingVerificationRequest) -> Result<Self, Self::Error> {
691        match request {
692            OutgoingVerificationRequest::ToDevice(r) => Self::try_from(r),
693            OutgoingVerificationRequest::InRoom(r) => Ok(Self::from(r)),
694        }
695    }
696}
697
698impl From<RoomMessageRequest> for OutgoingContent {
699    fn from(value: RoomMessageRequest) -> Self {
700        (value.room_id, value.content).into()
701    }
702}
703
704impl TryFrom<ToDeviceRequest> for OutgoingContent {
705    type Error = String;
706
707    fn try_from(request: ToDeviceRequest) -> Result<Self, Self::Error> {
708        use ruma::events::ToDeviceEventType;
709        use serde_json::Value;
710
711        let json: Value = serde_json::from_str(
712            request
713                .messages
714                .values()
715                .next()
716                .and_then(|m| m.values().next())
717                .map(|c| c.json().get())
718                .ok_or_else(|| "Content is missing from the request".to_owned())?,
719        )
720        .map_err(|e| e.to_string())?;
721
722        let content = match request.event_type {
723            ToDeviceEventType::KeyVerificationStart => {
724                AnyToDeviceEventContent::KeyVerificationStart(
725                    serde_json::from_value(json).map_err(|e| e.to_string())?,
726                )
727            }
728            ToDeviceEventType::KeyVerificationKey => AnyToDeviceEventContent::KeyVerificationKey(
729                serde_json::from_value(json).map_err(|e| e.to_string())?,
730            ),
731            ToDeviceEventType::KeyVerificationAccept => {
732                AnyToDeviceEventContent::KeyVerificationAccept(
733                    serde_json::from_value(json).map_err(|e| e.to_string())?,
734                )
735            }
736            ToDeviceEventType::KeyVerificationMac => AnyToDeviceEventContent::KeyVerificationMac(
737                serde_json::from_value(json).map_err(|e| e.to_string())?,
738            ),
739            ToDeviceEventType::KeyVerificationCancel => {
740                AnyToDeviceEventContent::KeyVerificationCancel(
741                    serde_json::from_value(json).map_err(|e| e.to_string())?,
742                )
743            }
744            ToDeviceEventType::KeyVerificationReady => {
745                AnyToDeviceEventContent::KeyVerificationReady(
746                    serde_json::from_value(json).map_err(|e| e.to_string())?,
747                )
748            }
749            ToDeviceEventType::KeyVerificationDone => AnyToDeviceEventContent::KeyVerificationDone(
750                serde_json::from_value(json).map_err(|e| e.to_string())?,
751            ),
752            ToDeviceEventType::KeyVerificationRequest => {
753                AnyToDeviceEventContent::KeyVerificationRequest(
754                    serde_json::from_value(json).map_err(|e| e.to_string())?,
755                )
756            }
757            e => return Err(format!("Unsupported event type {e}")),
758        };
759
760        Ok(content.into())
761    }
762}
763
764impl TryFrom<OutgoingRequest> for OutgoingContent {
765    type Error = String;
766
767    fn try_from(value: OutgoingRequest) -> Result<Self, Self::Error> {
768        use crate::types::requests::AnyOutgoingRequest;
769
770        match value.request() {
771            AnyOutgoingRequest::KeysUpload(_)
772            | AnyOutgoingRequest::KeysQuery(_)
773            | AnyOutgoingRequest::SignatureUpload(_)
774            | AnyOutgoingRequest::KeysClaim(_) => Err("Invalid request type".to_owned()),
775            AnyOutgoingRequest::ToDeviceRequest(r) => Self::try_from(r.clone()),
776            AnyOutgoingRequest::RoomMessage(r) => Ok(Self::from(r.clone())),
777        }
778    }
779}