rustical_store/auth/
principal.rs

1use crate::{
2    Secret,
3    auth::{PrincipalType, UnauthorizedError},
4};
5use axum::extract::{FromRequestParts, OptionalFromRequestParts};
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8use std::convert::Infallible;
9
10#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct AppToken {
12    pub id: String,
13    pub name: String,
14    pub token: Secret<String>,
15    pub created_at: Option<DateTime<Utc>>,
16}
17
18#[derive(Debug, Clone, Deserialize, Serialize)]
19#[serde(deny_unknown_fields)]
20pub struct Principal {
21    pub id: String,
22    pub displayname: Option<String>,
23    #[serde(default)]
24    pub principal_type: PrincipalType,
25    #[serde(skip_serializing)]
26    pub password: Option<Secret<String>>,
27    #[serde(default)]
28    pub memberships: Vec<String>,
29}
30
31impl Principal {
32    /// Returns true if the user is either
33    /// - the principal itself
34    /// - has full access to the prinicpal (is member)
35    #[must_use]
36    pub fn is_principal(&self, principal: &str) -> bool {
37        if self.id == principal {
38            return true;
39        }
40        self.memberships
41            .iter()
42            .any(|membership| membership == principal)
43    }
44
45    /// Returns all principals the user implements
46    pub fn memberships(&self) -> Vec<&str> {
47        std::iter::once(self.id.as_str())
48            .chain(self.memberships.iter().map(String::as_ref))
49            .collect()
50    }
51
52    pub fn memberships_without_self(&self) -> Vec<&str> {
53        self.memberships.iter().map(String::as_str).collect()
54    }
55}
56
57impl rustical_dav::Principal for Principal {
58    fn get_id(&self) -> &str {
59        &self.id
60    }
61}
62
63impl<S: Send + Sync + Clone> FromRequestParts<S> for Principal {
64    type Rejection = UnauthorizedError;
65
66    async fn from_request_parts(
67        parts: &mut http::request::Parts,
68        _state: &S,
69    ) -> Result<Self, Self::Rejection> {
70        parts
71            .extensions
72            .get::<Self>()
73            .cloned()
74            .ok_or(UnauthorizedError)
75    }
76}
77
78impl<S: Send + Sync + Clone> OptionalFromRequestParts<S> for Principal {
79    type Rejection = Infallible;
80
81    async fn from_request_parts(
82        parts: &mut http::request::Parts,
83        _state: &S,
84    ) -> Result<Option<Self>, Self::Rejection> {
85        Ok(parts.extensions.get::<Self>().cloned())
86    }
87}