1use crate::error::{IronError, Result};
7use serde::{Serialize, Deserialize};
8use std::collections::{HashMap, HashSet};
9use std::time::SystemTime;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub enum AdminOperation {
14 CreateChannel {
16 channel: String,
17 settings: ChannelSettings,
18 },
19 SetTopic {
21 channel: String,
22 topic: String,
23 },
24 SetMode {
26 channel: String,
27 mode: ChannelMode,
28 enabled: bool,
29 },
30 MemberOperation {
32 channel: String,
33 target: String,
34 operation: MemberOperation,
35 },
36 BanOperation {
38 channel: String,
39 target: String,
40 operation: BanOperation,
41 duration: Option<SystemTime>,
42 },
43 KeyOperation {
45 channel: String,
46 operation: KeyOperation,
47 },
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub enum MemberOperation {
53 Invite,
55 Kick { reason: Option<String> },
57 Op,
59 Deop,
61 Voice,
63 Devoice,
65 SetRole { role: MemberRole },
67 Mute { duration: Option<SystemTime> },
69 Unmute,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub enum BanOperation {
76 Add { reason: Option<String> },
78 Remove,
80 List,
82 Check,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
88pub enum KeyOperation {
89 Rotate,
91 Backup,
93 Restore { backup_id: String },
95 Generate,
97 ExportPublic,
99 ImportPublic { user_id: String, public_key: Vec<u8> },
101}
102
103#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
105pub enum MemberRole {
106 Founder,
108 Owner,
110 Admin,
112 Operator,
114 HalfOp,
116 Voice,
118 Member,
120 Restricted,
122 Muted,
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
128pub enum ChannelMode {
129 Moderated,
131 InviteOnly,
133 NoExternal,
135 TopicProtected,
137 Secret,
139 Private,
141 KeyRotation,
143 History,
145 Anonymous,
147 RateLimit,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct ChannelSettings {
154 pub topic: Option<String>,
156 pub topic_set_by: Option<(String, SystemTime)>,
158 pub modes: HashSet<ChannelMode>,
160 pub member_limit: Option<usize>,
162 pub password: Option<String>,
164 pub invite_list: HashSet<String>,
166 pub exception_list: HashSet<String>,
168 pub quiet_list: HashSet<String>,
170 pub rate_limit: Option<RateLimit>,
172 pub key_rotation_interval: Option<u64>,
174 pub history_retention: Option<u64>,
176 pub created_at: SystemTime,
178 pub last_activity: SystemTime,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct RateLimit {
185 pub messages: u32,
187 pub window: u64,
189 pub burst: u32,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct ChannelBan {
196 pub pattern: String,
198 pub reason: Option<String>,
200 pub set_by: String,
202 pub set_at: SystemTime,
204 pub expires_at: Option<SystemTime>,
206 pub ban_type: BanType,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
212pub enum BanType {
213 Full,
215 Quiet,
217 Invite,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct AdminResult {
224 pub operation: AdminOperation,
226 pub success: bool,
228 pub message: String,
230 pub data: Option<AdminData>,
232 pub timestamp: SystemTime,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
238pub enum AdminData {
239 MemberList(Vec<ChannelMember>),
241 BanList(Vec<ChannelBan>),
243 ChannelInfo(ChannelInfo),
245 KeyInfo(KeyInfo),
247 Permissions(HashSet<Permission>),
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct ChannelMember {
254 pub user_id: String,
256 pub nickname: String,
258 pub role: MemberRole,
260 pub joined_at: SystemTime,
262 pub last_activity: SystemTime,
264 pub public_key: Option<Vec<u8>>,
266 pub custom_permissions: Option<HashSet<Permission>>,
268 pub is_online: bool,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct ChannelInfo {
275 pub name: String,
277 pub settings: ChannelSettings,
279 pub member_count: usize,
281 pub topic: Option<String>,
283 pub modes: HashSet<ChannelMode>,
285 pub stats: ChannelStats,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
291pub struct ChannelStats {
292 pub total_messages: u64,
294 pub messages_today: f64,
296 pub avg_messages_per_day: f64,
298 pub most_active_member: Option<String>,
300 pub key_rotations: u64,
302 pub last_key_rotation: Option<SystemTime>,
304}
305
306impl Default for ChannelStats {
307 fn default() -> Self {
308 Self {
309 total_messages: 0,
310 messages_today: 0.0,
311 avg_messages_per_day: 0.0,
312 most_active_member: None,
313 key_rotations: 0,
314 last_key_rotation: None,
315 }
316 }
317}
318
319#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct KeyInfo {
322 pub key_version: u64,
324 pub created_at: SystemTime,
326 pub rotation_schedule: Option<SystemTime>,
328 pub member_key_count: usize,
330 pub has_backup: bool,
332}
333
334#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
336pub enum Permission {
337 SendMessage,
340 ReadMessage,
342 JoinChannel,
344 LeaveChannel,
346
347 KickMember,
350 BanMember,
352 UnbanMember,
354 MuteMember,
356 UnmuteMember,
358
359 SetTopic,
362 SetMode,
364 InviteMember,
366 GrantVoice,
368 GrantOp,
370
371 ManageChannel,
374 ManageRoles,
376 ViewLogs,
378 ManageBans,
380
381 RotateKeys,
384 BackupKeys,
386 RestoreKeys,
388 ManageKeys,
390
391 TransferOwnership,
394 DestroyChannel,
396 ManageAdmins,
398}
399
400impl Default for ChannelSettings {
401 fn default() -> Self {
402 Self {
403 topic: None,
404 topic_set_by: None,
405 modes: HashSet::new(),
406 member_limit: None,
407 password: None,
408 invite_list: HashSet::new(),
409 exception_list: HashSet::new(),
410 quiet_list: HashSet::new(),
411 rate_limit: None,
412 key_rotation_interval: Some(86400), history_retention: Some(2592000), created_at: SystemTime::now(),
415 last_activity: SystemTime::now(),
416 }
417 }
418}
419
420impl MemberRole {
421 pub fn has_permission(&self, permission: &Permission) -> bool {
423 match self {
424 MemberRole::Founder => true, MemberRole::Owner => !matches!(permission, Permission::TransferOwnership),
426 MemberRole::Admin => matches!(permission,
427 Permission::SendMessage | Permission::ReadMessage | Permission::JoinChannel | Permission::LeaveChannel |
428 Permission::KickMember | Permission::BanMember | Permission::UnbanMember | Permission::MuteMember | Permission::UnmuteMember |
429 Permission::SetTopic | Permission::SetMode | Permission::InviteMember | Permission::GrantVoice | Permission::GrantOp |
430 Permission::ManageChannel | Permission::ManageRoles | Permission::ViewLogs | Permission::ManageBans |
431 Permission::RotateKeys | Permission::BackupKeys | Permission::RestoreKeys | Permission::ManageKeys
432 ),
433 MemberRole::Operator => matches!(permission,
434 Permission::SendMessage | Permission::ReadMessage | Permission::JoinChannel | Permission::LeaveChannel |
435 Permission::KickMember | Permission::BanMember | Permission::UnbanMember | Permission::MuteMember | Permission::UnmuteMember |
436 Permission::SetTopic | Permission::InviteMember | Permission::GrantVoice |
437 Permission::ViewLogs | Permission::ManageBans
438 ),
439 MemberRole::HalfOp => matches!(permission,
440 Permission::SendMessage | Permission::ReadMessage | Permission::JoinChannel | Permission::LeaveChannel |
441 Permission::MuteMember | Permission::UnmuteMember | Permission::InviteMember |
442 Permission::ViewLogs
443 ),
444 MemberRole::Voice => matches!(permission,
445 Permission::SendMessage | Permission::ReadMessage | Permission::JoinChannel | Permission::LeaveChannel
446 ),
447 MemberRole::Member => matches!(permission,
448 Permission::SendMessage | Permission::ReadMessage | Permission::JoinChannel | Permission::LeaveChannel
449 ),
450 MemberRole::Restricted => matches!(permission,
451 Permission::ReadMessage | Permission::JoinChannel | Permission::LeaveChannel
452 ),
453 MemberRole::Muted => matches!(permission,
454 Permission::ReadMessage | Permission::JoinChannel | Permission::LeaveChannel
455 ),
456 }
457 }
458
459 pub fn permissions(&self) -> HashSet<Permission> {
461 use Permission::*;
462 let all_permissions = vec![
463 SendMessage, ReadMessage, JoinChannel, LeaveChannel,
464 KickMember, BanMember, UnbanMember, MuteMember, UnmuteMember,
465 SetTopic, SetMode, InviteMember, GrantVoice, GrantOp,
466 ManageChannel, ManageRoles, ViewLogs, ManageBans,
467 RotateKeys, BackupKeys, RestoreKeys, ManageKeys,
468 TransferOwnership, DestroyChannel, ManageAdmins,
469 ];
470
471 all_permissions.into_iter()
472 .filter(|p| self.has_permission(p))
473 .collect()
474 }
475
476 pub fn can_manage_role(&self, target_role: &MemberRole) -> bool {
478 use MemberRole::*;
479 match (self, target_role) {
480 (Founder, _) => true,
481 (Owner, Founder) => false,
482 (Owner, _) => true,
483 (Admin, Founder | Owner) => false,
484 (Admin, _) => true,
485 (Operator, Founder | Owner | Admin) => false,
486 (Operator, _) => true,
487 _ => false,
488 }
489 }
490
491 pub fn hierarchy_level(&self) -> u8 {
493 match self {
494 MemberRole::Founder => 100,
495 MemberRole::Owner => 90,
496 MemberRole::Admin => 80,
497 MemberRole::Operator => 70,
498 MemberRole::HalfOp => 60,
499 MemberRole::Voice => 50,
500 MemberRole::Member => 40,
501 MemberRole::Restricted => 30,
502 MemberRole::Muted => 20,
503 }
504 }
505}
506
507impl ChannelBan {
508 pub fn is_active(&self) -> bool {
510 match self.expires_at {
511 Some(expires) => SystemTime::now() < expires,
512 None => true, }
514 }
515
516 pub fn matches_pattern(&self, pattern: &str) -> bool {
518 if self.pattern.contains('*') || self.pattern.contains('?') {
520 self.wildcard_match(&self.pattern, pattern)
521 } else {
522 self.pattern == pattern
523 }
524 }
525
526 fn wildcard_match(&self, pattern: &str, text: &str) -> bool {
527 let pattern_chars: Vec<char> = pattern.chars().collect();
531 let text_chars: Vec<char> = text.chars().collect();
532
533 self.match_recursive(&pattern_chars, &text_chars, 0, 0)
534 }
535
536 fn match_recursive(&self, pattern: &[char], text: &[char], p_idx: usize, t_idx: usize) -> bool {
537 if p_idx >= pattern.len() {
538 return t_idx >= text.len();
539 }
540
541 match pattern[p_idx] {
542 '*' => {
543 for i in t_idx..=text.len() {
545 if self.match_recursive(pattern, text, p_idx + 1, i) {
546 return true;
547 }
548 }
549 false
550 },
551 '?' => {
552 if t_idx < text.len() {
554 self.match_recursive(pattern, text, p_idx + 1, t_idx + 1)
555 } else {
556 false
557 }
558 },
559 c => {
560 if t_idx < text.len() && text[t_idx] == c {
562 self.match_recursive(pattern, text, p_idx + 1, t_idx + 1)
563 } else {
564 false
565 }
566 }
567 }
568 }
569}
570
571pub struct ChannelAdmin {
573 user_id: String,
575 user_role: MemberRole,
577 user_permissions: HashSet<Permission>,
579}
580
581impl ChannelAdmin {
582 pub fn new(user_id: String, user_role: MemberRole, user_permissions: HashSet<Permission>) -> Self {
584 Self {
585 user_id,
586 user_role,
587 user_permissions,
588 }
589 }
590
591 pub fn can_perform(&self, operation: &AdminOperation, target_channel: &ChannelSettings) -> bool {
593 match operation {
594 AdminOperation::CreateChannel { .. } => {
595 true
597 },
598 AdminOperation::SetTopic { .. } => {
599 self.has_permission(&Permission::SetTopic) &&
600 (!target_channel.modes.contains(&ChannelMode::TopicProtected) ||
601 self.user_role.hierarchy_level() >= MemberRole::Operator.hierarchy_level())
602 },
603 AdminOperation::SetMode { .. } => {
604 self.has_permission(&Permission::SetMode)
605 },
606 AdminOperation::MemberOperation { operation, .. } => {
607 match operation {
608 MemberOperation::Invite => self.has_permission(&Permission::InviteMember),
609 MemberOperation::Kick { .. } => self.has_permission(&Permission::KickMember),
610 MemberOperation::Op | MemberOperation::Deop => self.has_permission(&Permission::GrantOp),
611 MemberOperation::Voice | MemberOperation::Devoice => self.has_permission(&Permission::GrantVoice),
612 MemberOperation::SetRole { .. } => self.has_permission(&Permission::ManageRoles),
613 MemberOperation::Mute { .. } | MemberOperation::Unmute => self.has_permission(&Permission::MuteMember),
614 }
615 },
616 AdminOperation::BanOperation { operation, .. } => {
617 match operation {
618 BanOperation::Add { .. } => self.has_permission(&Permission::BanMember),
619 BanOperation::Remove => self.has_permission(&Permission::UnbanMember),
620 BanOperation::List | BanOperation::Check => self.has_permission(&Permission::ViewLogs),
621 }
622 },
623 AdminOperation::KeyOperation { operation, .. } => {
624 match operation {
625 KeyOperation::Rotate => self.has_permission(&Permission::RotateKeys),
626 KeyOperation::Backup => self.has_permission(&Permission::BackupKeys),
627 KeyOperation::Restore { .. } => self.has_permission(&Permission::RestoreKeys),
628 KeyOperation::Generate => self.has_permission(&Permission::ManageKeys),
629 KeyOperation::ExportPublic => true, KeyOperation::ImportPublic { .. } => self.has_permission(&Permission::ManageKeys),
631 }
632 },
633 }
634 }
635
636 pub fn has_permission(&self, permission: &Permission) -> bool {
638 self.user_role.has_permission(permission) || self.user_permissions.contains(permission)
639 }
640
641 pub fn get_permissions(&self) -> HashSet<Permission> {
643 let mut permissions = self.user_role.permissions();
644 permissions.extend(self.user_permissions.clone());
645 permissions
646 }
647
648 pub fn can_manage_user_role(&self, target_role: &MemberRole) -> bool {
650 self.user_role.can_manage_role(target_role)
651 }
652}
653
654#[cfg(test)]
655mod tests {
656 use super::*;
657
658 #[test]
659 fn test_role_permissions() {
660 let owner = MemberRole::Owner;
661 let member = MemberRole::Member;
662
663 assert!(owner.has_permission(&Permission::KickMember));
664 assert!(!member.has_permission(&Permission::KickMember));
665 assert!(member.has_permission(&Permission::SendMessage));
666 }
667
668 #[test]
669 fn test_role_hierarchy() {
670 let founder = MemberRole::Founder;
671 let admin = MemberRole::Admin;
672 let member = MemberRole::Member;
673
674 assert!(founder.can_manage_role(&admin));
675 assert!(admin.can_manage_role(&member));
676 assert!(!member.can_manage_role(&admin));
677 }
678
679 #[test]
680 fn test_ban_wildcard_matching() {
681 let ban = ChannelBan {
682 pattern: "*@evil.com".to_string(),
683 reason: Some("Spam domain".to_string()),
684 set_by: "admin".to_string(),
685 set_at: SystemTime::now(),
686 expires_at: None,
687 ban_type: BanType::Full,
688 };
689
690 assert!(ban.matches_pattern("user@evil.com"));
691 assert!(ban.matches_pattern("spammer@evil.com"));
692 assert!(!ban.matches_pattern("user@good.com"));
693 }
694
695 #[test]
696 fn test_admin_permissions() {
697 let admin = ChannelAdmin::new(
698 "admin_user".to_string(),
699 MemberRole::Admin,
700 HashSet::new(),
701 );
702
703 let settings = ChannelSettings::default();
704 let kick_op = AdminOperation::MemberOperation {
705 channel: "!test".to_string(),
706 target: "user".to_string(),
707 operation: MemberOperation::Kick { reason: None },
708 };
709
710 assert!(admin.can_perform(&kick_op, &settings));
711 }
712}