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