Skip to main content

kanidm_proto/internal/
mod.rs

1//! Kanidm internal elements
2//!
3//! Items defined in this module *may* change between releases without notice.
4
5use crate::constants::{
6    CONTENT_TYPE_GIF, CONTENT_TYPE_JPG, CONTENT_TYPE_PNG, CONTENT_TYPE_SVG, CONTENT_TYPE_WEBP,
7};
8use clap::ValueEnum;
9use serde::{Deserialize, Serialize};
10use std::fmt;
11use std::str::FromStr;
12use url::Url;
13use utoipa::ToSchema;
14use uuid::Uuid;
15
16use num_enum::TryFromPrimitive;
17
18mod credupdate;
19mod error;
20mod raw;
21mod token;
22
23pub use self::credupdate::*;
24pub use self::error::*;
25pub use self::raw::*;
26pub use self::token::*;
27
28pub const COOKIE_CSRF_NONCE: &str = "csrf-nonce";
29pub const COOKIE_AUTH_SESSION_ID: &str = "auth-session-id";
30pub const COOKIE_BEARER_TOKEN: &str = "bearer";
31pub const COOKIE_CU_SESSION_TOKEN: &str = "cu-session-token";
32pub const COOKIE_USERNAME: &str = "username";
33pub const COOKIE_OAUTH2_REQ: &str = "o2-authreq";
34
35#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
36/// This is a description of a linked or connected application for a user. This is
37/// used in the UI to render applications on the dashboard for a user to access.
38pub enum AppLink {
39    Oauth2 {
40        name: String,
41        display_name: String,
42        redirect_url: Url,
43        // Whether this oauth2 resource has an image.
44        has_image: bool,
45    },
46}
47
48#[derive(
49    Debug, Serialize, Deserialize, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, ToSchema,
50)]
51#[serde(rename_all = "lowercase")]
52#[derive(TryFromPrimitive)]
53#[repr(u16)]
54pub enum UiHint {
55    ExperimentalFeatures = 0,
56    PosixAccount = 1,
57    CredentialUpdate = 2,
58    SynchronisedAccount = 3,
59}
60
61impl fmt::Display for UiHint {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        write!(f, "{}", self.as_ref())
64    }
65}
66
67impl AsRef<str> for UiHint {
68    fn as_ref(&self) -> &str {
69        match self {
70            UiHint::PosixAccount => "PosixAccount",
71            UiHint::CredentialUpdate => "CredentialUpdate",
72            UiHint::ExperimentalFeatures => "ExperimentalFeatures",
73            UiHint::SynchronisedAccount => "SynchronisedAccount",
74        }
75    }
76}
77
78impl FromStr for UiHint {
79    type Err = ();
80
81    fn from_str(s: &str) -> Result<Self, Self::Err> {
82        match s {
83            "CredentialUpdate" => Ok(UiHint::CredentialUpdate),
84            "PosixAccount" => Ok(UiHint::PosixAccount),
85            "ExperimentalFeatures" => Ok(UiHint::ExperimentalFeatures),
86            "SynchronisedAccount" => Ok(UiHint::SynchronisedAccount),
87            _ => Err(()),
88        }
89    }
90}
91
92// State machine states and transitions for the identity verification system feature!
93#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, ToSchema)]
94pub enum IdentifyUserRequest {
95    Start,
96    SubmitCode { other_totp: u32 },
97    DisplayCode,
98}
99
100#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, ToSchema)]
101pub enum IdentifyUserResponse {
102    IdentityVerificationUnavailable,
103    IdentityVerificationAvailable,
104    ProvideCode { step: u32, totp: u32 },
105    WaitForCode,
106    Success,
107    CodeFailure,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Ord, PartialOrd, ValueEnum)]
111#[serde(rename_all = "lowercase")]
112pub enum ImageType {
113    Png,
114    Jpg,
115    Gif,
116    Svg,
117    Webp,
118}
119
120impl TryFrom<&str> for ImageType {
121    type Error = &'static str;
122    /// ```
123    /// use kanidm_proto::internal::ImageType;
124    /// assert_eq!(ImageType::try_from("png").unwrap(), ImageType::Png);
125    /// assert!(ImageType::try_from("krabs").is_err());
126    /// ```
127    fn try_from(value: &str) -> Result<Self, &'static str> {
128        #[allow(clippy::panic)]
129        match value {
130            "png" => Ok(Self::Png),
131            "jpg" => Ok(Self::Jpg),
132            "jpeg" => Ok(Self::Jpg), // ugh I hate this
133            "gif" => Ok(Self::Gif),
134            "svg" => Ok(Self::Svg),
135            "webp" => Ok(Self::Webp),
136            _ => Err("Invalid image type!"),
137        }
138    }
139}
140
141impl ImageType {
142    pub fn try_from_content_type(content_type: &str) -> Result<Self, String> {
143        let content_type = content_type.to_lowercase();
144        match content_type.as_str() {
145            CONTENT_TYPE_JPG => Ok(ImageType::Jpg),
146            CONTENT_TYPE_PNG => Ok(ImageType::Png),
147            CONTENT_TYPE_GIF => Ok(ImageType::Gif),
148            CONTENT_TYPE_WEBP => Ok(ImageType::Webp),
149            CONTENT_TYPE_SVG => Ok(ImageType::Svg),
150            _ => Err(format!("Invalid content type: {content_type}")),
151        }
152    }
153
154    pub fn as_content_type_str(&self) -> &'static str {
155        match &self {
156            ImageType::Jpg => CONTENT_TYPE_JPG,
157            ImageType::Png => CONTENT_TYPE_PNG,
158            ImageType::Gif => CONTENT_TYPE_GIF,
159            ImageType::Webp => CONTENT_TYPE_WEBP,
160            ImageType::Svg => CONTENT_TYPE_SVG,
161        }
162    }
163}
164
165#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, PartialOrd, Ord, Hash)]
166pub struct ImageValue {
167    pub filename: String,
168    pub filetype: ImageType,
169    pub contents: Vec<u8>,
170}
171
172impl TryFrom<&str> for ImageValue {
173    type Error = String;
174    fn try_from(s: &str) -> Result<Self, String> {
175        serde_json::from_str(s).map_err(|e| format!("Failed to decode ImageValue from {s} - {e:?}"))
176    }
177}
178
179impl ImageValue {
180    pub fn new(filename: String, filetype: ImageType, contents: Vec<u8>) -> Self {
181        Self {
182            filename,
183            filetype,
184            contents,
185        }
186    }
187}
188
189#[repr(u32)]
190#[derive(Debug, Copy, Clone, Deserialize, Default, Eq, PartialEq)]
191#[serde(rename_all = "lowercase")]
192/// Filesystem type object, used for tuning database parameters.
193pub enum FsType {
194    Zfs = 65536,
195    #[default]
196    #[serde(other)]
197    /// The default setting, if not set to "zfs"
198    Generic = 4096,
199}
200
201impl FsType {
202    pub fn checkpoint_pages(&self) -> u32 {
203        match self {
204            FsType::Generic => 2048,
205            FsType::Zfs => 256,
206        }
207    }
208}
209
210impl TryFrom<&str> for FsType {
211    type Error = ();
212
213    fn try_from(s: &str) -> Result<Self, Self::Error> {
214        match s {
215            "zfs" => Ok(FsType::Zfs),
216            "generic" => Ok(FsType::Generic),
217            _ => Err(()),
218        }
219    }
220}
221
222impl FromStr for FsType {
223    type Err = &'static str;
224
225    fn from_str(s: &str) -> Result<Self, Self::Err> {
226        FsType::try_from(s).map_err(|_| "Invalid FsType, must be either 'zfs' or 'generic'")
227    }
228}
229
230#[derive(Debug, Serialize, Deserialize, Clone, Copy, ToSchema)]
231pub enum Oauth2ClaimMapJoin {
232    #[serde(rename = "csv")]
233    Csv,
234    #[serde(rename = "ssv")]
235    Ssv,
236    #[serde(rename = "array")]
237    Array,
238}
239
240#[derive(Debug, Serialize, Deserialize, Clone)]
241pub struct DomainInfo {
242    pub name: String,
243    pub displayname: String,
244    pub uuid: Uuid,
245    pub level: u32,
246}
247
248#[derive(Debug, Serialize, Deserialize, Clone)]
249pub struct DomainUpgradeCheckReport {
250    pub name: String,
251    pub uuid: Uuid,
252    pub current_level: u32,
253    pub upgrade_level: u32,
254    pub report_items: Vec<DomainUpgradeCheckItem>,
255}
256
257#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
258pub enum DomainUpgradeCheckStatus {
259    Pass6To7Gidnumber,
260    Fail6To7Gidnumber,
261
262    Pass7To8SecurityKeys,
263    Fail7To8SecurityKeys,
264
265    Pass7To8Oauth2StrictRedirectUri,
266    Fail7To8Oauth2StrictRedirectUri,
267}
268
269#[derive(Debug, Serialize, Deserialize, Clone)]
270pub struct DomainUpgradeCheckItem {
271    pub from_level: u32,
272    pub to_level: u32,
273    pub status: DomainUpgradeCheckStatus,
274    pub affected_entries: Vec<String>,
275}
276
277#[test]
278fn test_fstype_deser() {
279    assert_eq!(FsType::try_from("zfs"), Ok(FsType::Zfs));
280    assert_eq!(FsType::try_from("generic"), Ok(FsType::Generic));
281    assert_eq!(FsType::try_from(" "), Err(()));
282    assert_eq!(FsType::try_from("crab🦀"), Err(()));
283}