use std::collections::HashMap;
use derive_more::{Display, Error, From};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, From, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum Authentication {
#[serde(rename = "auth_initialization")]
Initialization(Initialization),
#[serde(rename = "auth_start_method")]
StartMethod(StartMethod),
#[serde(rename = "auth_challenge")]
Challenge(Challenge),
#[serde(rename = "auth_verification")]
Verification(Verification),
#[serde(rename = "auth_info")]
Info(Info),
#[serde(rename = "auth_error")]
Error(Error),
#[serde(rename = "auth_finished")]
Finished,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Initialization {
pub methods: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct StartMethod {
pub method: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Challenge {
pub questions: Vec<Question>,
pub options: HashMap<String, String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Verification {
pub kind: VerificationKind,
pub text: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Info {
pub text: String,
}
#[derive(Clone, Debug, From, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum AuthenticationResponse {
#[serde(rename = "auth_initialization_response")]
Initialization(InitializationResponse),
#[serde(rename = "auth_challenge_response")]
Challenge(ChallengeResponse),
#[serde(rename = "auth_verification_response")]
Verification(VerificationResponse),
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct InitializationResponse {
pub methods: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ChallengeResponse {
pub answers: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct VerificationResponse {
pub valid: bool,
}
#[derive(Copy, Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum VerificationKind {
#[display(fmt = "host")]
Host,
#[display(fmt = "unknown")]
#[serde(other)]
Unknown,
}
impl VerificationKind {
pub const fn known_variants() -> &'static [Self] {
&[Self::Host]
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Question {
pub label: String,
pub text: String,
pub options: HashMap<String, String>,
}
impl Question {
pub fn new(text: impl Into<String>) -> Self {
let text = text.into();
Self {
label: text.clone(),
text,
options: HashMap::new(),
}
}
}
#[derive(Clone, Debug, Display, Error, PartialEq, Eq, Serialize, Deserialize)]
#[display(fmt = "{kind}: {text}")]
pub struct Error {
pub kind: ErrorKind,
pub text: String,
}
impl Error {
pub fn fatal(text: impl Into<String>) -> Self {
Self {
kind: ErrorKind::Fatal,
text: text.into(),
}
}
pub fn non_fatal(text: impl Into<String>) -> Self {
Self {
kind: ErrorKind::Error,
text: text.into(),
}
}
pub fn is_fatal(&self) -> bool {
self.kind.is_fatal()
}
pub fn into_io_permission_denied(self) -> std::io::Error {
std::io::Error::new(std::io::ErrorKind::PermissionDenied, self)
}
}
#[derive(Copy, Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ErrorKind {
Fatal,
Error,
}
impl ErrorKind {
pub fn is_fatal(self) -> bool {
matches!(self, Self::Fatal)
}
}