Skip to main content

legion_protocol/
admin.rs

1//! Legion Protocol channel administration
2//! 
3//! Provides channel management, role-based permissions, and administrative operations
4//! for Legion encrypted channels.
5
6use crate::error::{IronError, Result};
7use serde::{Serialize, Deserialize};
8use std::collections::{HashMap, HashSet};
9use std::time::SystemTime;
10
11/// Channel administration operations
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub enum AdminOperation {
14    /// Create a new encrypted channel
15    CreateChannel {
16        channel: String,
17        settings: ChannelSettings,
18    },
19    /// Set channel topic
20    SetTopic {
21        channel: String,
22        topic: String,
23    },
24    /// Change channel mode
25    SetMode {
26        channel: String,
27        mode: ChannelMode,
28        enabled: bool,
29    },
30    /// Manage channel member
31    MemberOperation {
32        channel: String,
33        target: String,
34        operation: MemberOperation,
35    },
36    /// Manage channel bans
37    BanOperation {
38        channel: String,
39        target: String,
40        operation: BanOperation,
41        duration: Option<SystemTime>,
42    },
43    /// Key management operations
44    KeyOperation {
45        channel: String,
46        operation: KeyOperation,
47    },
48}
49
50/// Member management operations
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub enum MemberOperation {
53    /// Invite user to channel
54    Invite,
55    /// Remove user from channel (kick)
56    Kick { reason: Option<String> },
57    /// Grant operator status
58    Op,
59    /// Remove operator status
60    Deop,
61    /// Grant voice status
62    Voice,
63    /// Remove voice status
64    Devoice,
65    /// Change member role
66    SetRole { role: MemberRole },
67    /// Mute member (temporary silence)
68    Mute { duration: Option<SystemTime> },
69    /// Unmute member
70    Unmute,
71}
72
73/// Ban management operations
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub enum BanOperation {
76    /// Add ban
77    Add { reason: Option<String> },
78    /// Remove ban
79    Remove,
80    /// List bans
81    List,
82    /// Check if user is banned
83    Check,
84}
85
86/// Key management operations
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub enum KeyOperation {
89    /// Rotate channel encryption keys
90    Rotate,
91    /// Backup current keys
92    Backup,
93    /// Restore keys from backup
94    Restore { backup_id: String },
95    /// Generate new key pair
96    Generate,
97    /// Export public key
98    ExportPublic,
99    /// Import member public key
100    ImportPublic { user_id: String, public_key: Vec<u8> },
101}
102
103/// Channel member roles with hierarchical permissions
104#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
105pub enum MemberRole {
106    /// Channel founder (highest level)
107    Founder,
108    /// Channel owner (can manage all aspects)
109    Owner,
110    /// Channel administrator (can manage members)
111    Admin,
112    /// Channel operator (can moderate)
113    Operator,
114    /// Half-operator (limited moderation)
115    HalfOp,
116    /// Voiced member (can speak when moderated)
117    Voice,
118    /// Regular member
119    Member,
120    /// Restricted member (limited permissions)
121    Restricted,
122    /// Muted member (cannot speak)
123    Muted,
124}
125
126/// Channel operational modes
127#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
128pub enum ChannelMode {
129    /// Moderated channel (only voiced+ can speak)
130    Moderated,
131    /// Invite-only channel
132    InviteOnly,
133    /// No external messages
134    NoExternal,
135    /// Topic protection (only ops can change)
136    TopicProtected,
137    /// Secret channel (hidden from lists)
138    Secret,
139    /// Private channel (invite required)
140    Private,
141    /// Key rotation enabled
142    KeyRotation,
143    /// Message history enabled
144    History,
145    /// Anonymous mode (hide real identities)
146    Anonymous,
147    /// Rate limiting enabled
148    RateLimit,
149}
150
151/// Comprehensive channel settings
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct ChannelSettings {
154    /// Channel topic
155    pub topic: Option<String>,
156    /// Topic set by (user and timestamp)
157    pub topic_set_by: Option<(String, SystemTime)>,
158    /// Active channel modes
159    pub modes: HashSet<ChannelMode>,
160    /// Maximum number of members
161    pub member_limit: Option<usize>,
162    /// Channel password/key
163    pub password: Option<String>,
164    /// Invite-only list
165    pub invite_list: HashSet<String>,
166    /// Exception list (users who can bypass bans)
167    pub exception_list: HashSet<String>,
168    /// Quiet list (users who cannot speak)
169    pub quiet_list: HashSet<String>,
170    /// Rate limiting settings
171    pub rate_limit: Option<RateLimit>,
172    /// Key rotation interval in seconds
173    pub key_rotation_interval: Option<u64>,
174    /// Message history retention
175    pub history_retention: Option<u64>,
176    /// Channel creation time
177    pub created_at: SystemTime,
178    /// Last activity time
179    pub last_activity: SystemTime,
180}
181
182/// Rate limiting configuration
183#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct RateLimit {
185    /// Messages per time window
186    pub messages: u32,
187    /// Time window in seconds
188    pub window: u64,
189    /// Burst allowance
190    pub burst: u32,
191}
192
193/// Channel ban entry
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct ChannelBan {
196    /// Banned pattern (nick!user@host or Legion ID)
197    pub pattern: String,
198    /// Ban reason
199    pub reason: Option<String>,
200    /// Who set the ban
201    pub set_by: String,
202    /// When the ban was set
203    pub set_at: SystemTime,
204    /// When the ban expires (if temporary)
205    pub expires_at: Option<SystemTime>,
206    /// Ban type
207    pub ban_type: BanType,
208}
209
210/// Types of bans
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub enum BanType {
213    /// Full ban (cannot join)
214    Full,
215    /// Quiet ban (can join but cannot speak)
216    Quiet,
217    /// Invite ban (cannot be invited)
218    Invite,
219}
220
221/// Channel administration result
222#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct AdminResult {
224    /// Operation that was performed
225    pub operation: AdminOperation,
226    /// Whether the operation succeeded
227    pub success: bool,
228    /// Result message or error description
229    pub message: String,
230    /// Additional data (e.g., ban lists, member info)
231    pub data: Option<AdminData>,
232    /// Timestamp of the operation
233    pub timestamp: SystemTime,
234}
235
236/// Additional data returned by admin operations
237#[derive(Debug, Clone, Serialize, Deserialize)]
238pub enum AdminData {
239    /// List of channel members
240    MemberList(Vec<ChannelMember>),
241    /// List of channel bans
242    BanList(Vec<ChannelBan>),
243    /// Channel information
244    ChannelInfo(ChannelInfo),
245    /// Key information
246    KeyInfo(KeyInfo),
247    /// Permission information
248    Permissions(HashSet<Permission>),
249}
250
251/// Channel member information
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct ChannelMember {
254    /// Member user ID
255    pub user_id: String,
256    /// Member nickname
257    pub nickname: String,
258    /// Member role in channel
259    pub role: MemberRole,
260    /// When the member joined
261    pub joined_at: SystemTime,
262    /// Last activity time
263    pub last_activity: SystemTime,
264    /// Member's Legion public key
265    pub public_key: Option<Vec<u8>>,
266    /// Custom permissions (overrides role defaults)
267    pub custom_permissions: Option<HashSet<Permission>>,
268    /// Whether member is currently online
269    pub is_online: bool,
270}
271
272/// Channel information summary
273#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct ChannelInfo {
275    /// Channel name
276    pub name: String,
277    /// Channel settings
278    pub settings: ChannelSettings,
279    /// Number of members
280    pub member_count: usize,
281    /// Current topic
282    pub topic: Option<String>,
283    /// Channel modes
284    pub modes: HashSet<ChannelMode>,
285    /// Channel statistics
286    pub stats: ChannelStats,
287}
288
289/// Channel statistics
290#[derive(Debug, Clone, Serialize, Deserialize)]
291pub struct ChannelStats {
292    /// Total messages sent
293    pub total_messages: u64,
294    /// Messages today
295    pub messages_today: f64,
296    /// Average messages per day
297    pub avg_messages_per_day: f64,
298    /// Most active member
299    pub most_active_member: Option<String>,
300    /// Key rotations performed
301    pub key_rotations: u64,
302    /// Last key rotation
303    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/// Encryption key information
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct KeyInfo {
322    /// Current key version/sequence
323    pub key_version: u64,
324    /// Key creation time
325    pub created_at: SystemTime,
326    /// Key rotation schedule
327    pub rotation_schedule: Option<SystemTime>,
328    /// Number of members with current key
329    pub member_key_count: usize,
330    /// Backup availability
331    pub has_backup: bool,
332}
333
334/// Granular permissions for channel operations
335#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
336pub enum Permission {
337    // Basic permissions
338    /// Can send messages to channel
339    SendMessage,
340    /// Can read channel messages
341    ReadMessage,
342    /// Can join the channel
343    JoinChannel,
344    /// Can leave the channel
345    LeaveChannel,
346    
347    // Moderation permissions
348    /// Can kick members
349    KickMember,
350    /// Can ban members
351    BanMember,
352    /// Can unban members
353    UnbanMember,
354    /// Can mute members
355    MuteMember,
356    /// Can unmute members
357    UnmuteMember,
358    
359    // Channel management
360    /// Can change channel topic
361    SetTopic,
362    /// Can change channel modes
363    SetMode,
364    /// Can invite members
365    InviteMember,
366    /// Can grant voice status
367    GrantVoice,
368    /// Can grant operator status
369    GrantOp,
370    
371    // Administrative permissions
372    /// Can manage channel settings
373    ManageChannel,
374    /// Can manage member roles
375    ManageRoles,
376    /// Can view channel logs
377    ViewLogs,
378    /// Can manage channel bans
379    ManageBans,
380    
381    // Encryption permissions
382    /// Can rotate channel keys
383    RotateKeys,
384    /// Can backup keys
385    BackupKeys,
386    /// Can restore keys
387    RestoreKeys,
388    /// Can manage member keys
389    ManageKeys,
390    
391    // Owner permissions
392    /// Can transfer ownership
393    TransferOwnership,
394    /// Can destroy channel
395    DestroyChannel,
396    /// Can manage administrators
397    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), // 24 hours
413            history_retention: Some(2592000), // 30 days
414            created_at: SystemTime::now(),
415            last_activity: SystemTime::now(),
416        }
417    }
418}
419
420impl MemberRole {
421    /// Check if this role has a specific permission
422    pub fn has_permission(&self, permission: &Permission) -> bool {
423        match self {
424            MemberRole::Founder => true, // Founder has all permissions
425            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    /// Get all permissions for this role
460    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    /// Check if this role can perform an operation on another role
477    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    /// Get role hierarchy level (higher number = more permissions)
492    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    /// Check if this ban is currently active
509    pub fn is_active(&self) -> bool {
510        match self.expires_at {
511            Some(expires) => SystemTime::now() < expires,
512            None => true, // Permanent ban
513        }
514    }
515    
516    /// Check if this ban matches a user pattern
517    pub fn matches_pattern(&self, pattern: &str) -> bool {
518        // Simple wildcard matching - in production this would be more sophisticated
519        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        // Basic wildcard matching implementation
528        // * matches any sequence of characters
529        // ? matches any single character
530        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                // Try matching zero or more characters
544                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                // Match any single character
553                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                // Exact character match
561                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
571/// Channel administration manager
572pub struct ChannelAdmin {
573    /// User performing the admin operation
574    user_id: String,
575    /// User's role in the channel
576    user_role: MemberRole,
577    /// Additional permissions granted to user
578    user_permissions: HashSet<Permission>,
579}
580
581impl ChannelAdmin {
582    /// Create a new channel admin context
583    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    /// Check if the user can perform a specific operation
592    pub fn can_perform(&self, operation: &AdminOperation, target_channel: &ChannelSettings) -> bool {
593        match operation {
594            AdminOperation::CreateChannel { .. } => {
595                // Anyone can create channels, but may be subject to server limits
596                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, // Anyone can export public keys
630                    KeyOperation::ImportPublic { .. } => self.has_permission(&Permission::ManageKeys),
631                }
632            },
633        }
634    }
635    
636    /// Check if user has a specific permission (from role or custom grants)
637    pub fn has_permission(&self, permission: &Permission) -> bool {
638        self.user_role.has_permission(permission) || self.user_permissions.contains(permission)
639    }
640    
641    /// Get all permissions for this user
642    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    /// Check if user can manage another user's role
649    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}