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 pub session_id: Option<String>,
308}
309
310#[derive(Clone, Debug, Serialize)]
333pub struct TimelineEvent {
334 pub kind: TimelineEventKind,
336
337 #[serde(skip_serializing_if = "Option::is_none")]
341 pub push_actions: Option<Vec<Action>>,
342}
343
344#[cfg(not(feature = "test-send-sync"))]
346unsafe impl Send for TimelineEvent {}
347
348#[cfg(not(feature = "test-send-sync"))]
350unsafe impl Sync for TimelineEvent {}
351
352#[cfg(feature = "test-send-sync")]
353#[test]
354fn test_send_sync_for_sync_timeline_event() {
356 fn assert_send_sync<T: Send + Sync>() {}
357
358 assert_send_sync::<TimelineEvent>();
359}
360
361impl TimelineEvent {
362 pub fn new(event: Raw<AnySyncTimelineEvent>) -> Self {
367 Self { kind: TimelineEventKind::PlainText { event }, push_actions: None }
368 }
369
370 pub fn new_with_push_actions(
376 event: Raw<AnySyncTimelineEvent>,
377 push_actions: Vec<Action>,
378 ) -> Self {
379 Self { kind: TimelineEventKind::PlainText { event }, push_actions: Some(push_actions) }
380 }
381
382 pub fn new_utd_event(event: Raw<AnySyncTimelineEvent>, utd_info: UnableToDecryptInfo) -> Self {
385 Self { kind: TimelineEventKind::UnableToDecrypt { event, utd_info }, push_actions: None }
386 }
387
388 pub fn event_id(&self) -> Option<OwnedEventId> {
391 self.kind.event_id()
392 }
393
394 pub fn raw(&self) -> &Raw<AnySyncTimelineEvent> {
397 self.kind.raw()
398 }
399
400 pub fn replace_raw(&mut self, replacement: Raw<AnyMessageLikeEvent>) {
402 match &mut self.kind {
403 TimelineEventKind::Decrypted(decrypted) => decrypted.event = replacement,
404 TimelineEventKind::UnableToDecrypt { event, .. }
405 | TimelineEventKind::PlainText { event } => {
406 *event = replacement.cast();
409 }
410 }
411 }
412
413 pub fn encryption_info(&self) -> Option<&EncryptionInfo> {
416 self.kind.encryption_info()
417 }
418
419 pub fn into_raw(self) -> Raw<AnySyncTimelineEvent> {
422 self.kind.into_raw()
423 }
424}
425
426impl From<DecryptedRoomEvent> for TimelineEvent {
427 fn from(decrypted: DecryptedRoomEvent) -> Self {
428 Self { kind: TimelineEventKind::Decrypted(decrypted), push_actions: None }
429 }
430}
431
432impl<'de> Deserialize<'de> for TimelineEvent {
433 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
441 where
442 D: serde::Deserializer<'de>,
443 {
444 use serde_json::{Map, Value};
445
446 let value = Map::<String, Value>::deserialize(deserializer)?;
448
449 if value.contains_key("event") {
451 let v0: SyncTimelineEventDeserializationHelperV0 =
452 serde_json::from_value(Value::Object(value)).map_err(|e| {
453 serde::de::Error::custom(format!(
454 "Unable to deserialize V0-format TimelineEvent: {}",
455 e
456 ))
457 })?;
458 Ok(v0.into())
459 }
460 else {
462 let v1: SyncTimelineEventDeserializationHelperV1 =
463 serde_json::from_value(Value::Object(value)).map_err(|e| {
464 serde::de::Error::custom(format!(
465 "Unable to deserialize V1-format TimelineEvent: {}",
466 e
467 ))
468 })?;
469 Ok(v1.into())
470 }
471 }
472}
473
474#[derive(Clone, Serialize, Deserialize)]
476pub enum TimelineEventKind {
477 Decrypted(DecryptedRoomEvent),
479
480 UnableToDecrypt {
482 event: Raw<AnySyncTimelineEvent>,
486
487 utd_info: UnableToDecryptInfo,
489 },
490
491 PlainText {
493 event: Raw<AnySyncTimelineEvent>,
497 },
498}
499
500impl TimelineEventKind {
501 pub fn raw(&self) -> &Raw<AnySyncTimelineEvent> {
504 match self {
505 TimelineEventKind::Decrypted(d) => d.event.cast_ref(),
511 TimelineEventKind::UnableToDecrypt { event, .. } => event.cast_ref(),
512 TimelineEventKind::PlainText { event } => event,
513 }
514 }
515
516 pub fn event_id(&self) -> Option<OwnedEventId> {
519 self.raw().get_field::<OwnedEventId>("event_id").ok().flatten()
520 }
521
522 pub fn encryption_info(&self) -> Option<&EncryptionInfo> {
525 match self {
526 TimelineEventKind::Decrypted(d) => Some(&d.encryption_info),
527 TimelineEventKind::UnableToDecrypt { .. } => None,
528 TimelineEventKind::PlainText { .. } => None,
529 }
530 }
531
532 pub fn into_raw(self) -> Raw<AnySyncTimelineEvent> {
535 match self {
536 TimelineEventKind::Decrypted(d) => d.event.cast(),
542 TimelineEventKind::UnableToDecrypt { event, .. } => event.cast(),
543 TimelineEventKind::PlainText { event } => event,
544 }
545 }
546
547 pub fn session_id(&self) -> Option<&str> {
550 match self {
551 TimelineEventKind::Decrypted(decrypted_room_event) => {
552 decrypted_room_event.encryption_info.session_id.as_ref()
553 }
554 TimelineEventKind::UnableToDecrypt { utd_info, .. } => utd_info.session_id.as_ref(),
555 TimelineEventKind::PlainText { .. } => None,
556 }
557 .map(String::as_str)
558 }
559}
560
561#[cfg(not(tarpaulin_include))]
562impl fmt::Debug for TimelineEventKind {
563 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
564 match &self {
565 Self::PlainText { event } => f
566 .debug_struct("TimelineEventDecryptionResult::PlainText")
567 .field("event", &DebugRawEvent(event))
568 .finish(),
569
570 Self::UnableToDecrypt { event, utd_info } => f
571 .debug_struct("TimelineEventDecryptionResult::UnableToDecrypt")
572 .field("event", &DebugRawEvent(event))
573 .field("utd_info", &utd_info)
574 .finish(),
575
576 Self::Decrypted(decrypted) => {
577 f.debug_tuple("TimelineEventDecryptionResult::Decrypted").field(decrypted).finish()
578 }
579 }
580 }
581}
582
583#[derive(Clone, Serialize, Deserialize)]
584pub struct DecryptedRoomEvent {
586 pub event: Raw<AnyMessageLikeEvent>,
593
594 pub encryption_info: EncryptionInfo,
596
597 #[serde(skip_serializing_if = "Option::is_none")]
602 pub unsigned_encryption_info: Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>>,
603}
604
605#[cfg(not(tarpaulin_include))]
606impl fmt::Debug for DecryptedRoomEvent {
607 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
608 let DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info } = self;
609
610 f.debug_struct("DecryptedRoomEvent")
611 .field("event", &DebugRawEvent(event))
612 .field("encryption_info", encryption_info)
613 .maybe_field("unsigned_encryption_info", unsigned_encryption_info)
614 .finish()
615 }
616}
617
618#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
620pub enum UnsignedEventLocation {
621 RelationsReplace,
624 RelationsThreadLatestEvent,
627}
628
629impl UnsignedEventLocation {
630 pub fn find_mut<'a>(&self, unsigned: &'a mut JsonObject) -> Option<&'a mut serde_json::Value> {
637 let relations = unsigned.get_mut("m.relations")?.as_object_mut()?;
638
639 match self {
640 Self::RelationsReplace => relations.get_mut("m.replace"),
641 Self::RelationsThreadLatestEvent => {
642 relations.get_mut("m.thread")?.as_object_mut()?.get_mut("latest_event")
643 }
644 }
645 }
646}
647
648#[derive(Debug, Clone, Serialize, Deserialize)]
650pub enum UnsignedDecryptionResult {
651 Decrypted(EncryptionInfo),
653 UnableToDecrypt(UnableToDecryptInfo),
655}
656
657#[derive(Debug, Clone, Serialize, Deserialize)]
659pub struct UnableToDecryptInfo {
660 #[serde(skip_serializing_if = "Option::is_none")]
663 pub session_id: Option<String>,
664
665 #[serde(default = "unknown_utd_reason", deserialize_with = "deserialize_utd_reason")]
667 pub reason: UnableToDecryptReason,
668}
669
670fn unknown_utd_reason() -> UnableToDecryptReason {
671 UnableToDecryptReason::Unknown
672}
673
674pub fn deserialize_utd_reason<'de, D>(d: D) -> Result<UnableToDecryptReason, D::Error>
677where
678 D: serde::Deserializer<'de>,
679{
680 let v: serde_json::Value = Deserialize::deserialize(d)?;
682 if v.as_str().is_some_and(|s| s == "MissingMegolmSession") {
685 return Ok(UnableToDecryptReason::MissingMegolmSession { withheld_code: None });
686 }
687 serde_json::from_value::<UnableToDecryptReason>(v).map_err(serde::de::Error::custom)
690}
691
692#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
694pub enum UnableToDecryptReason {
695 #[doc(hidden)]
698 Unknown,
699
700 MalformedEncryptedEvent,
704
705 MissingMegolmSession {
708 withheld_code: Option<WithheldCode>,
711 },
712
713 UnknownMegolmMessageIndex,
716
717 MegolmDecryptionFailure,
724
725 PayloadDeserializationFailure,
727
728 MismatchedIdentityKeys,
732
733 SenderIdentityNotTrusted(VerificationLevel),
737}
738
739impl UnableToDecryptReason {
740 pub fn is_missing_room_key(&self) -> bool {
743 matches!(
746 self,
747 Self::MissingMegolmSession { withheld_code: None } | Self::UnknownMegolmMessageIndex
748 )
749 }
750}
751
752#[derive(
756 Clone,
757 PartialEq,
758 Eq,
759 Hash,
760 AsStrAsRefStr,
761 AsRefStr,
762 FromString,
763 DebugAsRefStr,
764 SerializeAsRefStr,
765 DeserializeFromCowStr,
766)]
767pub enum WithheldCode {
768 #[ruma_enum(rename = "m.blacklisted")]
770 Blacklisted,
771
772 #[ruma_enum(rename = "m.unverified")]
774 Unverified,
775
776 #[ruma_enum(rename = "m.unauthorised")]
780 Unauthorised,
781
782 #[ruma_enum(rename = "m.unavailable")]
785 Unavailable,
786
787 #[ruma_enum(rename = "m.no_olm")]
791 NoOlm,
792
793 #[doc(hidden)]
794 _Custom(PrivOwnedStr),
795}
796
797impl fmt::Display for WithheldCode {
798 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
799 let string = match self {
800 WithheldCode::Blacklisted => "The sender has blocked you.",
801 WithheldCode::Unverified => "The sender has disabled encrypting to unverified devices.",
802 WithheldCode::Unauthorised => "You are not authorised to read the message.",
803 WithheldCode::Unavailable => "The requested key was not found.",
804 WithheldCode::NoOlm => "Unable to establish a secure channel.",
805 _ => self.as_str(),
806 };
807
808 f.write_str(string)
809 }
810}
811
812#[doc(hidden)]
816#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
817pub struct PrivOwnedStr(pub Box<str>);
818
819#[cfg(not(tarpaulin_include))]
820impl fmt::Debug for PrivOwnedStr {
821 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822 self.0.fmt(f)
823 }
824}
825
826#[derive(Debug, Deserialize)]
831struct SyncTimelineEventDeserializationHelperV1 {
832 kind: TimelineEventKind,
834
835 #[serde(default)]
837 push_actions: Vec<Action>,
838}
839
840impl From<SyncTimelineEventDeserializationHelperV1> for TimelineEvent {
841 fn from(value: SyncTimelineEventDeserializationHelperV1) -> Self {
842 let SyncTimelineEventDeserializationHelperV1 { kind, push_actions } = value;
843 TimelineEvent { kind, push_actions: Some(push_actions) }
844 }
845}
846
847#[derive(Deserialize)]
849struct SyncTimelineEventDeserializationHelperV0 {
850 event: Raw<AnySyncTimelineEvent>,
852
853 encryption_info: Option<EncryptionInfo>,
856
857 #[serde(default)]
859 push_actions: Vec<Action>,
860
861 unsigned_encryption_info: Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>>,
866}
867
868impl From<SyncTimelineEventDeserializationHelperV0> for TimelineEvent {
869 fn from(value: SyncTimelineEventDeserializationHelperV0) -> Self {
870 let SyncTimelineEventDeserializationHelperV0 {
871 event,
872 encryption_info,
873 push_actions,
874 unsigned_encryption_info,
875 } = value;
876
877 let kind = match encryption_info {
878 Some(encryption_info) => {
879 TimelineEventKind::Decrypted(DecryptedRoomEvent {
880 event: event.cast(),
887 encryption_info,
888 unsigned_encryption_info,
889 })
890 }
891
892 None => TimelineEventKind::PlainText { event },
893 };
894
895 TimelineEvent { kind, push_actions: Some(push_actions) }
896 }
897}
898
899#[cfg(test)]
900mod tests {
901 use std::collections::BTreeMap;
902
903 use assert_matches::assert_matches;
904 use insta::{assert_json_snapshot, with_settings};
905 use ruma::{
906 device_id, event_id, events::room::message::RoomMessageEventContent, serde::Raw, user_id,
907 DeviceKeyAlgorithm,
908 };
909 use serde::Deserialize;
910 use serde_json::json;
911
912 use super::{
913 AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo, ShieldState,
914 ShieldStateCode, TimelineEvent, TimelineEventKind, UnableToDecryptInfo,
915 UnableToDecryptReason, UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel,
916 VerificationState, WithheldCode,
917 };
918
919 fn example_event() -> serde_json::Value {
920 json!({
921 "content": RoomMessageEventContent::text_plain("secret"),
922 "type": "m.room.message",
923 "event_id": "$xxxxx:example.org",
924 "room_id": "!someroom:example.com",
925 "origin_server_ts": 2189,
926 "sender": "@carl:example.com",
927 })
928 }
929
930 #[test]
931 fn sync_timeline_debug_content() {
932 let room_event = TimelineEvent::new(Raw::new(&example_event()).unwrap().cast());
933 let debug_s = format!("{room_event:?}");
934 assert!(
935 !debug_s.contains("secret"),
936 "Debug representation contains event content!\n{debug_s}"
937 );
938 }
939
940 #[test]
941 fn old_verification_state_to_new_migration() {
942 #[derive(Deserialize)]
943 struct State {
944 state: VerificationState,
945 }
946
947 let state = json!({
948 "state": "Trusted",
949 });
950 let deserialized: State =
951 serde_json::from_value(state).expect("We can deserialize the old trusted value");
952 assert_eq!(deserialized.state, VerificationState::Verified);
953
954 let state = json!({
955 "state": "UnknownDevice",
956 });
957
958 let deserialized: State =
959 serde_json::from_value(state).expect("We can deserialize the old unknown device value");
960
961 assert_eq!(
962 deserialized.state,
963 VerificationState::Unverified(VerificationLevel::None(
964 DeviceLinkProblem::MissingDevice
965 ))
966 );
967
968 let state = json!({
969 "state": "Untrusted",
970 });
971 let deserialized: State =
972 serde_json::from_value(state).expect("We can deserialize the old trusted value");
973
974 assert_eq!(
975 deserialized.state,
976 VerificationState::Unverified(VerificationLevel::UnsignedDevice)
977 );
978 }
979
980 #[test]
981 fn test_verification_level_deserializes() {
982 #[derive(Deserialize)]
984 struct Container {
985 verification_level: VerificationLevel,
986 }
987 let container = json!({ "verification_level": "VerificationViolation" });
988
989 let deserialized: Container = serde_json::from_value(container)
991 .expect("We can deserialize the old PreviouslyVerified value");
992
993 assert_eq!(deserialized.verification_level, VerificationLevel::VerificationViolation);
995 }
996
997 #[test]
998 fn test_verification_level_deserializes_from_old_previously_verified_value() {
999 #[derive(Deserialize)]
1001 struct Container {
1002 verification_level: VerificationLevel,
1003 }
1004 let container = json!({ "verification_level": "PreviouslyVerified" });
1005
1006 let deserialized: Container = serde_json::from_value(container)
1008 .expect("We can deserialize the old PreviouslyVerified value");
1009
1010 assert_eq!(deserialized.verification_level, VerificationLevel::VerificationViolation);
1012 }
1013
1014 #[test]
1015 fn test_shield_state_code_deserializes() {
1016 #[derive(Deserialize)]
1018 struct Container {
1019 shield_state_code: ShieldStateCode,
1020 }
1021 let container = json!({ "shield_state_code": "VerificationViolation" });
1022
1023 let deserialized: Container = serde_json::from_value(container)
1025 .expect("We can deserialize the old PreviouslyVerified value");
1026
1027 assert_eq!(deserialized.shield_state_code, ShieldStateCode::VerificationViolation);
1029 }
1030
1031 #[test]
1032 fn test_shield_state_code_deserializes_from_old_previously_verified_value() {
1033 #[derive(Deserialize)]
1035 struct Container {
1036 shield_state_code: ShieldStateCode,
1037 }
1038 let container = json!({ "shield_state_code": "PreviouslyVerified" });
1039
1040 let deserialized: Container = serde_json::from_value(container)
1042 .expect("We can deserialize the old PreviouslyVerified value");
1043
1044 assert_eq!(deserialized.shield_state_code, ShieldStateCode::VerificationViolation);
1046 }
1047
1048 #[test]
1049 fn sync_timeline_event_serialisation() {
1050 let room_event = TimelineEvent {
1051 kind: TimelineEventKind::Decrypted(DecryptedRoomEvent {
1052 event: Raw::new(&example_event()).unwrap().cast(),
1053 encryption_info: EncryptionInfo {
1054 sender: user_id!("@sender:example.com").to_owned(),
1055 sender_device: None,
1056 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
1057 curve25519_key: "xxx".to_owned(),
1058 sender_claimed_keys: Default::default(),
1059 },
1060 verification_state: VerificationState::Verified,
1061 session_id: Some("xyz".to_owned()),
1062 },
1063 unsigned_encryption_info: Some(BTreeMap::from([(
1064 UnsignedEventLocation::RelationsReplace,
1065 UnsignedDecryptionResult::UnableToDecrypt(UnableToDecryptInfo {
1066 session_id: Some("xyz".to_owned()),
1067 reason: UnableToDecryptReason::MalformedEncryptedEvent,
1068 }),
1069 )])),
1070 }),
1071 push_actions: Default::default(),
1072 };
1073
1074 let serialized = serde_json::to_value(&room_event).unwrap();
1075
1076 assert_eq!(
1078 serialized,
1079 json!({
1080 "kind": {
1081 "Decrypted": {
1082 "event": {
1083 "content": {"body": "secret", "msgtype": "m.text"},
1084 "event_id": "$xxxxx:example.org",
1085 "origin_server_ts": 2189,
1086 "room_id": "!someroom:example.com",
1087 "sender": "@carl:example.com",
1088 "type": "m.room.message",
1089 },
1090 "encryption_info": {
1091 "sender": "@sender:example.com",
1092 "sender_device": null,
1093 "algorithm_info": {
1094 "MegolmV1AesSha2": {
1095 "curve25519_key": "xxx",
1096 "sender_claimed_keys": {}
1097 }
1098 },
1099 "verification_state": "Verified",
1100 "session_id": "xyz",
1101 },
1102 "unsigned_encryption_info": {
1103 "RelationsReplace": {"UnableToDecrypt": {
1104 "session_id": "xyz",
1105 "reason": "MalformedEncryptedEvent",
1106 }}
1107 }
1108 }
1109 }
1110 })
1111 );
1112
1113 let event: TimelineEvent = serde_json::from_value(serialized).unwrap();
1115 assert_eq!(event.event_id(), Some(event_id!("$xxxxx:example.org").to_owned()));
1116 assert_matches!(
1117 event.encryption_info().unwrap().algorithm_info,
1118 AlgorithmInfo::MegolmV1AesSha2 { .. }
1119 );
1120
1121 let serialized = json!({
1123 "event": {
1124 "content": {"body": "secret", "msgtype": "m.text"},
1125 "event_id": "$xxxxx:example.org",
1126 "origin_server_ts": 2189,
1127 "room_id": "!someroom:example.com",
1128 "sender": "@carl:example.com",
1129 "type": "m.room.message",
1130 },
1131 "encryption_info": {
1132 "sender": "@sender:example.com",
1133 "sender_device": null,
1134 "algorithm_info": {
1135 "MegolmV1AesSha2": {
1136 "curve25519_key": "xxx",
1137 "sender_claimed_keys": {}
1138 }
1139 },
1140 "verification_state": "Verified",
1141 },
1142 });
1143 let event: TimelineEvent = serde_json::from_value(serialized).unwrap();
1144 assert_eq!(event.event_id(), Some(event_id!("$xxxxx:example.org").to_owned()));
1145 assert_matches!(
1146 event.encryption_info().unwrap().algorithm_info,
1147 AlgorithmInfo::MegolmV1AesSha2 { .. }
1148 );
1149 assert_eq!(event.encryption_info().unwrap().session_id, None);
1150
1151 let serialized = json!({
1154 "event": {
1155 "content": {"body": "secret", "msgtype": "m.text"},
1156 "event_id": "$xxxxx:example.org",
1157 "origin_server_ts": 2189,
1158 "room_id": "!someroom:example.com",
1159 "sender": "@carl:example.com",
1160 "type": "m.room.message",
1161 },
1162 "encryption_info": {
1163 "sender": "@sender:example.com",
1164 "sender_device": null,
1165 "algorithm_info": {
1166 "MegolmV1AesSha2": {
1167 "curve25519_key": "xxx",
1168 "sender_claimed_keys": {}
1169 }
1170 },
1171 "verification_state": "Verified",
1172 },
1173 "unsigned_encryption_info": {
1174 "RelationsReplace": {"UnableToDecrypt": {"session_id": "xyz"}}
1175 }
1176 });
1177 let event: TimelineEvent = serde_json::from_value(serialized).unwrap();
1178 assert_eq!(event.event_id(), Some(event_id!("$xxxxx:example.org").to_owned()));
1179 assert_matches!(
1180 event.encryption_info().unwrap().algorithm_info,
1181 AlgorithmInfo::MegolmV1AesSha2 { .. }
1182 );
1183 assert_matches!(event.kind, TimelineEventKind::Decrypted(decrypted) => {
1184 assert_matches!(decrypted.unsigned_encryption_info, Some(map) => {
1185 assert_eq!(map.len(), 1);
1186 let (location, result) = map.into_iter().next().unwrap();
1187 assert_eq!(location, UnsignedEventLocation::RelationsReplace);
1188 assert_matches!(result, UnsignedDecryptionResult::UnableToDecrypt(utd_info) => {
1189 assert_eq!(utd_info.session_id, Some("xyz".to_owned()));
1190 assert_eq!(utd_info.reason, UnableToDecryptReason::Unknown);
1191 })
1192 });
1193 });
1194 }
1195
1196 #[test]
1197 fn sync_timeline_event_deserialisation_migration_for_withheld() {
1198 let serialized = json!({
1215 "kind": {
1216 "UnableToDecrypt": {
1217 "event": {
1218 "content": {
1219 "algorithm": "m.megolm.v1.aes-sha2",
1220 "ciphertext": "AwgAEoABzL1JYhqhjW9jXrlT3M6H8mJ4qffYtOQOnPuAPNxsuG20oiD/Fnpv6jnQGhU6YbV9pNM+1mRnTvxW3CbWOPjLKqCWTJTc7Q0vDEVtYePg38ncXNcwMmfhgnNAoW9S7vNs8C003x3yUl6NeZ8bH+ci870BZL+kWM/lMl10tn6U7snNmSjnE3ckvRdO+11/R4//5VzFQpZdf4j036lNSls/WIiI67Fk9iFpinz9xdRVWJFVdrAiPFwb8L5xRZ8aX+e2JDMlc1eW8gk",
1221 "device_id": "SKCGPNUWAU",
1222 "sender_key": "Gim/c7uQdSXyrrUbmUOrBT6sMC0gO7QSLmOK6B7NOm0",
1223 "session_id": "hgLyeSqXfb8vc5AjQLsg6TSHVu0HJ7HZ4B6jgMvxkrs"
1224 },
1225 "event_id": "$xxxxx:example.org",
1226 "origin_server_ts": 2189,
1227 "room_id": "!someroom:example.com",
1228 "sender": "@carl:example.com",
1229 "type": "m.room.message"
1230 },
1231 "utd_info": {
1232 "reason": "MissingMegolmSession",
1233 "session_id": "session000"
1234 }
1235 }
1236 }
1237 });
1238
1239 let result = serde_json::from_value(serialized);
1240 assert!(result.is_ok());
1241
1242 let event: TimelineEvent = result.unwrap();
1244 assert_matches!(
1245 event.kind,
1246 TimelineEventKind::UnableToDecrypt { utd_info, .. }=> {
1247 assert_matches!(
1248 utd_info.reason,
1249 UnableToDecryptReason::MissingMegolmSession { withheld_code: None }
1250 );
1251 }
1252 )
1253 }
1254
1255 #[test]
1256 fn unable_to_decrypt_info_migration_for_withheld() {
1257 let old_format = json!({
1258 "reason": "MissingMegolmSession",
1259 "session_id": "session000"
1260 });
1261
1262 let deserialized = serde_json::from_value::<UnableToDecryptInfo>(old_format).unwrap();
1263 let session_id = Some("session000".to_owned());
1264
1265 assert_eq!(deserialized.session_id, session_id);
1266 assert_eq!(
1267 deserialized.reason,
1268 UnableToDecryptReason::MissingMegolmSession { withheld_code: None },
1269 );
1270
1271 let new_format = json!({
1272 "session_id": "session000",
1273 "reason": {
1274 "MissingMegolmSession": {
1275 "withheld_code": null
1276 }
1277 }
1278 });
1279
1280 let deserialized = serde_json::from_value::<UnableToDecryptInfo>(new_format).unwrap();
1281
1282 assert_eq!(
1283 deserialized.reason,
1284 UnableToDecryptReason::MissingMegolmSession { withheld_code: None },
1285 );
1286 assert_eq!(deserialized.session_id, session_id);
1287 }
1288
1289 #[test]
1290 fn unable_to_decrypt_reason_is_missing_room_key() {
1291 let reason = UnableToDecryptReason::MissingMegolmSession { withheld_code: None };
1292 assert!(reason.is_missing_room_key());
1293
1294 let reason = UnableToDecryptReason::MissingMegolmSession {
1295 withheld_code: Some(WithheldCode::Blacklisted),
1296 };
1297 assert!(!reason.is_missing_room_key());
1298
1299 let reason = UnableToDecryptReason::UnknownMegolmMessageIndex;
1300 assert!(reason.is_missing_room_key());
1301 }
1302
1303 #[test]
1304 fn snapshot_test_verification_level() {
1305 with_settings!({ prepend_module_to_snapshot => false }, {
1306 assert_json_snapshot!(VerificationLevel::VerificationViolation);
1307 assert_json_snapshot!(VerificationLevel::UnsignedDevice);
1308 assert_json_snapshot!(VerificationLevel::None(DeviceLinkProblem::InsecureSource));
1309 assert_json_snapshot!(VerificationLevel::None(DeviceLinkProblem::MissingDevice));
1310 assert_json_snapshot!(VerificationLevel::UnverifiedIdentity);
1311 });
1312 }
1313
1314 #[test]
1315 fn snapshot_test_verification_states() {
1316 with_settings!({ prepend_module_to_snapshot => false }, {
1317 assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::UnsignedDevice));
1318 assert_json_snapshot!(VerificationState::Unverified(
1319 VerificationLevel::VerificationViolation
1320 ));
1321 assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::None(
1322 DeviceLinkProblem::InsecureSource,
1323 )));
1324 assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::None(
1325 DeviceLinkProblem::MissingDevice,
1326 )));
1327 assert_json_snapshot!(VerificationState::Verified);
1328 });
1329 }
1330
1331 #[test]
1332 fn snapshot_test_shield_states() {
1333 with_settings!({ prepend_module_to_snapshot => false }, {
1334 assert_json_snapshot!(ShieldState::None);
1335 assert_json_snapshot!(ShieldState::Red {
1336 code: ShieldStateCode::UnverifiedIdentity,
1337 message: "a message"
1338 });
1339 assert_json_snapshot!(ShieldState::Grey {
1340 code: ShieldStateCode::AuthenticityNotGuaranteed,
1341 message: "authenticity of this message cannot be guaranteed",
1342 });
1343 });
1344 }
1345
1346 #[test]
1347 fn snapshot_test_shield_codes() {
1348 with_settings!({ prepend_module_to_snapshot => false }, {
1349 assert_json_snapshot!(ShieldStateCode::AuthenticityNotGuaranteed);
1350 assert_json_snapshot!(ShieldStateCode::UnknownDevice);
1351 assert_json_snapshot!(ShieldStateCode::UnsignedDevice);
1352 assert_json_snapshot!(ShieldStateCode::UnverifiedIdentity);
1353 assert_json_snapshot!(ShieldStateCode::SentInClear);
1354 assert_json_snapshot!(ShieldStateCode::VerificationViolation);
1355 });
1356 }
1357
1358 #[test]
1359 fn snapshot_test_algorithm_info() {
1360 let mut map = BTreeMap::new();
1361 map.insert(DeviceKeyAlgorithm::Curve25519, "claimedclaimedcurve25519".to_owned());
1362 map.insert(DeviceKeyAlgorithm::Ed25519, "claimedclaimeded25519".to_owned());
1363 let info = AlgorithmInfo::MegolmV1AesSha2 {
1364 curve25519_key: "curvecurvecurve".into(),
1365 sender_claimed_keys: BTreeMap::from([
1366 (DeviceKeyAlgorithm::Curve25519, "claimedclaimedcurve25519".to_owned()),
1367 (DeviceKeyAlgorithm::Ed25519, "claimedclaimeded25519".to_owned()),
1368 ]),
1369 };
1370
1371 with_settings!({ prepend_module_to_snapshot => false }, {
1372 assert_json_snapshot!(info)
1373 });
1374 }
1375
1376 #[test]
1377 fn snapshot_test_encryption_info() {
1378 let info = EncryptionInfo {
1379 sender: user_id!("@alice:localhost").to_owned(),
1380 sender_device: Some(device_id!("ABCDEFGH").to_owned()),
1381 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
1382 curve25519_key: "curvecurvecurve".into(),
1383 sender_claimed_keys: Default::default(),
1384 },
1385 verification_state: VerificationState::Verified,
1386 session_id: Some("mysessionid76".to_owned()),
1387 };
1388
1389 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
1390 assert_json_snapshot!(info)
1391 })
1392 }
1393
1394 #[test]
1395 fn snapshot_test_sync_timeline_event() {
1396 let room_event = TimelineEvent {
1397 kind: TimelineEventKind::Decrypted(DecryptedRoomEvent {
1398 event: Raw::new(&example_event()).unwrap().cast(),
1399 encryption_info: EncryptionInfo {
1400 sender: user_id!("@sender:example.com").to_owned(),
1401 sender_device: Some(device_id!("ABCDEFGHIJ").to_owned()),
1402 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
1403 curve25519_key: "xxx".to_owned(),
1404 sender_claimed_keys: BTreeMap::from([
1405 (
1406 DeviceKeyAlgorithm::Ed25519,
1407 "I3YsPwqMZQXHkSQbjFNEs7b529uac2xBpI83eN3LUXo".to_owned(),
1408 ),
1409 (
1410 DeviceKeyAlgorithm::Curve25519,
1411 "qzdW3F5IMPFl0HQgz5w/L5Oi/npKUFn8Um84acIHfPY".to_owned(),
1412 ),
1413 ]),
1414 },
1415 verification_state: VerificationState::Verified,
1416 session_id: Some("mysessionid112".to_owned()),
1417 },
1418 unsigned_encryption_info: Some(BTreeMap::from([(
1419 UnsignedEventLocation::RelationsThreadLatestEvent,
1420 UnsignedDecryptionResult::UnableToDecrypt(UnableToDecryptInfo {
1421 session_id: Some("xyz".to_owned()),
1422 reason: UnableToDecryptReason::MissingMegolmSession {
1423 withheld_code: Some(WithheldCode::Unverified),
1424 },
1425 }),
1426 )])),
1427 }),
1428 push_actions: Default::default(),
1429 };
1430
1431 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
1432 assert_json_snapshot! {
1435 serde_json::to_value(&room_event).unwrap(),
1436 }
1437 });
1438 }
1439}