1use 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)]
36pub enum AppLink {
39 Oauth2 {
40 name: String,
41 display_name: String,
42 redirect_url: Url,
43 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#[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 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), "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")]
192pub enum FsType {
194 Zfs = 65536,
195 #[default]
196 #[serde(other)]
197 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}