Implement Serialize, Deserialize and TryFromMultipart for Username/Password

Enable the axum feature to use it
This commit is contained in:
selfhoster selfhoster 2023-08-22 16:51:52 +02:00
commit 4eb3ac6350
3 changed files with 68 additions and 7 deletions

View file

@ -1,6 +1,17 @@
use ldap3::dn_escape;
use serde::{Serialize, Deserialize};
use snafu::OptionExt;
use snafu::prelude::*;
#[cfg(feature="axum")]
use axum::{
async_trait,
body::Bytes,
};
#[cfg(feature="axum")]
use axum_typed_multipart::{FieldMetadata, TryFromChunks, TypedMultipartError};
#[cfg(feature="axum")]
use futures_util::stream::Stream;
use serde::{Serialize, Deserialize, Deserializer};
use std::str::FromStr;
@ -14,7 +25,7 @@ fn non_empty_string(s: &str) -> Option<String> {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
pub struct Username(String);
impl Username {
@ -56,7 +67,29 @@ impl std::fmt::Display for Username {
}
}
#[derive(Clone, Debug)]
impl<'de> Deserialize<'de> for Username {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}
#[cfg(feature="axum")]
#[async_trait]
impl TryFromChunks for Username {
async fn try_from_chunks(
chunks: impl Stream<Item = Result<Bytes, TypedMultipartError>> + Send + Sync + Unpin,
metadata: FieldMetadata,
) -> Result<Self, TypedMultipartError> {
let string = String::try_from_chunks(chunks, metadata).await?;
let data = Self::from_str(&string).map_err(|e| TypedMultipartError::Other { source: e.into() })?;
Ok(data)
}
}
#[derive(Clone, Debug, Serialize)]
pub struct Password(String);
impl Password {
@ -81,3 +114,25 @@ impl FromStr for Password {
Password::new(s)
}
}
impl<'de> Deserialize<'de> for Password {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}
#[cfg(feature="axum")]
#[async_trait]
impl TryFromChunks for Password {
async fn try_from_chunks(
chunks: impl Stream<Item = Result<Bytes, TypedMultipartError>> + Send + Sync + Unpin,
metadata: FieldMetadata,
) -> Result<Self, TypedMultipartError> {
let string = String::try_from_chunks(chunks, metadata).await?;
let data = Self::from_str(&string).map_err(|e| TypedMultipartError::Other { source: e.into() })?;
Ok(data)
}
}

View file

@ -5,7 +5,7 @@ use std::collections::HashMap;
use crate::Username;
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct SSOWatConfig {
domains: Vec<String>,
permissions: HashMap<PermissionName, Permission>,
@ -32,7 +32,7 @@ impl SSOWatConfig {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Permission {
auth_header: bool,
label: String,
@ -43,7 +43,7 @@ pub struct Permission {
users: Vec<Username>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct PermissionName {
#[serde(flatten)]
name: String,