1use crate::room_state::member::MemberId;
2use crate::room_state::privacy::{PrivacyMode, RoomDisplayMetadata};
3use crate::room_state::ChatRoomParametersV1;
4use crate::util::truncated_base64;
5use crate::ChatRoomStateV1;
6use ed25519_dalek::{Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey};
7use freenet_scaffold::util::{fast_hash, FastHash};
8use freenet_scaffold::ComposableState;
9use serde::{Deserialize, Serialize};
10use std::fmt;
11
12#[derive(Serialize, Deserialize, Clone, PartialEq)]
13pub struct AuthorizedConfigurationV1 {
14 pub configuration: Configuration,
15 pub signature: Signature,
16}
17
18impl ComposableState for AuthorizedConfigurationV1 {
19 type ParentState = ChatRoomStateV1;
20 type Summary = u32;
21 type Delta = AuthorizedConfigurationV1;
22 type Parameters = ChatRoomParametersV1;
23
24 fn verify(
25 &self,
26 _parent_state: &Self::ParentState,
27 parameters: &Self::Parameters,
28 ) -> Result<(), String> {
29 self.verify_signature(¶meters.owner)
30 .map_err(|e| format!("Invalid signature: {}", e))
31 }
32
33 fn summarize(
34 &self,
35 _parent_state: &Self::ParentState,
36 _parameters: &Self::Parameters,
37 ) -> Self::Summary {
38 self.configuration.configuration_version
39 }
40
41 fn delta(
42 &self,
43 _parent_state: &Self::ParentState,
44 _parameters: &Self::Parameters,
45 old_version: &Self::Summary,
46 ) -> Option<Self::Delta> {
47 if self.configuration.configuration_version > *old_version {
48 Some(self.clone())
49 } else {
50 None
51 }
52 }
53
54 fn apply_delta(
55 &mut self,
56 _parent_state: &Self::ParentState,
57 parameters: &Self::Parameters,
58 delta: &Option<Self::Delta>,
59 ) -> Result<(), String> {
60 if let Some(delta) = delta {
61 delta
63 .verify_signature(¶meters.owner)
64 .map_err(|e| format!("Invalid signature: {}", e))?;
65
66 if delta.configuration.configuration_version <= self.configuration.configuration_version
68 {
69 return Err(
70 "New configuration version must be greater than the current version"
71 .to_string(),
72 );
73 }
74
75 if delta.configuration.owner_member_id != self.configuration.owner_member_id {
77 return Err("Cannot change the owner_member_id".to_string());
78 }
79
80 if delta.configuration.max_recent_messages == 0
82 || delta.configuration.max_user_bans == 0
83 || delta.configuration.max_message_size == 0
84 || delta.configuration.max_nickname_size == 0
85 || delta.configuration.max_members == 0
86 || delta.configuration.max_room_name == 0
87 || delta.configuration.max_room_description == 0
88 {
89 return Err("Invalid configuration values".to_string());
90 }
91
92 if delta.configuration.display.name.declared_len() > delta.configuration.max_room_name {
94 return Err(format!(
95 "Room name declared length {} exceeds max_room_name {}",
96 delta.configuration.display.name.declared_len(),
97 delta.configuration.max_room_name
98 ));
99 }
100
101 if let Some(desc) = &delta.configuration.display.description {
102 if desc.declared_len() > delta.configuration.max_room_description {
103 return Err(format!(
104 "Room description declared length {} exceeds max_room_description {}",
105 desc.declared_len(),
106 delta.configuration.max_room_description
107 ));
108 }
109 }
110
111 if delta.configuration.privacy_mode == PrivacyMode::Private
113 && delta.configuration.display.name.is_public()
114 {
115 return Err("Private room must have encrypted display metadata".to_string());
116 }
117
118 self.configuration = delta.configuration.clone();
120 self.signature = delta.signature;
121 }
122
123 Ok(())
124 }
125}
126
127impl AuthorizedConfigurationV1 {
128 pub fn new(configuration: Configuration, owner_signing_key: &SigningKey) -> Self {
129 let mut serialized_config = Vec::new();
130 ciborium::ser::into_writer(&configuration, &mut serialized_config)
131 .expect("Serialization should not fail");
132 let signature = owner_signing_key.sign(&serialized_config);
133
134 Self {
135 configuration,
136 signature,
137 }
138 }
139
140 pub fn with_signature(configuration: Configuration, signature: Signature) -> Self {
143 Self {
144 configuration,
145 signature,
146 }
147 }
148
149 pub fn verify_signature(
150 &self,
151 owner_verifying_key: &VerifyingKey,
152 ) -> Result<(), SignatureError> {
153 let mut serialized_config = Vec::new();
154 ciborium::ser::into_writer(&self.configuration, &mut serialized_config)
155 .expect("Serialization should not fail");
156 owner_verifying_key.verify(&serialized_config, &self.signature)
157 }
158
159 pub fn id(&self) -> FastHash {
160 fast_hash(&self.signature.to_bytes())
161 }
162}
163
164impl Default for AuthorizedConfigurationV1 {
165 fn default() -> Self {
166 let default_config = Configuration::default();
167 let default_key = SigningKey::from_bytes(&[0; 32]);
168 Self::new(default_config, &default_key)
169 }
170}
171
172impl Default for Configuration {
173 fn default() -> Self {
174 Configuration {
175 owner_member_id: MemberId(FastHash(0)), configuration_version: 1,
177 privacy_mode: PrivacyMode::default(),
178 display: RoomDisplayMetadata::default(),
179 max_recent_messages: 100,
180 max_user_bans: 10,
181 max_message_size: 1000,
182 max_nickname_size: 50,
183 max_members: 200,
184 max_room_name: 100,
185 max_room_description: 500,
186 }
187 }
188}
189
190impl fmt::Debug for AuthorizedConfigurationV1 {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 f.debug_struct("AuthorizedConfiguration")
193 .field("configuration", &self.configuration)
194 .field(
195 "signature",
196 &format_args!("{}", truncated_base64(self.signature.to_bytes())),
197 )
198 .finish()
199 }
200}
201
202#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
203pub struct Configuration {
204 pub owner_member_id: MemberId,
205 pub configuration_version: u32,
206 pub privacy_mode: PrivacyMode,
207 pub display: RoomDisplayMetadata,
208 pub max_recent_messages: usize,
209 pub max_user_bans: usize,
210 pub max_message_size: usize,
211 pub max_nickname_size: usize,
212 pub max_members: usize,
213 pub max_room_name: usize,
214 pub max_room_description: usize,
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220 use rand::rngs::OsRng;
221
222 #[test]
223 fn test_verify() {
224 let owner_signing_key = SigningKey::generate(&mut OsRng);
225 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
226 let configuration = Configuration::default();
227 let authorized_configuration =
228 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
229
230 assert!(authorized_configuration
231 .verify_signature(&owner_verifying_key)
232 .is_ok());
233
234 let parent_state = ChatRoomStateV1 {
235 configuration: authorized_configuration.clone(),
236 ..ChatRoomStateV1::default()
237 };
238 let parameters = ChatRoomParametersV1 {
239 owner: owner_verifying_key,
240 };
241
242 assert!(authorized_configuration
243 .verify(&parent_state, ¶meters)
244 .is_ok());
245 }
246
247 #[test]
248 fn test_verify_fail() {
249 let owner_signing_key = SigningKey::generate(&mut OsRng);
250 let configuration = Configuration::default();
251 let authorized_configuration =
252 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
253
254 let wrong_owner_signing_key = SigningKey::generate(&mut OsRng);
255 let wrong_owner_verifying_key = VerifyingKey::from(&wrong_owner_signing_key);
256
257 assert!(authorized_configuration
258 .verify_signature(&wrong_owner_verifying_key)
259 .is_err());
260
261 let parent_state = ChatRoomStateV1 {
262 configuration: authorized_configuration.clone(),
263 ..ChatRoomStateV1::default()
264 };
265 let parameters = ChatRoomParametersV1 {
266 owner: wrong_owner_verifying_key,
267 };
268
269 assert!(authorized_configuration
270 .verify(&parent_state, ¶meters)
271 .is_err());
272 }
273
274 #[test]
275 fn test_summarize() {
276 let owner_signing_key = SigningKey::generate(&mut OsRng);
277 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
278 let configuration = Configuration::default();
279 let authorized_configuration =
280 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
281
282 let parent_state = ChatRoomStateV1 {
283 configuration: authorized_configuration.clone(),
284 ..Default::default()
285 };
286 let parameters = ChatRoomParametersV1 {
287 owner: owner_verifying_key,
288 };
289
290 assert_eq!(
291 authorized_configuration.summarize(&parent_state, ¶meters),
292 configuration.configuration_version
293 );
294 }
295
296 #[test]
297 fn test_delta_new_version() {
298 let owner_signing_key = SigningKey::generate(&mut OsRng);
299 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
300 let configuration = Configuration::default();
301 let authorized_configuration =
302 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
303
304 let parent_state = ChatRoomStateV1 {
305 configuration: authorized_configuration.clone(),
306 ..Default::default()
307 };
308 let parameters = ChatRoomParametersV1 {
309 owner: owner_verifying_key,
310 };
311
312 let new_configuration = Configuration {
313 configuration_version: 2,
314 ..configuration.clone()
315 };
316 let new_authorized_configuration =
317 AuthorizedConfigurationV1::new(new_configuration.clone(), &owner_signing_key);
318
319 assert_eq!(
320 new_authorized_configuration.delta(&parent_state, ¶meters, &1),
321 Some(new_authorized_configuration)
322 );
323 }
324
325 #[test]
326 fn test_delta_older_version() {
327 let owner_signing_key = SigningKey::generate(&mut OsRng);
328 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
329
330 let old_configuration = Configuration {
332 configuration_version: 1,
333 ..Configuration::default()
334 };
335 let old_authorized_configuration =
336 AuthorizedConfigurationV1::new(old_configuration.clone(), &owner_signing_key);
337
338 let parent_state = ChatRoomStateV1 {
339 configuration: old_authorized_configuration.clone(),
340 ..Default::default()
341 };
342 let parameters = ChatRoomParametersV1 {
343 owner: owner_verifying_key,
344 };
345
346 assert_eq!(
349 old_authorized_configuration.delta(&parent_state, ¶meters, &2),
350 None
351 );
352 }
353
354 #[test]
355 fn test_apply_delta_should_apply() {
356 let owner_signing_key = SigningKey::generate(&mut OsRng);
357 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
358 let configuration = Configuration::default();
359 let mut authorized_configuration =
360 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
361
362 let parent_state = ChatRoomStateV1 {
363 configuration: authorized_configuration.clone(),
364 ..Default::default()
365 };
366 let parameters = ChatRoomParametersV1 {
367 owner: owner_verifying_key,
368 };
369
370 let new_configuration = Configuration {
371 configuration_version: 2,
372 ..configuration.clone()
373 };
374 let new_authorized_configuration =
375 AuthorizedConfigurationV1::new(new_configuration.clone(), &owner_signing_key);
376
377 authorized_configuration
378 .apply_delta(
379 &parent_state,
380 ¶meters,
381 &Some(new_authorized_configuration.clone()),
382 )
383 .unwrap();
384
385 assert_eq!(authorized_configuration, new_authorized_configuration);
386 }
387
388 #[test]
389 fn test_apply_delta_old_version() {
390 let owner_signing_key = SigningKey::generate(&mut OsRng);
391 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
392 let configuration = Configuration::default();
393 let mut authorized_configuration =
394 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
395
396 let orig_authorized_configuration = authorized_configuration.clone();
397
398 let parent_state = ChatRoomStateV1 {
399 configuration: authorized_configuration.clone(),
400 ..Default::default()
401 };
402 let parameters = ChatRoomParametersV1 {
403 owner: owner_verifying_key,
404 };
405
406 let new_configuration = Configuration {
407 configuration_version: 0,
408 ..configuration.clone()
409 };
410 let new_authorized_configuration =
411 AuthorizedConfigurationV1::new(new_configuration.clone(), &owner_signing_key);
412
413 let result = authorized_configuration.apply_delta(
414 &parent_state,
415 ¶meters,
416 &Some(new_authorized_configuration),
417 );
418
419 assert!(result.is_err());
420 assert_eq!(
421 result.unwrap_err(),
422 "New configuration version must be greater than the current version"
423 );
424 assert_eq!(authorized_configuration, orig_authorized_configuration);
425 }
426
427 #[test]
428 fn test_apply_delta_change_owner() {
429 let owner_signing_key = SigningKey::generate(&mut OsRng);
430 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
431 let configuration = Configuration {
432 owner_member_id: MemberId(FastHash(1)),
433 ..Configuration::default()
434 };
435 let mut authorized_configuration =
436 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
437
438 let parent_state = ChatRoomStateV1 {
439 configuration: authorized_configuration.clone(),
440 ..Default::default()
441 };
442 let parameters = ChatRoomParametersV1 {
443 owner: owner_verifying_key,
444 };
445
446 let mut new_configuration = configuration.clone();
447 new_configuration.configuration_version += 1;
448 new_configuration.owner_member_id = MemberId(FastHash(2));
449 let new_authorized_configuration =
450 AuthorizedConfigurationV1::new(new_configuration, &owner_signing_key);
451
452 let result = authorized_configuration.apply_delta(
453 &parent_state,
454 ¶meters,
455 &Some(new_authorized_configuration),
456 );
457
458 assert!(result.is_err());
459 assert_eq!(result.unwrap_err(), "Cannot change the owner_member_id");
460 }
461
462 #[test]
463 fn test_apply_delta_invalid_values() {
464 let owner_signing_key = SigningKey::generate(&mut OsRng);
465 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
466 let configuration = Configuration::default();
467 let mut authorized_configuration =
468 AuthorizedConfigurationV1::new(configuration.clone(), &owner_signing_key);
469
470 let parent_state = ChatRoomStateV1 {
471 configuration: authorized_configuration.clone(),
472 ..Default::default()
473 };
474 let parameters = ChatRoomParametersV1 {
475 owner: owner_verifying_key,
476 };
477
478 let mut new_configuration = configuration.clone();
479 new_configuration.configuration_version += 1;
480 new_configuration.max_recent_messages = 0;
481 let new_authorized_configuration =
482 AuthorizedConfigurationV1::new(new_configuration, &owner_signing_key);
483
484 let result = authorized_configuration.apply_delta(
485 &parent_state,
486 ¶meters,
487 &Some(new_authorized_configuration),
488 );
489
490 assert!(result.is_err());
491 assert_eq!(result.unwrap_err(), "Invalid configuration values");
492 }
493}