backend/config/auth/
user_info.rs1use actix_http::{HttpMessage, StatusCode};
4use actix_utils::future::{ready, Ready};
5use actix_web::FromRequest;
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use crate::{config::app::Mode, error::ServiceError};
10
11use super::claims::Claims;
12
13#[derive(Debug, Clone, Deserialize)]
15pub struct UserInfo {
16 pub id: Uuid,
18 pub scopes: Vec<String>,
20 pub roles: Vec<Role>,
22 pub mode: Mode,
24}
25
26#[derive(Debug, Clone, Deserialize, Serialize)]
28pub enum Role {
29 Member,
31 Testing,
33 Admin,
35}
36
37impl UserInfo {
38 #[must_use]
40 pub fn is_member(&self) -> bool {
41 self.roles.iter().any(|role| matches!(role, Role::Member))
42 }
43
44 #[must_use]
46 pub fn is_admin(&self) -> bool {
47 match self.mode {
48 Mode::Production => self.roles.iter().any(|role| matches!(role, Role::Admin)),
49 Mode::Testing => self.roles.iter().any(|role| matches!(role, Role::Admin)),
50 }
51 }
52 #[must_use]
53 pub fn is_testing(&self) -> bool {
54 match self.mode {
55 Mode::Production => false,
56 Mode::Testing => self.roles.iter().any(|role| matches!(role, Role::Testing)),
57 }
58 }
59}
60
61impl Role {
62 #[must_use]
64 pub fn from_string(str: &str) -> Option<Self> {
65 match str {
66 "/Member" => Some(Self::Member),
67 "/Testing" => Some(Self::Testing),
68 "/Admin" => Some(Self::Admin),
69 _ => None,
70 }
71 }
72}
73
74impl From<(Claims, Mode)> for UserInfo {
77 fn from((value, mode): (Claims, Mode)) -> Self {
78 let roles = value.groups.map_or_else(Vec::new, |groups| {
79 groups
80 .into_iter()
81 .filter_map(|s| Role::from_string(&s))
82 .collect::<Vec<_>>()
83 });
84
85 Self {
86 id: value.sub,
87 scopes: value.scope.split(' ').map(str::to_owned).collect(),
88 roles,
89 mode,
90 }
91 }
92}
93
94impl FromRequest for UserInfo {
95 type Future = Ready<Result<Self, Self::Error>>;
96 type Error = ServiceError;
97
98 fn from_request(
99 req: &actix_web::HttpRequest,
100 _payload: &mut actix_http::Payload,
101 ) -> Self::Future {
102 let extensions = req.extensions();
103 ready({
104 extensions.get::<Self>().map_or_else(
105 || {
106 Err(ServiceError::new(
107 StatusCode::INTERNAL_SERVER_ERROR,
108 &StatusCode::INTERNAL_SERVER_ERROR.to_string(),
109 ))
110 },
111 |user_info| Ok(user_info.clone()),
112 )
113 })
114 }
115}