1use std::{collections::BTreeMap, fmt};
16
17#[cfg(doc)]
18use ruma::events::AnyTimelineEvent;
19use ruma::{
20 events::{AnyMessageLikeEvent, AnySyncTimelineEvent},
21 push::Action,
22 serde::{
23 AsRefStr, AsStrAsRefStr, DebugAsRefStr, DeserializeFromCowStr, FromString, JsonObject, Raw,
24 SerializeAsRefStr,
25 },
26 DeviceKeyAlgorithm, OwnedDeviceId, OwnedEventId, OwnedUserId,
27};
28use serde::{Deserialize, Serialize};
29#[cfg(target_arch = "wasm32")]
30use wasm_bindgen::prelude::*;
31
32use crate::debug::{DebugRawEvent, DebugStructExt};
33
34const AUTHENTICITY_NOT_GUARANTEED: &str =
35 "The authenticity of this encrypted message can't be guaranteed on this device.";
36const UNVERIFIED_IDENTITY: &str = "Encrypted by an unverified user.";
37const VERIFICATION_VIOLATION: &str =
38 "Encrypted by a previously-verified user who is no longer verified.";
39const UNSIGNED_DEVICE: &str = "Encrypted by a device not verified by its owner.";
40const UNKNOWN_DEVICE: &str = "Encrypted by an unknown or deleted device.";
41pub const SENT_IN_CLEAR: &str = "Not encrypted.";
42
43#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
46#[serde(from = "OldVerificationStateHelper")]
47pub enum VerificationState {
48 Verified,
53
54 Unverified(VerificationLevel),
59}
60
61#[derive(Clone, Debug, Deserialize)]
64enum OldVerificationStateHelper {
65 Untrusted,
66 UnknownDevice,
67 #[serde(alias = "Trusted")]
68 Verified,
69 Unverified(VerificationLevel),
70}
71
72impl From<OldVerificationStateHelper> for VerificationState {
73 fn from(value: OldVerificationStateHelper) -> Self {
74 match value {
75 OldVerificationStateHelper::Untrusted => {
78 VerificationState::Unverified(VerificationLevel::UnsignedDevice)
79 }
80 OldVerificationStateHelper::UnknownDevice => {
81 Self::Unverified(VerificationLevel::None(DeviceLinkProblem::MissingDevice))
82 }
83 OldVerificationStateHelper::Verified => Self::Verified,
84 OldVerificationStateHelper::Unverified(l) => Self::Unverified(l),
85 }
86 }
87}
88
89impl VerificationState {
90 pub fn to_shield_state_strict(&self) -> ShieldState {
97 match self {
98 VerificationState::Verified => ShieldState::None,
99 VerificationState::Unverified(level) => match level {
100 VerificationLevel::UnverifiedIdentity
101 | VerificationLevel::VerificationViolation
102 | VerificationLevel::UnsignedDevice => ShieldState::Red {
103 code: ShieldStateCode::UnverifiedIdentity,
104 message: UNVERIFIED_IDENTITY,
105 },
106 VerificationLevel::None(link) => match link {
107 DeviceLinkProblem::MissingDevice => ShieldState::Red {
108 code: ShieldStateCode::UnknownDevice,
109 message: UNKNOWN_DEVICE,
110 },
111 DeviceLinkProblem::InsecureSource => ShieldState::Red {
112 code: ShieldStateCode::AuthenticityNotGuaranteed,
113 message: AUTHENTICITY_NOT_GUARANTEED,
114 },
115 },
116 },
117 }
118 }
119
120 pub fn to_shield_state_lax(&self) -> ShieldState {
128 match self {
129 VerificationState::Verified => ShieldState::None,
130 VerificationState::Unverified(level) => match level {
131 VerificationLevel::UnverifiedIdentity => {
132 ShieldState::None
135 }
136 VerificationLevel::VerificationViolation => {
137 ShieldState::Red {
140 code: ShieldStateCode::VerificationViolation,
141 message: VERIFICATION_VIOLATION,
142 }
143 }
144 VerificationLevel::UnsignedDevice => {
145 ShieldState::Red {
147 code: ShieldStateCode::UnsignedDevice,
148 message: UNSIGNED_DEVICE,
149 }
150 }
151 VerificationLevel::None(link) => match link {
152 DeviceLinkProblem::MissingDevice => {
153 ShieldState::Red {
157 code: ShieldStateCode::UnknownDevice,
158 message: UNKNOWN_DEVICE,
159 }
160 }
161 DeviceLinkProblem::InsecureSource => {
162 ShieldState::Grey {
165 code: ShieldStateCode::AuthenticityNotGuaranteed,
166 message: AUTHENTICITY_NOT_GUARANTEED,
167 }
168 }
169 },
170 },
171 }
172 }
173}
174
175#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
178pub enum VerificationLevel {
179 UnverifiedIdentity,
181
182 #[serde(alias = "PreviouslyVerified")]
185 VerificationViolation,
186
187 UnsignedDevice,
190
191 None(DeviceLinkProblem),
197}
198
199impl fmt::Display for VerificationLevel {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
201 let display = match self {
202 VerificationLevel::UnverifiedIdentity => "The sender's identity was not verified",
203 VerificationLevel::VerificationViolation => {
204 "The sender's identity was previously verified but has changed"
205 }
206 VerificationLevel::UnsignedDevice => {
207 "The sending device was not signed by the user's identity"
208 }
209 VerificationLevel::None(..) => "The sending device is not known",
210 };
211 write!(f, "{}", display)
212 }
213}
214
215#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
218pub enum DeviceLinkProblem {
219 MissingDevice,
223 InsecureSource,
226}
227
228#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
231pub enum ShieldState {
232 Red {
235 code: ShieldStateCode,
237 message: &'static str,
239 },
240 Grey {
243 code: ShieldStateCode,
245 message: &'static str,
247 },
248 None,
250}
251
252#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq)]
254#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
255#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
256pub enum ShieldStateCode {
257 AuthenticityNotGuaranteed,
259 UnknownDevice,
261 UnsignedDevice,
263 UnverifiedIdentity,
265 SentInClear,
267 #[serde(alias = "PreviouslyVerified")]
269 VerificationViolation,
270}
271
272#[derive(Clone, Debug, Deserialize, Serialize)]
274pub enum AlgorithmInfo {
275 MegolmV1AesSha2 {
277 curve25519_key: String,
280 sender_claimed_keys: BTreeMap<DeviceKeyAlgorithm, String>,
284 },
285}
286
287#[derive(Clone, Debug, Deserialize, Serialize)]
289pub struct EncryptionInfo {
290 pub sender: OwnedUserId,
293 pub sender_device: Option<OwnedDeviceId>,
296 pub algorithm_info: AlgorithmInfo,
298 pub verification_state: VerificationState,
305}
306
307#[derive(Clone, Debug, Serialize)]
330pub struct TimelineEvent {
331 pub kind: TimelineEventKind,
333
334 #[serde(skip_serializing_if = "Option::is_none")]
338 pub push_actions: Option<Vec<Action>>,
339}
340
341#[cfg(not(feature = "test-send-sync"))]
343unsafe impl Send for TimelineEvent {}
344
345#[cfg(not(feature = "test-send-sync"))]
347unsafe impl Sync for TimelineEvent {}
348
349#[cfg(feature = "test-send-sync")]
350#[test]
351fn test_send_sync_for_sync_timeline_event() {
353 fn assert_send_sync<T: Send + Sync>() {}
354
355 assert_send_sync::<TimelineEvent>();
356}
357
358impl TimelineEvent {
359 pub fn new(event: Raw<AnySyncTimelineEvent>) -> Self {
364 Self { kind: TimelineEventKind::PlainText { event }, push_actions: None }
365 }
366
367 pub fn new_with_push_actions(
373 event: Raw<AnySyncTimelineEvent>,
374 push_actions: Vec<Action>,
375 ) -> Self {
376 Self { kind: TimelineEventKind::PlainText { event }, push_actions: Some(push_actions) }
377 }
378
379 pub fn new_utd_event(event: Raw<AnySyncTimelineEvent>, utd_info: UnableToDecryptInfo) -> Self {
382 Self { kind: TimelineEventKind::UnableToDecrypt { event, utd_info }, push_actions: None }
383 }
384
385 pub fn event_id(&self) -> Option<OwnedEventId> {
388 self.kind.event_id()
389 }
390
391 pub fn raw(&self) -> &Raw<AnySyncTimelineEvent> {
394 self.kind.raw()
395 }
396
397 pub fn replace_raw(&mut self, replacement: Raw<AnyMessageLikeEvent>) {
399 match &mut self.kind {
400 TimelineEventKind::Decrypted(decrypted) => decrypted.event = replacement,
401 TimelineEventKind::UnableToDecrypt { event, .. }
402 | TimelineEventKind::PlainText { event } => {
403 *event = replacement.cast();
406 }
407 }
408 }
409
410 pub fn encryption_info(&self) -> Option<&EncryptionInfo> {
413 self.kind.encryption_info()
414 }
415
416 pub fn into_raw(self) -> Raw<AnySyncTimelineEvent> {
419 self.kind.into_raw()
420 }
421}
422
423impl From<DecryptedRoomEvent> for TimelineEvent {
424 fn from(decrypted: DecryptedRoomEvent) -> Self {
425 Self { kind: TimelineEventKind::Decrypted(decrypted), push_actions: None }
426 }
427}
428
429impl<'de> Deserialize<'de> for TimelineEvent {
430 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
438 where
439 D: serde::Deserializer<'de>,
440 {
441 use serde_json::{Map, Value};
442
443 let value = Map::<String, Value>::deserialize(deserializer)?;
445
446 if value.contains_key("event") {
448 let v0: SyncTimelineEventDeserializationHelperV0 =
449 serde_json::from_value(Value::Object(value)).map_err(|e| {
450 serde::de::Error::custom(format!(
451 "Unable to deserialize V0-format TimelineEvent: {}",
452 e
453 ))
454 })?;
455 Ok(v0.into())
456 }
457 else {
459 let v1: SyncTimelineEventDeserializationHelperV1 =
460 serde_json::from_value(Value::Object(value)).map_err(|e| {
461 serde::de::Error::custom(format!(
462 "Unable to deserialize V1-format TimelineEvent: {}",
463 e
464 ))
465 })?;
466 Ok(v1.into())
467 }
468 }
469}
470
471#[derive(Clone, Serialize, Deserialize)]
473pub enum TimelineEventKind {
474 Decrypted(DecryptedRoomEvent),
476
477 UnableToDecrypt {
479 event: Raw<AnySyncTimelineEvent>,
483
484 utd_info: UnableToDecryptInfo,
486 },
487
488 PlainText {
490 event: Raw<AnySyncTimelineEvent>,
494 },
495}
496
497impl TimelineEventKind {
498 pub fn raw(&self) -> &Raw<AnySyncTimelineEvent> {
501 match self {
502 TimelineEventKind::Decrypted(d) => d.event.cast_ref(),
508 TimelineEventKind::UnableToDecrypt { event, .. } => event.cast_ref(),
509 TimelineEventKind::PlainText { event } => event,
510 }
511 }
512
513 pub fn event_id(&self) -> Option<OwnedEventId> {
516 self.raw().get_field::<OwnedEventId>("event_id").ok().flatten()
517 }
518
519 pub fn encryption_info(&self) -> Option<&EncryptionInfo> {
522 match self {
523 TimelineEventKind::Decrypted(d) => Some(&d.encryption_info),
524 TimelineEventKind::UnableToDecrypt { .. } => None,
525 TimelineEventKind::PlainText { .. } => None,
526 }
527 }
528
529 pub fn into_raw(self) -> Raw<AnySyncTimelineEvent> {
532 match self {
533 TimelineEventKind::Decrypted(d) => d.event.cast(),
539 TimelineEventKind::UnableToDecrypt { event, .. } => event.cast(),
540 TimelineEventKind::PlainText { event } => event,
541 }
542 }
543}
544
545#[cfg(not(tarpaulin_include))]
546impl fmt::Debug for TimelineEventKind {
547 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
548 match &self {
549 Self::PlainText { event } => f
550 .debug_struct("TimelineEventDecryptionResult::PlainText")
551 .field("event", &DebugRawEvent(event))
552 .finish(),
553
554 Self::UnableToDecrypt { event, utd_info } => f
555 .debug_struct("TimelineEventDecryptionResult::UnableToDecrypt")
556 .field("event", &DebugRawEvent(event))
557 .field("utd_info", &utd_info)
558 .finish(),
559
560 Self::Decrypted(decrypted) => {
561 f.debug_tuple("TimelineEventDecryptionResult::Decrypted").field(decrypted).finish()
562 }
563 }
564 }
565}
566
567#[derive(Clone, Serialize, Deserialize)]
568pub struct DecryptedRoomEvent {
570 pub event: Raw<AnyMessageLikeEvent>,
577
578 pub encryption_info: EncryptionInfo,
580
581 #[serde(skip_serializing_if = "Option::is_none")]
586 pub unsigned_encryption_info: Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>>,
587}
588
589#[cfg(not(tarpaulin_include))]
590impl fmt::Debug for DecryptedRoomEvent {
591 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592 let DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info } = self;
593
594 f.debug_struct("DecryptedRoomEvent")
595 .field("event", &DebugRawEvent(event))
596 .field("encryption_info", encryption_info)
597 .maybe_field("unsigned_encryption_info", unsigned_encryption_info)
598 .finish()
599 }
600}
601
602#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
604pub enum UnsignedEventLocation {
605 RelationsReplace,
608 RelationsThreadLatestEvent,
611}
612
613impl UnsignedEventLocation {
614 pub fn find_mut<'a>(&self, unsigned: &'a mut JsonObject) -> Option<&'a mut serde_json::Value> {
621 let relations = unsigned.get_mut("m.relations")?.as_object_mut()?;
622
623 match self {
624 Self::RelationsReplace => relations.get_mut("m.replace"),
625 Self::RelationsThreadLatestEvent => {
626 relations.get_mut("m.thread")?.as_object_mut()?.get_mut("latest_event")
627 }
628 }
629 }
630}
631
632#[derive(Debug, Clone, Serialize, Deserialize)]
634pub enum UnsignedDecryptionResult {
635 Decrypted(EncryptionInfo),
637 UnableToDecrypt(UnableToDecryptInfo),
639}
640
641#[derive(Debug, Clone, Serialize, Deserialize)]
643pub struct UnableToDecryptInfo {
644 #[serde(skip_serializing_if = "Option::is_none")]
647 pub session_id: Option<String>,
648
649 #[serde(default = "unknown_utd_reason", deserialize_with = "deserialize_utd_reason")]
651 pub reason: UnableToDecryptReason,
652}
653
654fn unknown_utd_reason() -> UnableToDecryptReason {
655 UnableToDecryptReason::Unknown
656}
657
658pub fn deserialize_utd_reason<'de, D>(d: D) -> Result<UnableToDecryptReason, D::Error>
661where
662 D: serde::Deserializer<'de>,
663{
664 let v: serde_json::Value = Deserialize::deserialize(d)?;
666 if v.as_str().is_some_and(|s| s == "MissingMegolmSession") {
669 return Ok(UnableToDecryptReason::MissingMegolmSession { withheld_code: None });
670 }
671 serde_json::from_value::<UnableToDecryptReason>(v).map_err(serde::de::Error::custom)
674}
675
676#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
678pub enum UnableToDecryptReason {
679 #[doc(hidden)]
682 Unknown,
683
684 MalformedEncryptedEvent,
688
689 MissingMegolmSession {
692 withheld_code: Option<WithheldCode>,
695 },
696
697 UnknownMegolmMessageIndex,
700
701 MegolmDecryptionFailure,
708
709 PayloadDeserializationFailure,
711
712 MismatchedIdentityKeys,
716
717 SenderIdentityNotTrusted(VerificationLevel),
721}
722
723impl UnableToDecryptReason {
724 pub fn is_missing_room_key(&self) -> bool {
727 matches!(
730 self,
731 Self::MissingMegolmSession { withheld_code: None } | Self::UnknownMegolmMessageIndex
732 )
733 }
734}
735
736#[derive(
740 Clone,
741 PartialEq,
742 Eq,
743 Hash,
744 AsStrAsRefStr,
745 AsRefStr,
746 FromString,
747 DebugAsRefStr,
748 SerializeAsRefStr,
749 DeserializeFromCowStr,
750)]
751pub enum WithheldCode {
752 #[ruma_enum(rename = "m.blacklisted")]
754 Blacklisted,
755
756 #[ruma_enum(rename = "m.unverified")]
758 Unverified,
759
760 #[ruma_enum(rename = "m.unauthorised")]
764 Unauthorised,
765
766 #[ruma_enum(rename = "m.unavailable")]
769 Unavailable,
770
771 #[ruma_enum(rename = "m.no_olm")]
775 NoOlm,
776
777 #[doc(hidden)]
778 _Custom(PrivOwnedStr),
779}
780
781impl fmt::Display for WithheldCode {
782 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
783 let string = match self {
784 WithheldCode::Blacklisted => "The sender has blocked you.",
785 WithheldCode::Unverified => "The sender has disabled encrypting to unverified devices.",
786 WithheldCode::Unauthorised => "You are not authorised to read the message.",
787 WithheldCode::Unavailable => "The requested key was not found.",
788 WithheldCode::NoOlm => "Unable to establish a secure channel.",
789 _ => self.as_str(),
790 };
791
792 f.write_str(string)
793 }
794}
795
796#[doc(hidden)]
800#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
801pub struct PrivOwnedStr(pub Box<str>);
802
803#[cfg(not(tarpaulin_include))]
804impl fmt::Debug for PrivOwnedStr {
805 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806 self.0.fmt(f)
807 }
808}
809
810#[derive(Debug, Deserialize)]
815struct SyncTimelineEventDeserializationHelperV1 {
816 kind: TimelineEventKind,
818
819 #[serde(default)]
821 push_actions: Vec<Action>,
822}
823
824impl From<SyncTimelineEventDeserializationHelperV1> for TimelineEvent {
825 fn from(value: SyncTimelineEventDeserializationHelperV1) -> Self {
826 let SyncTimelineEventDeserializationHelperV1 { kind, push_actions } = value;
827 TimelineEvent { kind, push_actions: Some(push_actions) }
828 }
829}
830
831#[derive(Deserialize)]
833struct SyncTimelineEventDeserializationHelperV0 {
834 event: Raw<AnySyncTimelineEvent>,
836
837 encryption_info: Option<EncryptionInfo>,
840
841 #[serde(default)]
843 push_actions: Vec<Action>,
844
845 unsigned_encryption_info: Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>>,
850}
851
852impl From<SyncTimelineEventDeserializationHelperV0> for TimelineEvent {
853 fn from(value: SyncTimelineEventDeserializationHelperV0) -> Self {
854 let SyncTimelineEventDeserializationHelperV0 {
855 event,
856 encryption_info,
857 push_actions,
858 unsigned_encryption_info,
859 } = value;
860
861 let kind = match encryption_info {
862 Some(encryption_info) => {
863 TimelineEventKind::Decrypted(DecryptedRoomEvent {
864 event: event.cast(),
871 encryption_info,
872 unsigned_encryption_info,
873 })
874 }
875
876 None => TimelineEventKind::PlainText { event },
877 };
878
879 TimelineEvent { kind, push_actions: Some(push_actions) }
880 }
881}
882
883#[cfg(test)]
884mod tests {
885 use std::collections::BTreeMap;
886
887 use assert_matches::assert_matches;
888 use insta::{assert_json_snapshot, with_settings};
889 use ruma::{
890 device_id, event_id, events::room::message::RoomMessageEventContent, serde::Raw, user_id,
891 DeviceKeyAlgorithm,
892 };
893 use serde::Deserialize;
894 use serde_json::json;
895
896 use super::{
897 AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo, ShieldState,
898 ShieldStateCode, TimelineEvent, TimelineEventKind, UnableToDecryptInfo,
899 UnableToDecryptReason, UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel,
900 VerificationState, WithheldCode,
901 };
902
903 fn example_event() -> serde_json::Value {
904 json!({
905 "content": RoomMessageEventContent::text_plain("secret"),
906 "type": "m.room.message",
907 "event_id": "$xxxxx:example.org",
908 "room_id": "!someroom:example.com",
909 "origin_server_ts": 2189,
910 "sender": "@carl:example.com",
911 })
912 }
913
914 #[test]
915 fn sync_timeline_debug_content() {
916 let room_event = TimelineEvent::new(Raw::new(&example_event()).unwrap().cast());
917 let debug_s = format!("{room_event:?}");
918 assert!(
919 !debug_s.contains("secret"),
920 "Debug representation contains event content!\n{debug_s}"
921 );
922 }
923
924 #[test]
925 fn old_verification_state_to_new_migration() {
926 #[derive(Deserialize)]
927 struct State {
928 state: VerificationState,
929 }
930
931 let state = json!({
932 "state": "Trusted",
933 });
934 let deserialized: State =
935 serde_json::from_value(state).expect("We can deserialize the old trusted value");
936 assert_eq!(deserialized.state, VerificationState::Verified);
937
938 let state = json!({
939 "state": "UnknownDevice",
940 });
941
942 let deserialized: State =
943 serde_json::from_value(state).expect("We can deserialize the old unknown device value");
944
945 assert_eq!(
946 deserialized.state,
947 VerificationState::Unverified(VerificationLevel::None(
948 DeviceLinkProblem::MissingDevice
949 ))
950 );
951
952 let state = json!({
953 "state": "Untrusted",
954 });
955 let deserialized: State =
956 serde_json::from_value(state).expect("We can deserialize the old trusted value");
957
958 assert_eq!(
959 deserialized.state,
960 VerificationState::Unverified(VerificationLevel::UnsignedDevice)
961 );
962 }
963
964 #[test]
965 fn test_verification_level_deserializes() {
966 #[derive(Deserialize)]
968 struct Container {
969 verification_level: VerificationLevel,
970 }
971 let container = json!({ "verification_level": "VerificationViolation" });
972
973 let deserialized: Container = serde_json::from_value(container)
975 .expect("We can deserialize the old PreviouslyVerified value");
976
977 assert_eq!(deserialized.verification_level, VerificationLevel::VerificationViolation);
979 }
980
981 #[test]
982 fn test_verification_level_deserializes_from_old_previously_verified_value() {
983 #[derive(Deserialize)]
985 struct Container {
986 verification_level: VerificationLevel,
987 }
988 let container = json!({ "verification_level": "PreviouslyVerified" });
989
990 let deserialized: Container = serde_json::from_value(container)
992 .expect("We can deserialize the old PreviouslyVerified value");
993
994 assert_eq!(deserialized.verification_level, VerificationLevel::VerificationViolation);
996 }
997
998 #[test]
999 fn test_shield_state_code_deserializes() {
1000 #[derive(Deserialize)]
1002 struct Container {
1003 shield_state_code: ShieldStateCode,
1004 }
1005 let container = json!({ "shield_state_code": "VerificationViolation" });
1006
1007 let deserialized: Container = serde_json::from_value(container)
1009 .expect("We can deserialize the old PreviouslyVerified value");
1010
1011 assert_eq!(deserialized.shield_state_code, ShieldStateCode::VerificationViolation);
1013 }
1014
1015 #[test]
1016 fn test_shield_state_code_deserializes_from_old_previously_verified_value() {
1017 #[derive(Deserialize)]
1019 struct Container {
1020 shield_state_code: ShieldStateCode,
1021 }
1022 let container = json!({ "shield_state_code": "PreviouslyVerified" });
1023
1024 let deserialized: Container = serde_json::from_value(container)
1026 .expect("We can deserialize the old PreviouslyVerified value");
1027
1028 assert_eq!(deserialized.shield_state_code, ShieldStateCode::VerificationViolation);
1030 }
1031
1032 #[test]
1033 fn sync_timeline_event_serialisation() {
1034 let room_event = TimelineEvent {
1035 kind: TimelineEventKind::Decrypted(DecryptedRoomEvent {
1036 event: Raw::new(&example_event()).unwrap().cast(),
1037 encryption_info: EncryptionInfo {
1038 sender: user_id!("@sender:example.com").to_owned(),
1039 sender_device: None,
1040 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
1041 curve25519_key: "xxx".to_owned(),
1042 sender_claimed_keys: Default::default(),
1043 },
1044 verification_state: VerificationState::Verified,
1045 },
1046 unsigned_encryption_info: Some(BTreeMap::from([(
1047 UnsignedEventLocation::RelationsReplace,
1048 UnsignedDecryptionResult::UnableToDecrypt(UnableToDecryptInfo {
1049 session_id: Some("xyz".to_owned()),
1050 reason: UnableToDecryptReason::MalformedEncryptedEvent,
1051 }),
1052 )])),
1053 }),
1054 push_actions: Default::default(),
1055 };
1056
1057 let serialized = serde_json::to_value(&room_event).unwrap();
1058
1059 assert_eq!(
1061 serialized,
1062 json!({
1063 "kind": {
1064 "Decrypted": {
1065 "event": {
1066 "content": {"body": "secret", "msgtype": "m.text"},
1067 "event_id": "$xxxxx:example.org",
1068 "origin_server_ts": 2189,
1069 "room_id": "!someroom:example.com",
1070 "sender": "@carl:example.com",
1071 "type": "m.room.message",
1072 },
1073 "encryption_info": {
1074 "sender": "@sender:example.com",
1075 "sender_device": null,
1076 "algorithm_info": {
1077 "MegolmV1AesSha2": {
1078 "curve25519_key": "xxx",
1079 "sender_claimed_keys": {}
1080 }
1081 },
1082 "verification_state": "Verified",
1083 },
1084 "unsigned_encryption_info": {
1085 "RelationsReplace": {"UnableToDecrypt": {
1086 "session_id": "xyz",
1087 "reason": "MalformedEncryptedEvent",
1088 }}
1089 }
1090 }
1091 }
1092 })
1093 );
1094
1095 let event: TimelineEvent = serde_json::from_value(serialized).unwrap();
1097 assert_eq!(event.event_id(), Some(event_id!("$xxxxx:example.org").to_owned()));
1098 assert_matches!(
1099 event.encryption_info().unwrap().algorithm_info,
1100 AlgorithmInfo::MegolmV1AesSha2 { .. }
1101 );
1102
1103 let serialized = json!({
1105 "event": {
1106 "content": {"body": "secret", "msgtype": "m.text"},
1107 "event_id": "$xxxxx:example.org",
1108 "origin_server_ts": 2189,
1109 "room_id": "!someroom:example.com",
1110 "sender": "@carl:example.com",
1111 "type": "m.room.message",
1112 },
1113 "encryption_info": {
1114 "sender": "@sender:example.com",
1115 "sender_device": null,
1116 "algorithm_info": {
1117 "MegolmV1AesSha2": {
1118 "curve25519_key": "xxx",
1119 "sender_claimed_keys": {}
1120 }
1121 },
1122 "verification_state": "Verified",
1123 },
1124 });
1125 let event: TimelineEvent = serde_json::from_value(serialized).unwrap();
1126 assert_eq!(event.event_id(), Some(event_id!("$xxxxx:example.org").to_owned()));
1127 assert_matches!(
1128 event.encryption_info().unwrap().algorithm_info,
1129 AlgorithmInfo::MegolmV1AesSha2 { .. }
1130 );
1131
1132 let serialized = json!({
1135 "event": {
1136 "content": {"body": "secret", "msgtype": "m.text"},
1137 "event_id": "$xxxxx:example.org",
1138 "origin_server_ts": 2189,
1139 "room_id": "!someroom:example.com",
1140 "sender": "@carl:example.com",
1141 "type": "m.room.message",
1142 },
1143 "encryption_info": {
1144 "sender": "@sender:example.com",
1145 "sender_device": null,
1146 "algorithm_info": {
1147 "MegolmV1AesSha2": {
1148 "curve25519_key": "xxx",
1149 "sender_claimed_keys": {}
1150 }
1151 },
1152 "verification_state": "Verified",
1153 },
1154 "unsigned_encryption_info": {
1155 "RelationsReplace": {"UnableToDecrypt": {"session_id": "xyz"}}
1156 }
1157 });
1158 let event: TimelineEvent = serde_json::from_value(serialized).unwrap();
1159 assert_eq!(event.event_id(), Some(event_id!("$xxxxx:example.org").to_owned()));
1160 assert_matches!(
1161 event.encryption_info().unwrap().algorithm_info,
1162 AlgorithmInfo::MegolmV1AesSha2 { .. }
1163 );
1164 assert_matches!(event.kind, TimelineEventKind::Decrypted(decrypted) => {
1165 assert_matches!(decrypted.unsigned_encryption_info, Some(map) => {
1166 assert_eq!(map.len(), 1);
1167 let (location, result) = map.into_iter().next().unwrap();
1168 assert_eq!(location, UnsignedEventLocation::RelationsReplace);
1169 assert_matches!(result, UnsignedDecryptionResult::UnableToDecrypt(utd_info) => {
1170 assert_eq!(utd_info.session_id, Some("xyz".to_owned()));
1171 assert_eq!(utd_info.reason, UnableToDecryptReason::Unknown);
1172 })
1173 });
1174 });
1175 }
1176
1177 #[test]
1178 fn sync_timeline_event_deserialisation_migration_for_withheld() {
1179 let serialized = json!({
1196 "kind": {
1197 "UnableToDecrypt": {
1198 "event": {
1199 "content": {
1200 "algorithm": "m.megolm.v1.aes-sha2",
1201 "ciphertext": "AwgAEoABzL1JYhqhjW9jXrlT3M6H8mJ4qffYtOQOnPuAPNxsuG20oiD/Fnpv6jnQGhU6YbV9pNM+1mRnTvxW3CbWOPjLKqCWTJTc7Q0vDEVtYePg38ncXNcwMmfhgnNAoW9S7vNs8C003x3yUl6NeZ8bH+ci870BZL+kWM/lMl10tn6U7snNmSjnE3ckvRdO+11/R4//5VzFQpZdf4j036lNSls/WIiI67Fk9iFpinz9xdRVWJFVdrAiPFwb8L5xRZ8aX+e2JDMlc1eW8gk",
1202 "device_id": "SKCGPNUWAU",
1203 "sender_key": "Gim/c7uQdSXyrrUbmUOrBT6sMC0gO7QSLmOK6B7NOm0",
1204 "session_id": "hgLyeSqXfb8vc5AjQLsg6TSHVu0HJ7HZ4B6jgMvxkrs"
1205 },
1206 "event_id": "$xxxxx:example.org",
1207 "origin_server_ts": 2189,
1208 "room_id": "!someroom:example.com",
1209 "sender": "@carl:example.com",
1210 "type": "m.room.message"
1211 },
1212 "utd_info": {
1213 "reason": "MissingMegolmSession",
1214 "session_id": "session000"
1215 }
1216 }
1217 }
1218 });
1219
1220 let result = serde_json::from_value(serialized);
1221 assert!(result.is_ok());
1222
1223 let event: TimelineEvent = result.unwrap();
1225 assert_matches!(
1226 event.kind,
1227 TimelineEventKind::UnableToDecrypt { utd_info, .. }=> {
1228 assert_matches!(
1229 utd_info.reason,
1230 UnableToDecryptReason::MissingMegolmSession { withheld_code: None }
1231 );
1232 }
1233 )
1234 }
1235
1236 #[test]
1237 fn unable_to_decrypt_info_migration_for_withheld() {
1238 let old_format = json!({
1239 "reason": "MissingMegolmSession",
1240 "session_id": "session000"
1241 });
1242
1243 let deserialized = serde_json::from_value::<UnableToDecryptInfo>(old_format).unwrap();
1244 let session_id = Some("session000".to_owned());
1245
1246 assert_eq!(deserialized.session_id, session_id);
1247 assert_eq!(
1248 deserialized.reason,
1249 UnableToDecryptReason::MissingMegolmSession { withheld_code: None },
1250 );
1251
1252 let new_format = json!({
1253 "session_id": "session000",
1254 "reason": {
1255 "MissingMegolmSession": {
1256 "withheld_code": null
1257 }
1258 }
1259 });
1260
1261 let deserialized = serde_json::from_value::<UnableToDecryptInfo>(new_format).unwrap();
1262
1263 assert_eq!(
1264 deserialized.reason,
1265 UnableToDecryptReason::MissingMegolmSession { withheld_code: None },
1266 );
1267 assert_eq!(deserialized.session_id, session_id);
1268 }
1269
1270 #[test]
1271 fn unable_to_decrypt_reason_is_missing_room_key() {
1272 let reason = UnableToDecryptReason::MissingMegolmSession { withheld_code: None };
1273 assert!(reason.is_missing_room_key());
1274
1275 let reason = UnableToDecryptReason::MissingMegolmSession {
1276 withheld_code: Some(WithheldCode::Blacklisted),
1277 };
1278 assert!(!reason.is_missing_room_key());
1279
1280 let reason = UnableToDecryptReason::UnknownMegolmMessageIndex;
1281 assert!(reason.is_missing_room_key());
1282 }
1283
1284 #[test]
1285 fn snapshot_test_verification_level() {
1286 assert_json_snapshot!(VerificationLevel::VerificationViolation);
1287 assert_json_snapshot!(VerificationLevel::UnsignedDevice);
1288 assert_json_snapshot!(VerificationLevel::None(DeviceLinkProblem::InsecureSource));
1289 assert_json_snapshot!(VerificationLevel::None(DeviceLinkProblem::MissingDevice));
1290 assert_json_snapshot!(VerificationLevel::UnverifiedIdentity);
1291 }
1292
1293 #[test]
1294 fn snapshot_test_verification_states() {
1295 assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::UnsignedDevice));
1296 assert_json_snapshot!(VerificationState::Unverified(
1297 VerificationLevel::VerificationViolation
1298 ));
1299 assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::None(
1300 DeviceLinkProblem::InsecureSource,
1301 )));
1302 assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::None(
1303 DeviceLinkProblem::MissingDevice,
1304 )));
1305 assert_json_snapshot!(VerificationState::Verified);
1306 }
1307
1308 #[test]
1309 fn snapshot_test_shield_states() {
1310 assert_json_snapshot!(ShieldState::None);
1311 assert_json_snapshot!(ShieldState::Red {
1312 code: ShieldStateCode::UnverifiedIdentity,
1313 message: "a message"
1314 });
1315 assert_json_snapshot!(ShieldState::Grey {
1316 code: ShieldStateCode::AuthenticityNotGuaranteed,
1317 message: "authenticity of this message cannot be guaranteed",
1318 });
1319 }
1320
1321 #[test]
1322 fn snapshot_test_shield_codes() {
1323 assert_json_snapshot!(ShieldStateCode::AuthenticityNotGuaranteed);
1324 assert_json_snapshot!(ShieldStateCode::UnknownDevice);
1325 assert_json_snapshot!(ShieldStateCode::UnsignedDevice);
1326 assert_json_snapshot!(ShieldStateCode::UnverifiedIdentity);
1327 assert_json_snapshot!(ShieldStateCode::SentInClear);
1328 assert_json_snapshot!(ShieldStateCode::VerificationViolation);
1329 }
1330
1331 #[test]
1332 fn snapshot_test_algorithm_info() {
1333 let mut map = BTreeMap::new();
1334 map.insert(DeviceKeyAlgorithm::Curve25519, "claimedclaimedcurve25519".to_owned());
1335 map.insert(DeviceKeyAlgorithm::Ed25519, "claimedclaimeded25519".to_owned());
1336 let info = AlgorithmInfo::MegolmV1AesSha2 {
1337 curve25519_key: "curvecurvecurve".into(),
1338 sender_claimed_keys: BTreeMap::from([
1339 (DeviceKeyAlgorithm::Curve25519, "claimedclaimedcurve25519".to_owned()),
1340 (DeviceKeyAlgorithm::Ed25519, "claimedclaimeded25519".to_owned()),
1341 ]),
1342 };
1343
1344 assert_json_snapshot!(info)
1345 }
1346
1347 #[test]
1348 fn snapshot_test_encryption_info() {
1349 let info = EncryptionInfo {
1350 sender: user_id!("@alice:localhost").to_owned(),
1351 sender_device: Some(device_id!("ABCDEFGH").to_owned()),
1352 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
1353 curve25519_key: "curvecurvecurve".into(),
1354 sender_claimed_keys: Default::default(),
1355 },
1356 verification_state: VerificationState::Verified,
1357 };
1358
1359 with_settings!({sort_maps =>true}, {
1360 assert_json_snapshot!(info)
1361 })
1362 }
1363
1364 #[test]
1365 fn snapshot_test_sync_timeline_event() {
1366 let room_event = TimelineEvent {
1367 kind: TimelineEventKind::Decrypted(DecryptedRoomEvent {
1368 event: Raw::new(&example_event()).unwrap().cast(),
1369 encryption_info: EncryptionInfo {
1370 sender: user_id!("@sender:example.com").to_owned(),
1371 sender_device: Some(device_id!("ABCDEFGHIJ").to_owned()),
1372 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
1373 curve25519_key: "xxx".to_owned(),
1374 sender_claimed_keys: BTreeMap::from([
1375 (
1376 DeviceKeyAlgorithm::Ed25519,
1377 "I3YsPwqMZQXHkSQbjFNEs7b529uac2xBpI83eN3LUXo".to_owned(),
1378 ),
1379 (
1380 DeviceKeyAlgorithm::Curve25519,
1381 "qzdW3F5IMPFl0HQgz5w/L5Oi/npKUFn8Um84acIHfPY".to_owned(),
1382 ),
1383 ]),
1384 },
1385 verification_state: VerificationState::Verified,
1386 },
1387 unsigned_encryption_info: Some(BTreeMap::from([(
1388 UnsignedEventLocation::RelationsThreadLatestEvent,
1389 UnsignedDecryptionResult::UnableToDecrypt(UnableToDecryptInfo {
1390 session_id: Some("xyz".to_owned()),
1391 reason: UnableToDecryptReason::MissingMegolmSession {
1392 withheld_code: Some(WithheldCode::Unverified),
1393 },
1394 }),
1395 )])),
1396 }),
1397 push_actions: Default::default(),
1398 };
1399
1400 with_settings!({sort_maps =>true}, {
1401 assert_json_snapshot! {
1404 serde_json::to_value(&room_event).unwrap(),
1405 }
1406 });
1407 }
1408}