diff options
author | Jesse Luehrs <doy@tozt.net> | 2023-03-25 22:01:37 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-25 22:01:37 -0500 |
commit | c12c7643779bc495ff5f26cfe0e924586ced3f2c (patch) | |
tree | 5207ee6eab126594e2b2af4a12af09ec97165e5c /src/api.rs | |
parent | 2f9bd4eb45c57ce8e8d3011d7660223c05b50f98 (diff) | |
parent | 7b57f928e5fb345e02f6101d07d5cbbc7e540458 (diff) | |
download | rbw-c12c7643779bc495ff5f26cfe0e924586ced3f2c.tar.gz rbw-c12c7643779bc495ff5f26cfe0e924586ced3f2c.zip |
Merge pull request #109 from quexten/feature/argon2
Implement argon2 kdf
Diffstat (limited to 'src/api.rs')
-rw-r--r-- | src/api.rs | 101 |
1 files changed, 99 insertions, 2 deletions
@@ -169,8 +169,14 @@ struct PreloginReq { #[derive(serde::Deserialize, Debug)] struct PreloginRes { + #[serde(rename = "Kdf", alias = "kdf")] + kdf: KdfType, #[serde(rename = "KdfIterations", alias = "kdfIterations")] kdf_iterations: u32, + #[serde(rename = "KdfMemory", alias = "kdfMemory")] + kdf_memory: Option<u32>, + #[serde(rename = "KdfParallelism", alias = "kdfParallelism")] + kdf_parallelism: Option<u32>, } #[derive(serde::Serialize, Debug)] @@ -628,7 +634,7 @@ impl Client { } } - pub async fn prelogin(&self, email: &str) -> Result<u32> { + pub async fn prelogin(&self, email: &str) -> Result<(KdfType, u32, Option<u32>, Option<u32>)> { let prelogin = PreloginReq { email: email.to_string(), }; @@ -640,7 +646,7 @@ impl Client { .await .map_err(|source| Error::Reqwest { source })?; let prelogin_res: PreloginRes = res.json_with_path().await?; - Ok(prelogin_res.kdf_iterations) + Ok((prelogin_res.kdf, prelogin_res.kdf_iterations, prelogin_res.kdf_memory, prelogin_res.kdf_parallelism)) } pub async fn register( @@ -1212,3 +1218,94 @@ fn classify_login_error(error_res: &ConnectErrorRes, code: u16) -> Error { log::warn!("unexpected error received during login: {:?}", error_res); Error::RequestFailed { status: code } } + + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum KdfType { + Pbkdf2 = 0, + Argon2id = 1, +} + +impl<'de> serde::Deserialize<'de> for KdfType { + fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + struct KdfTypeVisitor; + impl<'de> serde::de::Visitor<'de> for KdfTypeVisitor { + type Value = KdfType; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter, + ) -> std::fmt::Result { + formatter.write_str("two factor provider id") + } + + fn visit_str<E>( + self, + value: &str, + ) -> std::result::Result<Self::Value, E> + where + E: serde::de::Error, + { + value.parse().map_err(serde::de::Error::custom) + } + + fn visit_u64<E>( + self, + value: u64, + ) -> std::result::Result<Self::Value, E> + where + E: serde::de::Error, + { + std::convert::TryFrom::try_from(value) + .map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_any(KdfTypeVisitor) + } +} + +impl std::convert::TryFrom<u64> for KdfType { + type Error = Error; + + fn try_from(ty: u64) -> Result<Self> { + match ty { + 0 => Ok(Self::Pbkdf2), + 1 => Ok(Self::Argon2id), + _ => Err(Error::InvalidTwoFactorProvider { + ty: format!("{ty}"), + }), + } + } +} + +impl std::str::FromStr for KdfType { + type Err = Error; + + fn from_str(ty: &str) -> Result<Self> { + match ty { + "0" => Ok(Self::Pbkdf2), + "1" => Ok(Self::Argon2id), + _ => Err(Error::InvalidTwoFactorProvider { ty: ty.to_string() }), + } + } +} + +impl serde::Serialize for KdfType { + fn serialize<S>( + &self, + serializer: S, + ) -> std::result::Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + let s = match self { + Self::Pbkdf2 => "0", + Self::Argon2id => "1", + }; + serializer.serialize_str(s) + } +} |