Skip to main content

shared/models/user/
auth.rs

1use crate::response::ApiResponse;
2use axum::http::StatusCode;
3use std::{
4    ops::{Deref, DerefMut},
5    sync::Arc,
6};
7
8#[derive(Clone)]
9pub enum AuthMethod {
10    Session(crate::models::user_session::UserSession),
11    ApiKey(crate::models::user_api_key::UserApiKey),
12}
13
14#[derive(Clone)]
15pub struct UserImpersonator(pub super::User);
16
17impl Deref for UserImpersonator {
18    type Target = super::User;
19
20    fn deref(&self) -> &Self::Target {
21        &self.0
22    }
23}
24
25impl DerefMut for UserImpersonator {
26    fn deref_mut(&mut self) -> &mut Self::Target {
27        &mut self.0
28    }
29}
30
31pub type GetUser = crate::extract::ConsumingExtension<super::User>;
32pub type GetUserImpersonator = crate::extract::ConsumingExtension<Option<UserImpersonator>>;
33pub type GetAuthMethod = crate::extract::ConsumingExtension<AuthMethod>;
34pub type GetPermissionManager = axum::extract::Extension<PermissionManager>;
35
36#[derive(Clone)]
37pub struct PermissionManager {
38    user_admin: bool,
39    user_server_owner: bool,
40    role_admin_permissions: Option<Arc<Vec<compact_str::CompactString>>>,
41    role_server_permissions: Option<Arc<Vec<compact_str::CompactString>>>,
42    api_key_user_permissions: Option<Arc<Vec<compact_str::CompactString>>>,
43    api_key_admin_permissions: Option<Arc<Vec<compact_str::CompactString>>>,
44    api_key_server_permissions: Option<Arc<Vec<compact_str::CompactString>>>,
45    server_subuser_permissions: Option<Arc<Vec<compact_str::CompactString>>>,
46}
47
48impl PermissionManager {
49    pub fn new(user: &super::User) -> Self {
50        Self {
51            user_admin: user.admin,
52            user_server_owner: false,
53            role_admin_permissions: user.role.as_ref().map(|r| r.admin_permissions.clone()),
54            role_server_permissions: user.role.as_ref().map(|r| r.server_permissions.clone()),
55            api_key_user_permissions: None,
56            api_key_admin_permissions: None,
57            api_key_server_permissions: None,
58            server_subuser_permissions: None,
59        }
60    }
61
62    pub fn add_api_key(mut self, api_key: &crate::models::user_api_key::UserApiKey) -> Self {
63        self.api_key_user_permissions = Some(api_key.user_permissions.clone());
64        self.api_key_admin_permissions = Some(api_key.admin_permissions.clone());
65        self.api_key_server_permissions = Some(api_key.server_permissions.clone());
66        self
67    }
68
69    pub fn set_user_server_owner(mut self, is_owner: bool) -> Self {
70        self.user_server_owner = is_owner;
71        self
72    }
73
74    pub fn add_subuser_permissions(
75        mut self,
76        permissions: Option<Arc<Vec<compact_str::CompactString>>>,
77    ) -> Self {
78        self.server_subuser_permissions = permissions;
79        self
80    }
81
82    pub fn has_user_permission(&self, permission: &str) -> Result<(), ApiResponse> {
83        if let Some(api_key_permissions) = &self.api_key_user_permissions
84            && !api_key_permissions.iter().any(|p| p == permission)
85        {
86            return Err(ApiResponse::error(format!(
87                "you do not have permission to perform this action: {permission}"
88            ))
89            .with_status(StatusCode::FORBIDDEN));
90        }
91
92        Ok(())
93    }
94
95    pub fn has_admin_permission(&self, permission: &str) -> Result<(), ApiResponse> {
96        let is_admin = self.user_admin;
97        let has_role_perm = self
98            .role_admin_permissions
99            .as_ref()
100            .is_some_and(|perms| perms.iter().any(|p| p == permission));
101
102        let has_base_permission = is_admin || has_role_perm;
103
104        if !has_base_permission {
105            return Err(ApiResponse::error(format!(
106                "you do not have permission to perform this action: {permission}"
107            ))
108            .with_status(StatusCode::FORBIDDEN));
109        }
110
111        if let Some(api_key_permissions) = &self.api_key_admin_permissions
112            && !api_key_permissions.iter().any(|p| p == permission)
113        {
114            return Err(ApiResponse::error(format!(
115                "you do not have permission to perform this action: {permission}"
116            ))
117            .with_status(StatusCode::FORBIDDEN));
118        }
119
120        Ok(())
121    }
122
123    pub fn has_server_permission(&self, permission: &str) -> Result<(), ApiResponse> {
124        let is_admin = self.user_admin;
125
126        let has_role_perm = self
127            .role_server_permissions
128            .as_ref()
129            .is_some_and(|perms| perms.iter().any(|p| p == permission));
130
131        let is_owner = self.user_server_owner;
132
133        let has_subuser_perm = self
134            .server_subuser_permissions
135            .as_ref()
136            .is_some_and(|perms| perms.iter().any(|p| p == permission));
137
138        let has_base_permission = is_admin || has_role_perm || is_owner || has_subuser_perm;
139
140        if !has_base_permission {
141            return Err(ApiResponse::error(format!(
142                "you do not have permission to perform this action: {permission}"
143            ))
144            .with_status(StatusCode::FORBIDDEN));
145        }
146
147        if let Some(api_key_permissions) = &self.api_key_server_permissions
148            && !api_key_permissions.iter().any(|p| p == permission)
149        {
150            return Err(ApiResponse::error(format!(
151                "you do not have permission to perform this action: {permission}"
152            ))
153            .with_status(StatusCode::FORBIDDEN));
154        }
155
156        Ok(())
157    }
158}