diff options
author | metamuffin <metamuffin@disroot.org> | 2024-05-30 00:09:11 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-05-30 00:09:11 +0200 |
commit | 532cc431d1c5ca1ffcf429a4ccb94edc7848fe7a (patch) | |
tree | c4422c4d54e01f63bae391cd95788cad74f59fbb /src/modules/auth/mod.rs | |
parent | 8b39940a58c28bc1bbe291eb5229e9ce1444e33c (diff) | |
download | gnix-532cc431d1c5ca1ffcf429a4ccb94edc7848fe7a.tar gnix-532cc431d1c5ca1ffcf429a4ccb94edc7848fe7a.tar.bz2 gnix-532cc431d1c5ca1ffcf429a4ccb94edc7848fe7a.tar.zst |
rename filters dir
Diffstat (limited to 'src/modules/auth/mod.rs')
-rw-r--r-- | src/modules/auth/mod.rs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/modules/auth/mod.rs b/src/modules/auth/mod.rs new file mode 100644 index 0000000..d6e1a35 --- /dev/null +++ b/src/modules/auth/mod.rs @@ -0,0 +1,90 @@ +use argon2::PasswordVerifier; +use argon2::{ + password_hash::{Encoding, PasswordHashString}, + Algorithm, Argon2, Params, PasswordHash, Version, +}; +use serde::de::MapAccess; +use serde::{ + de::{value, Error, Visitor}, + Deserialize, +}; +use std::{collections::HashMap, fmt, fs::read_to_string}; + +pub mod basic; +pub mod cookie; + +struct Credentials { + wrong_user: PasswordHashString, + hashes: HashMap<String, PasswordHashString>, +} + +impl Credentials { + fn get(&self, usernamme: &str) -> &PasswordHashString { + self.hashes.get(usernamme).unwrap_or(&self.wrong_user) + } + pub fn authentificate(&self, usernamme: &str, password: &str) -> bool { + let algo = Argon2::new(Algorithm::Argon2id, Version::V0x13, Params::default()); + let hash = self.get(usernamme); + match hash.algorithm().as_str() { + "argon2id" => algo + .verify_password( + password.as_bytes(), + &PasswordHash::parse(hash.as_str(), hash.encoding()).unwrap(), + ) + .is_ok(), + "never" => false, + _ => false, + } + } +} + +impl<'de> Deserialize<'de> for Credentials { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + struct StringOrMap; + impl<'de> Visitor<'de> for StringOrMap { + type Value = HashMap<String, String>; + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("credentials map or file path") + } + fn visit_str<E>(self, val: &str) -> Result<Self::Value, E> + where + E: Error, + { + let path = String::deserialize(value::StrDeserializer::new(val))?; + let c = serde_yaml::from_str(&read_to_string(path).map_err(|io| { + serde::de::Error::custom(format!("cannot read creds file: {io:?}")) + })?) + .map_err(|e| serde::de::Error::custom(format!("cannot parse creds file: {e:?}")))?; + Ok(c) + } + fn visit_map<A>(self, val: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + Ok(HashMap::deserialize(value::MapAccessDeserializer::new( + val, + ))?) + } + } + let k = deserializer.deserialize_any(StringOrMap)?; + Ok(Credentials { + wrong_user: PasswordHashString::parse("$never", Encoding::B64).unwrap(), + hashes: k + .into_iter() + .map(|(k, v)| { + let hash = PasswordHash::parse(&v, Encoding::B64) + .map_err(|e| { + serde::de::Error::custom(format!( + "phc string for user {k:?} is invalid: {e:?}" + )) + })? + .serialize(); + Ok((k, hash)) + }) + .try_collect()?, + }) + } +} |