1use std::collections::HashMap;
2
3use derive_more::{Display, Error, From};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, From, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case", tag = "type")]
10pub enum Authentication {
11    #[serde(rename = "auth_initialization")]
13    Initialization(Initialization),
14
15    #[serde(rename = "auth_start_method")]
17    StartMethod(StartMethod),
18
19    #[serde(rename = "auth_challenge")]
21    Challenge(Challenge),
22
23    #[serde(rename = "auth_verification")]
25    Verification(Verification),
26
27    #[serde(rename = "auth_info")]
29    Info(Info),
30
31    #[serde(rename = "auth_error")]
33    Error(Error),
34
35    #[serde(rename = "auth_finished")]
37    Finished,
38}
39
40#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
42pub struct Initialization {
43    pub methods: Vec<String>,
45}
46
47#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
49pub struct StartMethod {
50    pub method: String,
51}
52
53#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
55pub struct Challenge {
56    pub questions: Vec<Question>,
57    pub options: HashMap<String, String>,
58}
59
60#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
62pub struct Verification {
63    pub kind: VerificationKind,
64    pub text: String,
65}
66
67#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
69pub struct Info {
70    pub text: String,
71}
72
73#[derive(Clone, Debug, From, PartialEq, Eq, Serialize, Deserialize)]
76#[serde(rename_all = "snake_case", tag = "type")]
77pub enum AuthenticationResponse {
78    #[serde(rename = "auth_initialization_response")]
80    Initialization(InitializationResponse),
81
82    #[serde(rename = "auth_challenge_response")]
84    Challenge(ChallengeResponse),
85
86    #[serde(rename = "auth_verification_response")]
88    Verification(VerificationResponse),
89}
90
91#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
93pub struct InitializationResponse {
94    pub methods: Vec<String>,
96}
97
98#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
100pub struct ChallengeResponse {
101    pub answers: Vec<String>,
103}
104
105#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
107pub struct VerificationResponse {
108    pub valid: bool,
110}
111
112#[derive(Copy, Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize)]
114#[serde(rename_all = "snake_case")]
115pub enum VerificationKind {
116    #[display(fmt = "host")]
118    Host,
119
120    #[display(fmt = "unknown")]
122    #[serde(other)]
123    Unknown,
124}
125
126impl VerificationKind {
127    pub const fn known_variants() -> &'static [Self] {
129        &[Self::Host]
130    }
131}
132
133#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
135pub struct Question {
136    pub label: String,
138
139    pub text: String,
141
142    pub options: HashMap<String, String>,
145}
146
147impl Question {
148    pub fn new(text: impl Into<String>) -> Self {
150        let text = text.into();
151
152        Self {
153            label: text.clone(),
154            text,
155            options: HashMap::new(),
156        }
157    }
158}
159
160#[derive(Clone, Debug, Display, Error, PartialEq, Eq, Serialize, Deserialize)]
162#[display(fmt = "{kind}: {text}")]
163pub struct Error {
164    pub kind: ErrorKind,
166
167    pub text: String,
169}
170
171impl Error {
172    pub fn fatal(text: impl Into<String>) -> Self {
174        Self {
175            kind: ErrorKind::Fatal,
176            text: text.into(),
177        }
178    }
179
180    pub fn non_fatal(text: impl Into<String>) -> Self {
182        Self {
183            kind: ErrorKind::Error,
184            text: text.into(),
185        }
186    }
187
188    pub fn is_fatal(&self) -> bool {
191        self.kind.is_fatal()
192    }
193
194    pub fn into_io_permission_denied(self) -> std::io::Error {
196        std::io::Error::new(std::io::ErrorKind::PermissionDenied, self)
197    }
198}
199
200#[derive(Copy, Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize)]
202#[serde(rename_all = "snake_case")]
203pub enum ErrorKind {
204    Fatal,
206
207    Error,
209}
210
211impl ErrorKind {
212    pub fn is_fatal(self) -> bool {
215        matches!(self, Self::Fatal)
216    }
217}