From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 0391F1FF1A6 for ; Tue, 13 May 2025 12:15:12 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id DEB391E5A5; Tue, 13 May 2025 12:15:33 +0200 (CEST) From: Stefan Hanreich To: pbs-devel@lists.proxmox.com Date: Tue, 13 May 2025 12:14:55 +0200 Message-Id: <20250513101459.122641-3-s.hanreich@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250513101459.122641-1-s.hanreich@proxmox.com> References: <20250513101459.122641-1-s.hanreich@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.283 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [parse.rs, api.rs, lib.rs] URIBL_CSS_A 0.1 Contains URL's A record listed in the Spamhaus CSS blocklist [195.154.200.217] Subject: [pbs-devel] [PATCH proxmox 2/3] login: move parse module to proxmox-serde X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" Remove the parse module, that has been moved to proxmox-serde. Fix all usages of the parse module in the process and add the new dependency. No functional changes intended. Signed-off-by: Stefan Hanreich --- proxmox-login/Cargo.toml | 1 + proxmox-login/src/api.rs | 2 +- proxmox-login/src/lib.rs | 2 - proxmox-login/src/parse.rs | 373 ------------------------------------- 4 files changed, 2 insertions(+), 376 deletions(-) delete mode 100644 proxmox-login/src/parse.rs diff --git a/proxmox-login/Cargo.toml b/proxmox-login/Cargo.toml index 50dfe2c8..2dc28d52 100644 --- a/proxmox-login/Cargo.toml +++ b/proxmox-login/Cargo.toml @@ -16,6 +16,7 @@ base64.workspace = true percent-encoding.workspace = true serde = { workspace = true, features = [ "derive" ] } serde_json.workspace = true +proxmox-serde = { workspace = true, features = [ "perl" ] } # For webauthn types webauthn-rs = { workspace = true, optional = true } diff --git a/proxmox-login/src/api.rs b/proxmox-login/src/api.rs index b7107312..6023485c 100644 --- a/proxmox-login/src/api.rs +++ b/proxmox-login/src/api.rs @@ -11,7 +11,7 @@ pub struct CreateTicket { /// With webauthn the format of half-authenticated tickts changed. New /// clients should pass 1 here and not worry about the old format. The old /// format is deprecated and will be retired with PVE-8.0 - #[serde(deserialize_with = "crate::parse::deserialize_bool")] + #[serde(deserialize_with = "proxmox_serde::perl::deserialize_bool")] #[serde(default, skip_serializing_if = "Option::is_none")] #[serde(rename = "new-format")] pub new_format: Option, diff --git a/proxmox-login/src/lib.rs b/proxmox-login/src/lib.rs index e97ece7b..4482f2e4 100644 --- a/proxmox-login/src/lib.rs +++ b/proxmox-login/src/lib.rs @@ -5,8 +5,6 @@ use serde::{Deserialize, Serialize}; -pub mod parse; - pub mod api; pub mod error; pub mod tfa; diff --git a/proxmox-login/src/parse.rs b/proxmox-login/src/parse.rs deleted file mode 100644 index 8efa86c9..00000000 --- a/proxmox-login/src/parse.rs +++ /dev/null @@ -1,373 +0,0 @@ -//! Some parsing helpers for the PVE API, mainly to deal with perl's untypedness. - -use std::fmt; - -use serde::de::Unexpected; - -// Boolean: - -pub trait FromBool: Sized + Default { - fn from_bool(value: bool) -> Self; -} - -impl FromBool for bool { - fn from_bool(value: bool) -> Self { - value - } -} - -impl FromBool for Option { - fn from_bool(value: bool) -> Self { - Some(value) - } -} - -pub fn deserialize_bool<'de, D, T>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, - T: FromBool, -{ - deserializer.deserialize_any(BoolVisitor::::new()) -} - -struct BoolVisitor(std::marker::PhantomData); - -impl BoolVisitor { - fn new() -> Self { - Self(std::marker::PhantomData) - } -} - -impl<'de, T: FromBool> serde::de::DeserializeSeed<'de> for BoolVisitor { - type Value = T; - - fn deserialize(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserialize_bool(deserializer) - } -} - -impl<'de, T> serde::de::Visitor<'de> for BoolVisitor -where - T: FromBool, -{ - type Value = T; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("a boolean-ish...") - } - - fn visit_some(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_any(self) - } - - fn visit_none(self) -> Result { - Ok(Default::default()) - } - - fn visit_bool(self, value: bool) -> Result { - Ok(Self::Value::from_bool(value)) - } - - fn visit_i128(self, value: i128) -> Result { - Ok(Self::Value::from_bool(value != 0)) - } - - fn visit_i64(self, value: i64) -> Result { - Ok(Self::Value::from_bool(value != 0)) - } - - fn visit_u64(self, value: u64) -> Result { - Ok(Self::Value::from_bool(value != 0)) - } - - fn visit_u128(self, value: u128) -> Result { - Ok(Self::Value::from_bool(value != 0)) - } - - fn visit_str(self, value: &str) -> Result { - let value = if value.eq_ignore_ascii_case("true") - || value.eq_ignore_ascii_case("yes") - || value.eq_ignore_ascii_case("on") - || value == "1" - { - true - } else if value.eq_ignore_ascii_case("false") - || value.eq_ignore_ascii_case("no") - || value.eq_ignore_ascii_case("off") - || value == "0" - { - false - } else { - return Err(E::invalid_value( - serde::de::Unexpected::Str(value), - &"a boolean-like value", - )); - }; - Ok(Self::Value::from_bool(value)) - } -} - -// integer helpers: - -macro_rules! integer_helper { - ($ty:ident, $deserialize_name:ident, $trait: ident, $from_name:ident, $visitor:ident) => { - #[doc(hidden)] - pub trait $trait: Sized + Default { - fn $from_name(value: $ty) -> Self; - } - - impl $trait for $ty { - fn $from_name(value: $ty) -> Self { - value - } - } - - impl $trait for Option<$ty> { - fn $from_name(value: $ty) -> Self { - Some(value) - } - } - - pub fn $deserialize_name<'de, D, T>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - T: $trait, - { - deserializer.deserialize_any($visitor::::new()) - } - - struct $visitor(std::marker::PhantomData); - - impl $visitor { - fn new() -> Self { - Self(std::marker::PhantomData) - } - } - - impl<'de, T: $trait> serde::de::DeserializeSeed<'de> for $visitor { - type Value = T; - - fn deserialize(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - $deserialize_name(deserializer) - } - } - - impl<'de, T> serde::de::Visitor<'de> for $visitor - where - T: $trait, - { - type Value = T; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(concat!("a ", stringify!($ty), "-ish...")) - } - - fn visit_some(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_any(self) - } - - fn visit_none(self) -> Result { - Ok(Default::default()) - } - - fn visit_i128(self, value: i128) -> Result { - $ty::try_from(value) - .map_err(|_| E::invalid_value(Unexpected::Other("i128"), &self)) - .map(Self::Value::$from_name) - } - - fn visit_i64(self, value: i64) -> Result { - $ty::try_from(value) - .map_err(|_| E::invalid_value(Unexpected::Signed(value), &self)) - .map(Self::Value::$from_name) - } - - fn visit_u64(self, value: u64) -> Result { - $ty::try_from(value) - .map_err(|_| E::invalid_value(Unexpected::Unsigned(value), &self)) - .map(Self::Value::$from_name) - } - - fn visit_u128(self, value: u128) -> Result { - $ty::try_from(value) - .map_err(|_| E::invalid_value(Unexpected::Other("u128"), &self)) - .map(Self::Value::$from_name) - } - - fn visit_str(self, value: &str) -> Result { - let value = value - .parse() - .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?; - self.visit_i64(value) - } - } - }; -} - -integer_helper!( - isize, - deserialize_isize, - FromIsize, - from_isize, - IsizeVisitor -); - -integer_helper!( - usize, - deserialize_usize, - FromUsize, - from_usize, - UsizeVisitor -); - -integer_helper!(u8, deserialize_u8, FromU8, from_u8, U8Visitor); -integer_helper!(u16, deserialize_u16, FromU16, from_u16, U16Visitor); -integer_helper!(u32, deserialize_u32, FromU32, from_u32, U32Visitor); -integer_helper!(u64, deserialize_u64, FromU64, from_u64, U64Visitor); -integer_helper!(i8, deserialize_i8, FromI8, from_i8, I8Visitor); -integer_helper!(i16, deserialize_i16, FromI16, from_i16, I16Visitor); -integer_helper!(i32, deserialize_i32, FromI32, from_i32, I32Visitor); -integer_helper!(i64, deserialize_i64, FromI64, from_i64, I64Visitor); - -// float helpers: - -macro_rules! float_helper { - ($ty:ident, $deserialize_name:ident, $visitor:ident) => { - pub fn $deserialize_name<'de, D, T>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - T: FromF64, - { - deserializer.deserialize_any($visitor::::new()) - } - - struct $visitor(std::marker::PhantomData); - - impl $visitor { - fn new() -> Self { - Self(std::marker::PhantomData) - } - } - - impl<'de, T: FromF64> serde::de::DeserializeSeed<'de> for $visitor { - type Value = T; - - fn deserialize(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - $deserialize_name(deserializer) - } - } - - impl<'de, T> serde::de::Visitor<'de> for $visitor - where - T: FromF64, - { - type Value = T; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(concat!("a ", stringify!($ty), "-ish...")) - } - - fn visit_some(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_any(self) - } - - fn visit_none(self) -> Result { - Ok(Default::default()) - } - - fn visit_f64(self, value: f64) -> Result { - Ok(T::from_f64(value)) - } - - fn visit_i128(self, value: i128) -> Result { - let conv = value as f64; - if conv as i128 == value { - Ok(T::from_f64(conv)) - } else { - Err(E::invalid_value(Unexpected::Other("i128"), &self)) - } - } - - fn visit_i64(self, value: i64) -> Result { - let conv = value as f64; - if conv as i64 == value { - Ok(T::from_f64(conv)) - } else { - Err(E::invalid_value(Unexpected::Signed(value), &self)) - } - } - - fn visit_u128(self, value: u128) -> Result { - let conv = value as f64; - if conv as u128 == value { - Ok(T::from_f64(conv)) - } else { - Err(E::invalid_value(Unexpected::Other("u128"), &self)) - } - } - - fn visit_u64(self, value: u64) -> Result { - let conv = value as f64; - if conv as u64 == value { - Ok(T::from_f64(conv)) - } else { - Err(E::invalid_value(Unexpected::Unsigned(value), &self)) - } - } - - fn visit_str(self, value: &str) -> Result { - let value = value - .parse() - .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?; - self.visit_f64(value) - } - } - }; -} - -#[doc(hidden)] -pub trait FromF64: Sized + Default { - fn from_f64(value: f64) -> Self; -} - -impl FromF64 for f32 { - #[inline(always)] - fn from_f64(f: f64) -> f32 { - f as f32 - } -} - -impl FromF64 for f64 { - #[inline(always)] - fn from_f64(f: f64) -> f64 { - f - } -} - -impl FromF64 for Option { - #[inline(always)] - fn from_f64(f: f64) -> Option { - Some(T::from_f64(f)) - } -} - -float_helper!(f32, deserialize_f32, F32Visitor); -float_helper!(f64, deserialize_f64, F64Visitor); -- 2.39.5 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel