1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4pub type SecretVersion = u32;
6
7#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
9pub enum PrivacyMode {
10 #[default]
12 Public,
13 Private,
15}
16
17#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
19pub enum RoomCipherSpec {
20 Aes256Gcm,
22}
23
24#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
26pub enum SealedBytes {
27 Public { value: Vec<u8> },
29 Private {
31 ciphertext: Vec<u8>,
32 nonce: [u8; 12],
33 secret_version: SecretVersion,
34 declared_len_bytes: u32,
35 },
36}
37
38impl SealedBytes {
39 pub fn public(value: Vec<u8>) -> Self {
41 Self::Public { value }
42 }
43
44 pub fn private(
46 ciphertext: Vec<u8>,
47 nonce: [u8; 12],
48 secret_version: SecretVersion,
49 declared_len_bytes: u32,
50 ) -> Self {
51 Self::Private {
52 ciphertext,
53 nonce,
54 secret_version,
55 declared_len_bytes,
56 }
57 }
58
59 pub fn is_public(&self) -> bool {
61 matches!(self, Self::Public { .. })
62 }
63
64 pub fn is_private(&self) -> bool {
66 matches!(self, Self::Private { .. })
67 }
68
69 pub fn declared_len(&self) -> usize {
71 match self {
72 Self::Public { value } => value.len(),
73 Self::Private {
74 declared_len_bytes, ..
75 } => *declared_len_bytes as usize,
76 }
77 }
78
79 pub fn secret_version(&self) -> Option<SecretVersion> {
81 match self {
82 Self::Public { .. } => None,
83 Self::Private { secret_version, .. } => Some(*secret_version),
84 }
85 }
86
87 pub fn to_string_lossy(&self) -> String {
90 match self {
91 Self::Public { value } => String::from_utf8_lossy(value).to_string(),
92 Self::Private {
93 declared_len_bytes,
94 secret_version,
95 ..
96 } => {
97 format!(
98 "[Encrypted: {} bytes, v{}]",
99 declared_len_bytes, secret_version
100 )
101 }
102 }
103 }
104
105 pub fn as_public_bytes(&self) -> Option<&[u8]> {
107 match self {
108 Self::Public { value } => Some(value),
109 Self::Private { .. } => None,
110 }
111 }
112}
113
114impl fmt::Display for SealedBytes {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "{}", self.to_string_lossy())
117 }
118}
119
120#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
122pub struct RoomDisplayMetadata {
123 pub name: SealedBytes,
124 pub description: Option<SealedBytes>,
125}
126
127impl RoomDisplayMetadata {
128 pub fn public(name: String, description: Option<String>) -> Self {
130 Self {
131 name: SealedBytes::public(name.into_bytes()),
132 description: description.map(|d| SealedBytes::public(d.into_bytes())),
133 }
134 }
135
136 pub fn private(
138 name_ciphertext: Vec<u8>,
139 name_nonce: [u8; 12],
140 name_declared_len: u32,
141 description: Option<(Vec<u8>, [u8; 12], u32)>,
142 secret_version: SecretVersion,
143 ) -> Self {
144 Self {
145 name: SealedBytes::private(
146 name_ciphertext,
147 name_nonce,
148 secret_version,
149 name_declared_len,
150 ),
151 description: description.map(|(ciphertext, nonce, declared_len)| {
152 SealedBytes::private(ciphertext, nonce, secret_version, declared_len)
153 }),
154 }
155 }
156
157 pub fn is_public(&self) -> bool {
159 self.name.is_public() && self.description.as_ref().is_none_or(|d| d.is_public())
160 }
161
162 pub fn is_private(&self) -> bool {
164 self.name.is_private()
165 }
166}
167
168impl Default for RoomDisplayMetadata {
169 fn default() -> Self {
170 Self::public("Default Room Name".to_string(), None)
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_privacy_mode_default() {
180 assert_eq!(PrivacyMode::default(), PrivacyMode::Public);
181 }
182
183 #[test]
184 fn test_sealed_bytes_public() {
185 let data = b"test data".to_vec();
186 let sealed = SealedBytes::public(data.clone());
187
188 assert!(sealed.is_public());
189 assert!(!sealed.is_private());
190 assert_eq!(sealed.declared_len(), data.len());
191 assert_eq!(sealed.secret_version(), None);
192 }
193
194 #[test]
195 fn test_sealed_bytes_private() {
196 let ciphertext = vec![1, 2, 3, 4];
197 let nonce = [0u8; 12];
198 let secret_version = 1;
199 let declared_len = 10;
200
201 let sealed = SealedBytes::private(ciphertext.clone(), nonce, secret_version, declared_len);
202
203 assert!(!sealed.is_public());
204 assert!(sealed.is_private());
205 assert_eq!(sealed.declared_len(), declared_len as usize);
206 assert_eq!(sealed.secret_version(), Some(secret_version));
207 }
208}