1use crate::room_state::ban::BansV1;
2use crate::room_state::ChatRoomParametersV1;
3use crate::util::{sign_struct, truncated_base32, verify_struct};
4use crate::ChatRoomStateV1;
5use ed25519_dalek::{Signature, SigningKey, VerifyingKey};
6use freenet_scaffold::util::{fast_hash, FastHash};
7use freenet_scaffold::ComposableState;
8use serde::{Deserialize, Serialize};
9use std::collections::{HashMap, HashSet};
10use std::fmt;
11use std::fmt::{Debug, Display};
12use std::hash::{Hash, Hasher};
13
14#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug, Default)]
21pub struct MembersV1 {
22 pub members: Vec<AuthorizedMember>,
23}
24
25impl ComposableState for MembersV1 {
26 type ParentState = ChatRoomStateV1;
27 type Summary = HashSet<MemberId>;
28 type Delta = MembersDelta;
29 type Parameters = ChatRoomParametersV1;
30
31 fn verify(
32 &self,
33 parent_state: &Self::ParentState,
34 parameters: &Self::Parameters,
35 ) -> Result<(), String> {
36 if self.members.is_empty() {
37 return Ok(());
38 }
39
40 if self.members.len() > parent_state.configuration.configuration.max_members {
41 return Err(format!(
42 "Too many members: {} > {}",
43 self.members.len(),
44 parent_state.configuration.configuration.max_members
45 ));
46 }
47
48 let owner_id = parameters.owner_id();
49 let members_by_id = self.members_by_member_id();
50
51 for member in &self.members {
52 if member.member.id() == owner_id {
53 return Err("Owner should not be included in the members list".to_string());
54 }
55 if member.member.member_vk == parameters.owner {
56 return Err(
57 "Member cannot have the same verifying key as the room owner".to_string(),
58 );
59 }
60 if member.member.invited_by == member.member.id() {
61 return Err("Self-invitation detected".to_string());
62 }
63
64 self.get_invite_chain_with_lookup(member, parameters, &members_by_id)?;
66 }
67 Ok(())
68 }
69 fn summarize(
70 &self,
71 _parent_state: &Self::ParentState,
72 _parameters: &Self::Parameters,
73 ) -> Self::Summary {
74 self.members.iter().map(|m| m.member.id()).collect()
75 }
76
77 fn delta(
78 &self,
79 _parent_state: &Self::ParentState,
80 _parameters: &Self::Parameters,
81 old_state_summary: &Self::Summary,
82 ) -> Option<Self::Delta> {
83 let added = self
84 .members
85 .iter()
86 .filter(|m| !old_state_summary.contains(&m.member.id()))
87 .cloned()
88 .collect::<Vec<_>>();
89 if added.is_empty() {
90 None
91 } else {
92 Some(MembersDelta { added })
93 }
94 }
95
96 fn apply_delta(
97 &mut self,
98 parent_state: &Self::ParentState,
99 parameters: &Self::Parameters,
100 delta: &Option<Self::Delta>,
101 ) -> Result<(), String> {
102 let max_members = parent_state.configuration.configuration.max_members;
103
104 if let Some(delta) = delta {
105 let mut combined_members_by_id = self.members_by_member_id();
111 for member in &delta.added {
112 combined_members_by_id
113 .entry(member.member.id())
114 .or_insert(member);
115 }
116
117 for member in &delta.added {
119 self.verify_member_invite_with_lookup(member, parameters, &combined_members_by_id)?;
120 }
121
122 for member in &delta.added {
126 if self
128 .members
129 .iter()
130 .any(|m| m.member.id() == member.member.id())
131 {
132 continue;
133 }
134 self.members.push(member.clone());
135 }
136 }
137
138 self.remove_banned_members(&parent_state.bans, parameters);
140
141 self.remove_excess_members(parameters, max_members);
143
144 self.members.sort_by_key(|m| m.member.id());
146
147 Ok(())
148 }
149}
150
151impl MembersV1 {
152 fn verify_member_invite_with_lookup(
157 &self,
158 member: &AuthorizedMember,
159 parameters: &ChatRoomParametersV1,
160 members_by_id: &HashMap<MemberId, &AuthorizedMember>,
161 ) -> Result<(), String> {
162 if member.member.invited_by == parameters.owner_id() {
163 member
165 .verify_signature(¶meters.owner)
166 .map_err(|e| format!("Invalid signature for member invited by owner: {}", e))?;
167 } else {
168 self.get_invite_chain_with_lookup(member, parameters, members_by_id)?;
170 }
171 Ok(())
172 }
173}
174
175impl MembersV1 {
176 pub fn is_inviter_of(
179 &self,
180 member_id: MemberId,
181 target_id: MemberId,
182 params: &ChatRoomParametersV1,
183 ) -> bool {
184 if member_id == params.owner_id() {
185 self.members
187 .iter()
188 .find(|m| m.member.id() == target_id)
189 .map(|m| m.member.invited_by == member_id)
190 .unwrap_or(false)
191 } else {
192 self.members
194 .iter()
195 .find(|m| m.member.id() == target_id)
196 .map(|m| m.member.invited_by == member_id)
197 .unwrap_or(false)
198 }
199 }
200
201 pub fn members_by_member_id(&self) -> HashMap<MemberId, &AuthorizedMember> {
203 self.members.iter().map(|m| (m.member.id(), m)).collect()
204 }
205
206 pub fn has_banned_members(&self, bans_v1: &BansV1, parameters: &ChatRoomParametersV1) -> bool {
208 self.check_banned_members(bans_v1, parameters).is_some()
209 }
210
211 fn remove_banned_members(&mut self, bans_v1: &BansV1, _parameters: &ChatRoomParametersV1) {
213 let mut banned_ids = HashSet::new();
214 for ban in &bans_v1.0 {
215 banned_ids.insert(ban.ban.banned_user);
216 banned_ids.extend(self.get_downstream_members(ban.ban.banned_user));
217 }
218 self.members
219 .retain(|m| !banned_ids.contains(&m.member.id()));
220 }
221
222 fn get_downstream_members(&self, member_id: MemberId) -> HashSet<MemberId> {
224 let mut downstream = HashSet::new();
225 let mut to_check = vec![member_id];
226 while let Some(current) = to_check.pop() {
227 for member in &self.members {
228 if member.member.invited_by == current {
229 downstream.insert(member.member.id());
230 to_check.push(member.member.id());
231 }
232 }
233 }
234 downstream
235 }
236
237 fn remove_excess_members(&mut self, parameters: &ChatRoomParametersV1, max_members: usize) {
241 if self.members.len() <= max_members {
242 return;
243 }
244
245 let members_by_id = self.members_by_member_id();
246 let owner_id = parameters.owner_id();
247
248 let mut chain_lengths: Vec<(MemberId, usize)> = self
250 .members
251 .iter()
252 .map(|m| {
253 let len = Self::invite_chain_length(m, owner_id, &members_by_id);
254 (m.member.id(), len)
255 })
256 .collect();
257
258 chain_lengths.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| b.0.cmp(&a.0)));
260
261 let excess = self.members.len() - max_members;
263 let ids_to_remove: HashSet<MemberId> = chain_lengths
264 .iter()
265 .take(excess)
266 .map(|(id, _)| *id)
267 .collect();
268
269 self.members
270 .retain(|m| !ids_to_remove.contains(&m.member.id()));
271 }
272
273 fn check_banned_members(
277 &self,
278 bans_v1: &BansV1,
279 parameters: &ChatRoomParametersV1,
280 ) -> Option<HashSet<MemberId>> {
281 let banned_user_ids: HashSet<MemberId> =
282 bans_v1.0.iter().map(|b| b.ban.banned_user).collect();
283 if banned_user_ids.is_empty() {
284 return None;
285 }
286
287 let members_by_id = self.members_by_member_id();
288 let owner_id = parameters.owner_id();
289 let mut result = HashSet::new();
290
291 for m in &self.members {
292 let chain_ids = Self::invite_chain_ids(m, owner_id, &members_by_id);
294 if chain_ids.iter().any(|id| banned_user_ids.contains(id)) {
295 result.insert(m.member.id());
296 }
297 }
298
299 if result.is_empty() {
300 None
301 } else {
302 Some(result)
303 }
304 }
305
306 pub fn get_invite_chain(
309 &self,
310 member: &AuthorizedMember,
311 parameters: &ChatRoomParametersV1,
312 ) -> Result<Vec<AuthorizedMember>, String> {
313 let members_by_id = self.members_by_member_id();
314 self.get_invite_chain_with_lookup(member, parameters, &members_by_id)
315 }
316
317 fn get_invite_chain_with_lookup(
320 &self,
321 member: &AuthorizedMember,
322 parameters: &ChatRoomParametersV1,
323 members_by_id: &HashMap<MemberId, &AuthorizedMember>,
324 ) -> Result<Vec<AuthorizedMember>, String> {
325 let mut invite_chain = Vec::new();
326 let mut current_member = member;
327 let owner_id = parameters.owner_id();
328 let mut visited_members = HashSet::new();
329
330 loop {
331 if !visited_members.insert(current_member.member.id()) {
332 return Err(format!(
333 "Circular invite chain detected for member {:?}",
334 current_member.member.id()
335 ));
336 }
337
338 if current_member.member.invited_by == current_member.member.id() {
339 return Err(format!(
340 "Self-invitation detected for member {:?}",
341 current_member.member.id()
342 ));
343 }
344
345 if current_member.member.invited_by == owner_id {
346 current_member
347 .verify_signature(¶meters.owner)
348 .map_err(|e| {
349 format!(
350 "Invalid signature for member {:?} invited by owner: {}",
351 current_member.member.id(),
352 e
353 )
354 })?;
355 break;
356 } else {
357 let inviter = members_by_id
358 .get(¤t_member.member.invited_by)
359 .ok_or_else(|| {
360 format!(
361 "Inviter {:?} not found for member {:?}",
362 current_member.member.invited_by,
363 current_member.member.id()
364 )
365 })?;
366
367 current_member
368 .verify_signature(&inviter.member.member_vk)
369 .map_err(|e| {
370 format!(
371 "Invalid signature for member {:?}: {}",
372 current_member.member.id(),
373 e
374 )
375 })?;
376
377 invite_chain.push((*inviter).clone());
378 current_member = inviter;
379 }
380 }
381
382 Ok(invite_chain)
383 }
384
385 fn invite_chain_length(
388 member: &AuthorizedMember,
389 owner_id: MemberId,
390 members_by_id: &HashMap<MemberId, &AuthorizedMember>,
391 ) -> usize {
392 let mut length = 0;
393 let mut current_id = member.member.invited_by;
394 let mut visited = HashSet::new();
395 visited.insert(member.member.id());
396
397 while current_id != owner_id {
398 if !visited.insert(current_id) {
399 break; }
401 length += 1;
402 match members_by_id.get(¤t_id) {
403 Some(inviter) => current_id = inviter.member.invited_by,
404 None => break, }
406 }
407 length
408 }
409
410 fn invite_chain_ids(
413 member: &AuthorizedMember,
414 owner_id: MemberId,
415 members_by_id: &HashMap<MemberId, &AuthorizedMember>,
416 ) -> Vec<MemberId> {
417 let mut chain_ids = vec![member.member.id()];
418 let mut current_id = member.member.invited_by;
419 let mut visited = HashSet::new();
420 visited.insert(member.member.id());
421
422 while current_id != owner_id {
423 if !visited.insert(current_id) {
424 break;
425 }
426 chain_ids.push(current_id);
427 match members_by_id.get(¤t_id) {
428 Some(inviter) => current_id = inviter.member.invited_by,
429 None => break,
430 }
431 }
432 chain_ids
433 }
434}
435
436#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)]
437pub struct MembersDelta {
438 added: Vec<AuthorizedMember>,
439}
440
441impl MembersDelta {
442 pub fn new(added: Vec<AuthorizedMember>) -> Self {
443 MembersDelta { added }
444 }
445
446 pub fn added(&self) -> &[AuthorizedMember] {
447 &self.added
448 }
449
450 pub fn into_added(self) -> Vec<AuthorizedMember> {
451 self.added
452 }
453}
454
455#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)]
458pub struct AuthorizedMember {
459 pub member: Member,
460 pub signature: Signature,
461}
462
463impl AuthorizedMember {
464 pub fn new(member: Member, inviter_signing_key: &SigningKey) -> Self {
465 assert_eq!(
466 member.invited_by,
467 VerifyingKey::from(inviter_signing_key).into(),
468 "The member's invited_by must match the inviter's signing key"
469 );
470 Self {
471 member: member.clone(),
472 signature: sign_struct(&member, inviter_signing_key),
473 }
474 }
475
476 pub fn with_signature(member: Member, signature: Signature) -> Self {
479 Self { member, signature }
480 }
481
482 pub fn verify_signature(&self, inviter_vk: &VerifyingKey) -> Result<(), String> {
483 verify_struct(&self.member, &self.signature, inviter_vk)
484 .map_err(|e| format!("Invalid signature: {}", e))
485 }
486}
487
488impl Hash for AuthorizedMember {
489 fn hash<H: Hasher>(&self, state: &mut H) {
490 self.member.hash(state);
491 }
492}
493
494#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Clone)]
495pub struct Member {
496 pub owner_member_id: MemberId,
497 pub invited_by: MemberId,
498 pub member_vk: VerifyingKey,
499}
500
501impl fmt::Debug for Member {
502 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
503 f.debug_struct("Member")
504 .field(
505 "public_key",
506 &format_args!("{}", truncated_base32(self.member_vk.as_bytes())),
507 )
508 .finish()
509 }
510}
511
512#[derive(Eq, PartialEq, Hash, Serialize, Deserialize, Clone, Ord, PartialOrd, Copy)]
517pub struct MemberId(pub FastHash);
518
519impl Display for MemberId {
520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
521 write!(f, "{}", truncated_base32(&self.0 .0.to_le_bytes()))
522 }
523}
524
525impl Debug for MemberId {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 write!(
528 f,
529 "MemberId({})",
530 truncated_base32(&self.0 .0.to_le_bytes())
531 )
532 }
533}
534
535impl From<&VerifyingKey> for MemberId {
536 fn from(vk: &VerifyingKey) -> Self {
537 MemberId(fast_hash(&vk.to_bytes()))
538 }
539}
540
541impl From<VerifyingKey> for MemberId {
542 fn from(vk: VerifyingKey) -> Self {
543 MemberId(fast_hash(&vk.to_bytes()))
544 }
545}
546
547impl Member {
548 pub fn id(&self) -> MemberId {
549 self.member_vk.into()
550 }
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556 use crate::room_state::ban::{AuthorizedUserBan, UserBan};
557 use ed25519_dalek::SigningKey;
558 use rand::rngs::OsRng;
559 use std::time::SystemTime;
560
561 fn create_test_member(owner_id: MemberId, invited_by: MemberId) -> (Member, SigningKey) {
562 let signing_key = SigningKey::generate(&mut OsRng);
563 let verifying_key = signing_key.verifying_key();
564 let member = Member {
565 owner_member_id: owner_id,
566 invited_by,
567 member_vk: verifying_key,
568 };
569 (member, signing_key)
570 }
571
572 #[test]
573 fn test_members_verify() {
574 let owner_signing_key = SigningKey::generate(&mut OsRng);
575 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
576 let owner_id = owner_verifying_key.into();
577
578 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
579 let (member2, _) = create_test_member(owner_id, member1.id());
580
581 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
582 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
583
584 let members = MembersV1 {
585 members: vec![authorized_member1.clone(), authorized_member2.clone()],
586 };
587
588 println!("Member1 ID: {:?}", member1.id());
589 println!("Member2 ID: {:?}", member2.id());
590 println!("Owner ID: {:?}", owner_id);
591
592 let mut parent_state = ChatRoomStateV1::default();
593 parent_state.configuration.configuration.max_members = 3;
594 let parameters = ChatRoomParametersV1 {
595 owner: owner_verifying_key,
596 };
597
598 let result = members.verify(&parent_state, ¶meters);
599 println!("Verification result: {:?}", result);
600 assert!(result.is_ok(), "Verification failed: {:?}", result);
601
602 let owner_member = Member {
604 owner_member_id: owner_id,
605 invited_by: owner_id,
606 member_vk: owner_verifying_key,
607 };
608 let authorized_owner = AuthorizedMember::new(owner_member, &owner_signing_key);
609 let members_with_owner = MembersV1 {
610 members: vec![authorized_owner, authorized_member1, authorized_member2],
611 };
612 let result_with_owner = members_with_owner.verify(&parent_state, ¶meters);
613 println!("Verification result with owner: {:?}", result_with_owner);
614 assert!(
615 result_with_owner.is_err(),
616 "Verification should fail when owner is included: {:?}",
617 result_with_owner
618 );
619 }
620
621 #[test]
622 fn test_members_summarize() {
623 let owner_signing_key = SigningKey::generate(&mut OsRng);
624 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
625 let owner_id = owner_verifying_key.into();
626
627 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
628 let (member2, _) = create_test_member(owner_id, member1.id());
629
630 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
631 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
632
633 let members = MembersV1 {
634 members: vec![authorized_member1, authorized_member2],
635 };
636
637 let parent_state = ChatRoomStateV1::default();
638 let parameters = ChatRoomParametersV1 {
639 owner: owner_verifying_key,
640 };
641
642 let summary = members.summarize(&parent_state, ¶meters);
643 assert_eq!(summary.len(), 2);
644 assert!(summary.contains(&member1.id()));
645 assert!(summary.contains(&member2.id()));
646 }
647
648 #[test]
649 fn test_members_delta() {
650 let owner_signing_key = SigningKey::generate(&mut OsRng);
651 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
652 let owner_id = owner_verifying_key.into();
653
654 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
655 let (member2, _) = create_test_member(owner_id, member1.id());
656 let (member3, _) = create_test_member(owner_id, member1.id());
657
658 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
659 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
660 let authorized_member3 = AuthorizedMember::new(member3.clone(), &member1_signing_key);
661
662 let old_members = MembersV1 {
663 members: vec![authorized_member1.clone(), authorized_member2.clone()],
664 };
665
666 let new_members = MembersV1 {
667 members: vec![authorized_member1.clone(), authorized_member3.clone()],
668 };
669
670 let parent_state = ChatRoomStateV1::default();
671 let parameters = ChatRoomParametersV1 {
672 owner: owner_verifying_key,
673 };
674
675 let old_summary = old_members.summarize(&parent_state, ¶meters);
676 let delta = new_members
677 .delta(&parent_state, ¶meters, &old_summary)
678 .unwrap();
679
680 assert_eq!(delta.added.len(), 1);
681 assert_eq!(delta.added[0].member.id(), member3.id());
682 }
683
684 #[test]
685 fn test_members_apply_delta_simple() {
686 let owner_signing_key = SigningKey::generate(&mut OsRng);
687 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
688 let owner_id = owner_verifying_key.into();
689
690 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
691 let (member2, _) = create_test_member(owner_id, member1.id());
692 let (member3, _) = create_test_member(owner_id, member1.id());
693
694 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
695 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
696 let authorized_member3 = AuthorizedMember::new(member3.clone(), &member1_signing_key);
697
698 let original_members = MembersV1 {
699 members: vec![authorized_member1.clone(), authorized_member2.clone()],
700 };
701
702 let delta = MembersDelta {
703 added: vec![authorized_member3.clone()],
704 };
705
706 let mut parent_state = ChatRoomStateV1::default();
707 parent_state.configuration.configuration.max_members = 3;
708
709 let parameters = ChatRoomParametersV1 {
710 owner: owner_verifying_key,
711 };
712
713 let mut modified_members = original_members.clone();
714
715 assert!(modified_members
716 .apply_delta(&parent_state, ¶meters, &Some(delta))
717 .is_ok());
718
719 assert_eq!(modified_members.members.len(), 3);
720 assert!(modified_members
721 .members
722 .iter()
723 .any(|m| m.member.id() == member1.id()));
724 assert!(modified_members
725 .members
726 .iter()
727 .any(|m| m.member.id() == member3.id()));
728 assert!(modified_members
729 .members
730 .iter()
731 .any(|m| m.member.id() == member2.id()));
732 }
733
734 #[test]
735 fn test_authorized_member_validate() {
736 let owner_signing_key = SigningKey::generate(&mut OsRng);
737 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
738 let owner_id = owner_verifying_key.into();
739
740 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
741 let (member2, _) = create_test_member(owner_id, member1.id());
742
743 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
744 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
745
746 assert!(authorized_member1
747 .verify_signature(&owner_verifying_key)
748 .is_ok());
749 assert!(authorized_member2
750 .verify_signature(&member1.member_vk)
751 .is_ok());
752
753 let invalid_member2 = AuthorizedMember {
755 member: member2.clone(),
756 signature: Signature::from_bytes(&[0; 64]),
757 };
758 assert!(invalid_member2
759 .verify_signature(&member1.member_vk)
760 .is_err());
761 }
762
763 #[test]
764 fn test_member_id() {
765 let owner_id = MemberId(FastHash(0));
766 let (member, _) = create_test_member(owner_id, owner_id);
767 let member_id = member.id();
768
769 assert_eq!(member_id, member.member_vk.into());
770 }
771
772 #[test]
773 fn test_verify_self_invited_member() {
774 let owner_signing_key = SigningKey::generate(&mut OsRng);
775 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
776 let owner_id = owner_verifying_key.into();
777
778 let (mut member, member_signing_key) = create_test_member(owner_id, owner_id);
779 member.invited_by = member.id(); let authorized_member = AuthorizedMember::new(member, &member_signing_key);
782
783 let members = MembersV1 {
784 members: vec![authorized_member],
785 };
786
787 let parent_state = ChatRoomStateV1::default();
788 let parameters = ChatRoomParametersV1 {
789 owner: owner_verifying_key,
790 };
791
792 let result = members.verify(&parent_state, ¶meters);
793 assert!(result.is_err());
794 assert!(result.unwrap_err().contains("Self-invitation detected"));
795 }
796
797 #[test]
798 fn test_verify_circular_invite_chain() {
799 let owner_signing_key = SigningKey::generate(&mut OsRng);
800 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
801 let owner_id = owner_verifying_key.into();
802
803 let (mut member1, member1_signing_key) = create_test_member(owner_id, owner_id);
804 let (member2, member2_signing_key) = create_test_member(owner_id, member1.id());
805 let (member3, member3_signing_key) = create_test_member(owner_id, member2.id());
806 member1.invited_by = member3.id(); let authorized_member1 = AuthorizedMember::new(member1, &member3_signing_key);
809 let authorized_member2 = AuthorizedMember::new(member2, &member1_signing_key);
810 let authorized_member3 = AuthorizedMember::new(member3, &member2_signing_key);
811
812 let members = MembersV1 {
813 members: vec![authorized_member1, authorized_member2, authorized_member3],
814 };
815
816 let parent_state = ChatRoomStateV1::default();
817 let parameters = ChatRoomParametersV1 {
818 owner: owner_verifying_key,
819 };
820
821 let result = members.verify(&parent_state, ¶meters);
822 assert!(result.is_err());
823 assert!(result
824 .unwrap_err()
825 .contains("Circular invite chain detected"));
826 }
827
828 #[test]
829 fn test_check_invite_chain() {
830 let owner_signing_key = SigningKey::generate(&mut OsRng);
831 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
832 let owner_id = owner_verifying_key.into();
833
834 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
836 let (member2, member2_signing_key) = create_test_member(owner_id, member1.id());
837 let (member3, _) = create_test_member(owner_id, member2.id());
838
839 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
840 let authorized_member2 = AuthorizedMember::new(member2, &member1_signing_key);
841 let authorized_member3 = AuthorizedMember::new(member3, &member2_signing_key);
842
843 let members = MembersV1 {
844 members: vec![authorized_member1, authorized_member2.clone()],
845 };
846
847 let parameters = ChatRoomParametersV1 {
848 owner: owner_verifying_key,
849 };
850
851 let result = members.get_invite_chain(&authorized_member3, ¶meters);
852 assert!(result.is_ok());
853 assert_eq!(result.unwrap().len(), 2);
854
855 let (mut circular_member1, circular_member1_signing_key) =
857 create_test_member(owner_id, owner_id);
858 let (circular_member2, circular_member2_signing_key) =
859 create_test_member(owner_id, circular_member1.id());
860 circular_member1.invited_by = circular_member2.id();
861
862 let circular_authorized_member1 =
863 AuthorizedMember::new(circular_member1, &circular_member2_signing_key);
864 let circular_authorized_member2 =
865 AuthorizedMember::new(circular_member2, &circular_member1_signing_key);
866
867 let circular_members = MembersV1 {
868 members: vec![
869 circular_authorized_member1.clone(),
870 circular_authorized_member2,
871 ],
872 };
873
874 let result = circular_members.get_invite_chain(&circular_authorized_member1, ¶meters);
875 assert!(result.is_err());
876 assert!(result
877 .clone()
878 .unwrap_err()
879 .contains("Circular invite chain detected"));
880
881 let non_existent_inviter_id = MemberId(FastHash(999));
883 let (orphan_member, _) = create_test_member(owner_id, non_existent_inviter_id);
884 let orphan_authorized_member = AuthorizedMember {
885 member: orphan_member,
886 signature: Signature::from_bytes(&[0; 64]), };
888
889 let result = members.get_invite_chain(&orphan_authorized_member, ¶meters);
890 assert!(result.is_err());
891 let err = result.unwrap_err();
892 assert!(err.contains("Inviter"), "Error message: {}", err);
893 assert!(err.contains("not found"), "Error message: {}", err);
894
895 let (invalid_member, _) = create_test_member(owner_id, member1.id());
897 let invalid_authorized_member = AuthorizedMember {
898 member: invalid_member,
899 signature: Signature::from_bytes(&[0; 64]),
900 };
901
902 let result = members.get_invite_chain(&invalid_authorized_member, ¶meters);
903 assert!(result.is_err());
904 assert!(result.unwrap_err().contains("Invalid signature"));
905 }
906
907 #[test]
908 fn test_has_banned_members() {
909 let owner_signing_key = SigningKey::generate(&mut OsRng);
910 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
911 let owner_id = owner_verifying_key.into();
912
913 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
914 let (member2, member2_signing_key) = create_test_member(owner_id, member1.id());
915 let (member3, _) = create_test_member(owner_id, member2.id());
916
917 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
918 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
919 let authorized_member3 = AuthorizedMember::new(member3.clone(), &member2_signing_key);
920
921 let members = MembersV1 {
922 members: vec![authorized_member1, authorized_member2, authorized_member3],
923 };
924
925 let parameters = ChatRoomParametersV1 {
926 owner: owner_verifying_key,
927 };
928
929 let empty_bans = BansV1(vec![]);
931 assert!(!members.has_banned_members(&empty_bans, ¶meters));
932
933 let banned_member = UserBan {
935 owner_member_id: owner_id,
936 banned_at: SystemTime::now(),
937 banned_user: member2.id(),
938 };
939 let authorized_ban = AuthorizedUserBan::new(banned_member, owner_id, &owner_signing_key);
940 let bans = BansV1(vec![authorized_ban]);
941 assert!(members.has_banned_members(&bans, ¶meters));
942 }
943
944 #[test]
945 fn test_remove_banned_members() {
946 let owner_signing_key = SigningKey::generate(&mut OsRng);
947 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
948 let owner_id = owner_verifying_key.into();
949
950 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
951 let (member2, member2_signing_key) = create_test_member(owner_id, member1.id());
952 let (member3, _) = create_test_member(owner_id, member2.id());
953 let (member4, _) = create_test_member(owner_id, member1.id());
954
955 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
956 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
957 let authorized_member3 = AuthorizedMember::new(member3.clone(), &member2_signing_key);
958 let authorized_member4 = AuthorizedMember::new(member4.clone(), &member1_signing_key);
959
960 let mut members = MembersV1 {
961 members: vec![
962 authorized_member1.clone(),
963 authorized_member2.clone(),
964 authorized_member3.clone(),
965 authorized_member4.clone(),
966 ],
967 };
968
969 let parameters = ChatRoomParametersV1 {
970 owner: owner_verifying_key,
971 };
972
973 let empty_bans = BansV1(vec![]);
975 members.remove_banned_members(&empty_bans, ¶meters);
976 assert_eq!(members.members.len(), 4);
977
978 let banned_member = UserBan {
980 owner_member_id: owner_id,
981 banned_at: SystemTime::now(),
982 banned_user: member2.id(),
983 };
984 let authorized_ban = AuthorizedUserBan::new(banned_member, owner_id, &owner_signing_key);
985 let bans = BansV1(vec![authorized_ban]);
986 members.remove_banned_members(&bans, ¶meters);
987 assert_eq!(members.members.len(), 2);
988 assert!(members
989 .members
990 .iter()
991 .any(|m| m.member.id() == member1.id()));
992 assert!(members
993 .members
994 .iter()
995 .any(|m| m.member.id() == member4.id()));
996 assert!(!members
997 .members
998 .iter()
999 .any(|m| m.member.id() == member2.id()));
1000 assert!(!members
1001 .members
1002 .iter()
1003 .any(|m| m.member.id() == member3.id()));
1004
1005 members = MembersV1 {
1007 members: vec![
1008 authorized_member1,
1009 authorized_member2,
1010 authorized_member3,
1011 authorized_member4,
1012 ],
1013 };
1014 let banned_member = UserBan {
1015 owner_member_id: owner_id,
1016 banned_at: SystemTime::now(),
1017 banned_user: member4.id(),
1018 };
1019 let authorized_ban = AuthorizedUserBan::new(banned_member, owner_id, &owner_signing_key);
1020 let bans = BansV1(vec![authorized_ban]);
1021 members.remove_banned_members(&bans, ¶meters);
1022 assert_eq!(members.members.len(), 3);
1023 assert!(members
1024 .members
1025 .iter()
1026 .any(|m| m.member.id() == member1.id()));
1027 assert!(members
1028 .members
1029 .iter()
1030 .any(|m| m.member.id() == member2.id()));
1031 assert!(members
1032 .members
1033 .iter()
1034 .any(|m| m.member.id() == member3.id()));
1035 assert!(!members
1036 .members
1037 .iter()
1038 .any(|m| m.member.id() == member4.id()));
1039 }
1040
1041 #[test]
1042 fn test_remove_excess_members() {
1043 let owner_signing_key = SigningKey::generate(&mut OsRng);
1044 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1045 let owner_id = owner_verifying_key.into();
1046
1047 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
1048 let (member2, member2_signing_key) = create_test_member(owner_id, member1.id());
1049 let (member3, _) = create_test_member(owner_id, member2.id());
1050
1051 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
1052 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
1053 let authorized_member3 = AuthorizedMember::new(member3.clone(), &member2_signing_key);
1054
1055 let mut members = MembersV1 {
1056 members: vec![authorized_member1, authorized_member2, authorized_member3],
1057 };
1058
1059 let parameters = ChatRoomParametersV1 {
1060 owner: owner_verifying_key,
1061 };
1062
1063 members.remove_excess_members(¶meters, 3);
1065 assert_eq!(members.members.len(), 3);
1066
1067 members.remove_excess_members(¶meters, 2);
1069 assert_eq!(members.members.len(), 2);
1070 assert!(members
1071 .members
1072 .iter()
1073 .any(|m| m.member.id() == member1.id()));
1074 assert!(members
1075 .members
1076 .iter()
1077 .any(|m| m.member.id() == member2.id()));
1078 assert!(!members
1079 .members
1080 .iter()
1081 .any(|m| m.member.id() == member3.id()));
1082 }
1083
1084 #[test]
1085 fn test_members_by_member_id() {
1086 let owner_signing_key = SigningKey::generate(&mut OsRng);
1087 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1088 let owner_id = owner_verifying_key.into();
1089
1090 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
1091 let (member2, _) = create_test_member(owner_id, member1.id());
1092
1093 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
1094 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
1095
1096 let members = MembersV1 {
1097 members: vec![authorized_member1.clone(), authorized_member2.clone()],
1098 };
1099
1100 let members_map = members.members_by_member_id();
1101
1102 assert_eq!(members_map.len(), 2);
1103 assert_eq!(
1104 members_map.get(&member1.id()).unwrap().member.id(),
1105 member1.id()
1106 );
1107 assert_eq!(
1108 members_map.get(&member2.id()).unwrap().member.id(),
1109 member2.id()
1110 );
1111 }
1112
1113 #[test]
1114 fn test_invite_chain_length() {
1115 let owner_signing_key = SigningKey::generate(&mut OsRng);
1116 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1117 let owner_id: MemberId = owner_verifying_key.into();
1118
1119 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
1121 let (member2, member2_signing_key) = create_test_member(owner_id, member1.id());
1122 let (member3, _) = create_test_member(owner_id, member2.id());
1123
1124 let auth_m1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
1125 let auth_m2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
1126 let auth_m3 = AuthorizedMember::new(member3.clone(), &member2_signing_key);
1127
1128 let members = MembersV1 {
1129 members: vec![auth_m1.clone(), auth_m2.clone(), auth_m3.clone()],
1130 };
1131 let members_by_id = members.members_by_member_id();
1132
1133 assert_eq!(
1135 MembersV1::invite_chain_length(&auth_m1, owner_id, &members_by_id),
1136 0
1137 );
1138 assert_eq!(
1140 MembersV1::invite_chain_length(&auth_m2, owner_id, &members_by_id),
1141 1
1142 );
1143 assert_eq!(
1145 MembersV1::invite_chain_length(&auth_m3, owner_id, &members_by_id),
1146 2
1147 );
1148 }
1149
1150 #[test]
1151 fn test_invite_chain_ids() {
1152 let owner_signing_key = SigningKey::generate(&mut OsRng);
1153 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1154 let owner_id: MemberId = owner_verifying_key.into();
1155
1156 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
1158 let (member2, member2_signing_key) = create_test_member(owner_id, member1.id());
1159 let (member3, _) = create_test_member(owner_id, member2.id());
1160
1161 let auth_m1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
1162 let auth_m2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
1163 let auth_m3 = AuthorizedMember::new(member3.clone(), &member2_signing_key);
1164
1165 let members = MembersV1 {
1166 members: vec![auth_m1.clone(), auth_m2.clone(), auth_m3.clone()],
1167 };
1168 let members_by_id = members.members_by_member_id();
1169
1170 let ids = MembersV1::invite_chain_ids(&auth_m1, owner_id, &members_by_id);
1172 assert_eq!(ids, vec![member1.id()]);
1173
1174 let ids = MembersV1::invite_chain_ids(&auth_m2, owner_id, &members_by_id);
1176 assert_eq!(ids, vec![member2.id(), member1.id()]);
1177
1178 let ids = MembersV1::invite_chain_ids(&auth_m3, owner_id, &members_by_id);
1180 assert_eq!(ids, vec![member3.id(), member2.id(), member1.id()]);
1181 }
1182
1183 #[test]
1184 fn test_members_apply_delta_complex() {
1185 let owner_signing_key = SigningKey::generate(&mut OsRng);
1186 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1187 let owner_id = owner_verifying_key.into();
1188
1189 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
1190 let (member2, _) = create_test_member(owner_id, member1.id());
1191 let (member3, _) = create_test_member(owner_id, member1.id());
1192 let (member4, _) = create_test_member(owner_id, member1.id());
1193
1194 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
1195 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
1196 let authorized_member3 = AuthorizedMember::new(member3.clone(), &member1_signing_key);
1197 let authorized_member4 = AuthorizedMember::new(member4.clone(), &member1_signing_key);
1198
1199 let mut members = MembersV1 {
1200 members: vec![authorized_member1.clone(), authorized_member2.clone()],
1201 };
1202
1203 let mut parent_state = ChatRoomStateV1::default();
1204 parent_state.configuration.configuration.max_members = 3;
1205
1206 let parameters = ChatRoomParametersV1 {
1207 owner: owner_verifying_key,
1208 };
1209
1210 let delta = MembersDelta {
1216 added: vec![authorized_member3.clone(), authorized_member4.clone()],
1217 };
1218
1219 let result = members.apply_delta(&parent_state, ¶meters, &Some(delta));
1220 assert!(result.is_ok());
1221 assert_eq!(members.members.len(), 3);
1222 assert!(members
1224 .members
1225 .iter()
1226 .any(|m| m.member.id() == member1.id()));
1227 let kept_count = [member2.id(), member3.id(), member4.id()]
1229 .iter()
1230 .filter(|id| members.members.iter().any(|m| m.member.id() == **id))
1231 .count();
1232 assert_eq!(
1233 kept_count, 2,
1234 "Exactly 2 of the 3 equal-chain-length members should be kept"
1235 );
1236
1237 let delta = MembersDelta {
1239 added: vec![authorized_member2.clone()],
1240 };
1241
1242 let result = members.apply_delta(&parent_state, ¶meters, &Some(delta));
1243 assert!(result.is_ok());
1244 assert_eq!(members.members.len(), 3);
1245 }
1246
1247 #[test]
1248 fn test_remove_excess_members_edge_cases() {
1249 let owner_signing_key = SigningKey::generate(&mut OsRng);
1250 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1251 let owner_id = owner_verifying_key.into();
1252
1253 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
1254 let (member2, _) = create_test_member(owner_id, member1.id());
1255
1256 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
1257 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
1258
1259 let mut members = MembersV1 {
1260 members: vec![authorized_member1.clone(), authorized_member2.clone()],
1261 };
1262
1263 let parameters = ChatRoomParametersV1 {
1264 owner: owner_verifying_key,
1265 };
1266
1267 members.remove_excess_members(¶meters, 0);
1269 assert_eq!(members.members.len(), 0);
1270
1271 members.members = vec![authorized_member1.clone(), authorized_member2.clone()];
1273
1274 members.remove_excess_members(¶meters, 3);
1276 assert_eq!(members.members.len(), 2);
1277 }
1278
1279 #[test]
1280 #[should_panic(expected = "The member's invited_by must match the inviter's signing key")]
1281 fn test_authorized_member_new_mismatch() {
1282 let owner_signing_key = SigningKey::generate(&mut OsRng);
1283 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1284 let owner_id = owner_verifying_key.into();
1285
1286 let (member, _) = create_test_member(owner_id, owner_id);
1287 let wrong_signing_key = SigningKey::generate(&mut OsRng);
1288
1289 AuthorizedMember::new(member, &wrong_signing_key);
1290 }
1291
1292 #[test]
1293 fn test_members_verify_edge_cases() {
1294 let owner_signing_key = SigningKey::generate(&mut OsRng);
1295 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1296 let owner_id = owner_verifying_key.into();
1297
1298 let mut parent_state = ChatRoomStateV1::default();
1299 parent_state.configuration.configuration.max_members = 2;
1300
1301 let parameters = ChatRoomParametersV1 {
1302 owner: owner_verifying_key,
1303 };
1304
1305 let empty_members = MembersV1 { members: vec![] };
1307 assert!(empty_members.verify(&parent_state, ¶meters).is_ok());
1308
1309 let (member1, member1_signing_key) = create_test_member(owner_id, owner_id);
1311 let (member2, _) = create_test_member(owner_id, member1.id());
1312
1313 let authorized_member1 = AuthorizedMember::new(member1.clone(), &owner_signing_key);
1314 let authorized_member2 = AuthorizedMember::new(member2.clone(), &member1_signing_key);
1315
1316 let max_members = MembersV1 {
1317 members: vec![authorized_member1, authorized_member2],
1318 };
1319 assert!(max_members.verify(&parent_state, ¶meters).is_ok());
1320
1321 let non_existent_signing_key = SigningKey::generate(&mut OsRng);
1323 let non_existent_verifying_key = VerifyingKey::from(&non_existent_signing_key);
1324 let non_existent_id = non_existent_verifying_key.into();
1325 let (invalid_member, _) = create_test_member(owner_id, non_existent_id);
1326 let invalid_authorized_member =
1327 AuthorizedMember::new(invalid_member, &non_existent_signing_key);
1328
1329 let invalid_members = MembersV1 {
1330 members: vec![invalid_authorized_member],
1331 };
1332 assert!(invalid_members.verify(&parent_state, ¶meters).is_err());
1333 }
1334
1335 #[test]
1336 fn test_room_owner_key_not_allowed_in_members() {
1337 let owner_signing_key = SigningKey::generate(&mut OsRng);
1338 let owner_verifying_key = VerifyingKey::from(&owner_signing_key);
1339 let owner_id = owner_verifying_key.into();
1340
1341 let owner_member = Member {
1342 owner_member_id: owner_id,
1343 invited_by: owner_id,
1344 member_vk: owner_verifying_key,
1345 };
1346
1347 let authorized_owner_member = AuthorizedMember::new(owner_member, &owner_signing_key);
1348
1349 let members = MembersV1 {
1350 members: vec![authorized_owner_member],
1351 };
1352
1353 let mut parent_state = ChatRoomStateV1::default();
1354 parent_state.configuration.configuration.max_members = 2;
1355
1356 let parameters = ChatRoomParametersV1 {
1357 owner: owner_verifying_key,
1358 };
1359
1360 let result = members.verify(&parent_state, ¶meters);
1361 assert!(
1362 result.is_err(),
1363 "Room owner should not be allowed in the members list"
1364 );
1365 assert!(result
1366 .unwrap_err()
1367 .contains("Owner should not be included in the members list"));
1368 }
1369}