use uuid::Uuid; use crate::actor::{ActorContext, ChannelRole, RepoAccess, SpaceRole, TokenScope}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PermissionError { Anonymous, Insufficient, Forbidden, } pub fn required_scope_for(access: RepoAccess) -> TokenScope { match access { RepoAccess::None | RepoAccess::Read => TokenScope::RepoRead, RepoAccess::Write => TokenScope::RepoWrite, RepoAccess::Admin => TokenScope::RepoAdmin, } } pub fn effective_access( actor: &ActorContext, channel_role: Option, space_role: Option, collaborator_mode: Option, is_public: bool, ) -> RepoAccess { if actor.is_site_admin { return RepoAccess::Admin; } if actor.has_scope(TokenScope::RepoAdmin) { return RepoAccess::Admin; } if actor.has_scope(TokenScope::RepoWrite) { return RepoAccess::Write; } if actor.has_scope(TokenScope::RepoRead) { if matches!( collaborator_mode, Some(RepoAccess::Write) | Some(RepoAccess::Admin) ) { return RepoAccess::Write; } return RepoAccess::Read; } if matches!(space_role, Some(SpaceRole::Owner | SpaceRole::Admin)) { return RepoAccess::Admin; } if matches!( channel_role, Some(ChannelRole::Owner | ChannelRole::Moderator) ) { return RepoAccess::Write; } if let Some(mode) = collaborator_mode { return mode; } if is_public { return RepoAccess::Read; } RepoAccess::None } pub fn require( actor: &ActorContext, required: RepoAccess, channel_role: Option, space_role: Option, collaborator_mode: Option, is_public: bool, ) -> Result<(), PermissionError> { let has = effective_access( actor, channel_role, space_role, collaborator_mode, is_public, ); if has.at_least(required) { Ok(()) } else if !actor.is_authenticated() && required == RepoAccess::Read && is_public { Ok(()) } else if !actor.is_authenticated() { Err(PermissionError::Anonymous) } else { Err(PermissionError::Insufficient) } } pub fn require_write(actor: &ActorContext, is_admin_endpoint: bool) -> Result<(), PermissionError> { if !actor.is_authenticated() { return Err(PermissionError::Anonymous); } if actor.is_site_admin { return Ok(()); } if is_admin_endpoint { if actor.has_scope(TokenScope::RepoAdmin) { return Ok(()); } } else if actor.has_scope(TokenScope::RepoWrite) { return Ok(()); } Err(PermissionError::Insufficient) }