From 9941feaf8a1a8eb7de1e5a4639032b11ad449c2a Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 2 Dec 2020 02:59:06 -0500 Subject: allow TwoFactorType to be provided as an integer or string bitwarden-rs still provides it as an integer, but bitwarden.com now provides it as a string --- src/api.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++----------- src/error.rs | 2 +- 2 files changed, 68 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/api.rs b/src/api.rs index 97e5006..77a6ee6 100644 --- a/src/api.rs +++ b/src/api.rs @@ -15,10 +15,52 @@ pub enum TwoFactorProviderType { OrganizationDuo = 6, } -impl std::convert::TryFrom for TwoFactorProviderType { +impl<'de> serde::Deserialize<'de> for TwoFactorProviderType { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct TwoFactorProviderTypeVisitor; + impl<'de> serde::de::Visitor<'de> for TwoFactorProviderTypeVisitor { + type Value = TwoFactorProviderType; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter, + ) -> std::fmt::Result { + formatter.write_str("two factor provider id") + } + + fn visit_str( + self, + value: &str, + ) -> std::result::Result + where + E: serde::de::Error, + { + value.parse().map_err(serde::de::Error::custom) + } + + fn visit_u64( + self, + value: u64, + ) -> std::result::Result + where + E: serde::de::Error, + { + std::convert::TryFrom::try_from(value) + .map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_any(TwoFactorProviderTypeVisitor) + } +} + +impl std::convert::TryFrom for TwoFactorProviderType { type Error = Error; - fn try_from(ty: u32) -> Result { + fn try_from(ty: u64) -> Result { match ty { 0 => Ok(Self::Authenticator), 1 => Ok(Self::Email), @@ -27,7 +69,26 @@ impl std::convert::TryFrom for TwoFactorProviderType { 4 => Ok(Self::U2f), 5 => Ok(Self::Remember), 6 => Ok(Self::OrganizationDuo), - _ => Err(Error::InvalidTwoFactorProvider { ty }), + _ => Err(Error::InvalidTwoFactorProvider { + ty: format!("{}", ty), + }), + } + } +} + +impl std::str::FromStr for TwoFactorProviderType { + type Err = Error; + + fn from_str(ty: &str) -> Result { + match ty { + "0" => Ok(Self::Authenticator), + "1" => Ok(Self::Email), + "2" => Ok(Self::Duo), + "3" => Ok(Self::Yubikey), + "4" => Ok(Self::U2f), + "5" => Ok(Self::Remember), + "6" => Ok(Self::OrganizationDuo), + _ => Err(Error::InvalidTwoFactorProvider { ty: ty.to_string() }), } } } @@ -83,7 +144,7 @@ struct ConnectErrorRes { #[serde(rename = "ErrorModel")] error_model: Option, #[serde(rename = "TwoFactorProviders")] - two_factor_providers: Option>, + two_factor_providers: Option>, } #[derive(serde::Deserialize, Debug)] @@ -946,16 +1007,8 @@ fn classify_login_error(error_res: &ConnectErrorRes, code: u16) -> Error { if let Some(providers) = error_res.two_factor_providers.as_ref() { - let providers: Result<_> = providers - .iter() - .copied() - .map(std::convert::TryInto::try_into) - .collect(); - return match providers { - Ok(providers) => { - Error::TwoFactorRequired { providers } - } - Err(e) => e, + return Error::TwoFactorRequired { + providers: providers.to_vec(), }; } } diff --git a/src/error.rs b/src/error.rs index 131d5b9..7201ce0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -50,7 +50,7 @@ pub enum Error { InvalidMac, #[snafu(display("invalid two factor provider type: {}", ty))] - InvalidTwoFactorProvider { ty: u32 }, + InvalidTwoFactorProvider { ty: String }, #[snafu(display("failed to parse JSON"))] JSON { -- cgit v1.2.3-54-g00ecf