use std::collections::VecDeque; use std::marker::PhantomData; use std::ops::Deref; use std::str::FromStr; use base64::Engine; use clap::builder::ValueParserFactory; use clap::{ArgMatches, CommandFactory, FromArgMatches}; use color_eyre::eyre::eyre; use digest::Update; use digest::generic_array::GenericArray; use hashing_serializer::HashingSerializer; use imbl_value::imbl::OrdMap; use openssl::pkey::{PKey, Private}; use openssl::x509::X509; use rpc_toolkit::{ CliBindings, Context, HandlerArgs, HandlerArgsFor, HandlerFor, HandlerTypes, PrintCliResult, }; use serde::de::DeserializeOwned; use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use sha2::Digest; use ts_rs::TS; use super::IntoDoubleEndedIterator; use crate::prelude::*; use crate::util::{Apply, FromStrParser}; pub fn const_true() -> bool { true } pub fn deserialize_from_str< 'de, D: serde::de::Deserializer<'de>, T: FromStr, E: std::fmt::Display, >( deserializer: D, ) -> std::result::Result { struct Visitor, E>(std::marker::PhantomData); impl<'de, T: FromStr, Err: std::fmt::Display> serde::de::Visitor<'de> for Visitor { type Value = T; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( formatter, "a string that can be parsed as a {}", std::any::type_name::() ) } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { v.parse().map_err(|e| serde::de::Error::custom(e)) } } deserializer.deserialize_str(Visitor(std::marker::PhantomData)) } pub fn deserialize_from_str_opt< 'de, D: serde::de::Deserializer<'de>, T: FromStr, E: std::fmt::Display, >( deserializer: D, ) -> std::result::Result, D::Error> { struct Visitor, E>(std::marker::PhantomData); impl<'de, T: FromStr, Err: std::fmt::Display> serde::de::Visitor<'de> for Visitor { type Value = Option; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "a parsable string") } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { v.parse().map(Some).map_err(|e| serde::de::Error::custom(e)) } fn visit_some(self, deserializer: D) -> Result where D: serde::de::Deserializer<'de>, { deserializer.deserialize_str(Visitor(std::marker::PhantomData)) } fn visit_none(self) -> Result where E: serde::de::Error, { Ok(None) } fn visit_unit(self) -> Result where E: serde::de::Error, { Ok(None) } } deserializer.deserialize_any(Visitor(std::marker::PhantomData)) } pub fn serialize_display( t: &T, serializer: S, ) -> Result { String::serialize(&t.to_string(), serializer) } pub fn serialize_display_opt( t: &Option, serializer: S, ) -> Result { Option::::serialize(&t.as_ref().map(|t| t.to_string()), serializer) } #[derive(Debug, Serialize)] #[serde(untagged)] pub enum ValuePrimitive { Null, Boolean(bool), String(String), Number(serde_json::Number), } impl<'de> serde::de::Deserialize<'de> for ValuePrimitive { fn deserialize(deserializer: D) -> Result where D: serde::de::Deserializer<'de>, { struct Visitor; impl<'de> serde::de::Visitor<'de> for Visitor { type Value = ValuePrimitive; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a JSON primative value") } fn visit_unit(self) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Null) } fn visit_none(self) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Null) } fn visit_bool(self, v: bool) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Boolean(v)) } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::String(v.to_owned())) } fn visit_string(self, v: String) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::String(v)) } fn visit_f32(self, v: f32) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number( serde_json::Number::from_f64(v as f64).ok_or_else(|| { serde::de::Error::invalid_value( serde::de::Unexpected::Float(v as f64), &"a finite number", ) })?, )) } fn visit_f64(self, v: f64) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number( serde_json::Number::from_f64(v).ok_or_else(|| { serde::de::Error::invalid_value( serde::de::Unexpected::Float(v), &"a finite number", ) })?, )) } fn visit_u8(self, v: u8) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } fn visit_u16(self, v: u16) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } fn visit_u32(self, v: u32) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } fn visit_u64(self, v: u64) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } fn visit_i8(self, v: i8) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } fn visit_i16(self, v: i16) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } fn visit_i32(self, v: i32) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } fn visit_i64(self, v: i64) -> Result where E: serde::de::Error, { Ok(ValuePrimitive::Number(v.into())) } } deserializer.deserialize_any(Visitor) } } #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)] #[serde(rename_all = "kebab-case")] pub enum IoFormat { Json, JsonPretty, Yaml, Cbor, Toml, TomlPretty, } impl Default for IoFormat { fn default() -> Self { IoFormat::JsonPretty } } impl std::fmt::Display for IoFormat { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use IoFormat::*; match self { Json => write!(f, "JSON"), JsonPretty => write!(f, "JSON (pretty)"), Yaml => write!(f, "YAML"), Cbor => write!(f, "CBOR"), Toml => write!(f, "TOML"), TomlPretty => write!(f, "TOML (pretty)"), } } } impl std::str::FromStr for IoFormat { type Err = Error; fn from_str(s: &str) -> Result { serde_json::from_value(serde_json::Value::String(s.to_owned())) .with_kind(crate::ErrorKind::Deserialization) } } impl IoFormat { pub fn to_writer( &self, mut writer: W, value: &T, ) -> Result<(), Error> { match self { IoFormat::Json => { serde_json::to_writer(writer, value).with_kind(crate::ErrorKind::Serialization) } IoFormat::JsonPretty => serde_json::to_writer_pretty(writer, value) .with_kind(crate::ErrorKind::Serialization), IoFormat::Yaml => { serde_yaml::to_writer(writer, value).with_kind(crate::ErrorKind::Serialization) } IoFormat::Cbor => serde_cbor::ser::into_writer(value, writer) .with_kind(crate::ErrorKind::Serialization), IoFormat::Toml => writer .write_all( serde_toml::to_string( &serde_toml::Value::try_from(value) .with_kind(crate::ErrorKind::Serialization)?, ) .with_kind(crate::ErrorKind::Serialization)? .as_bytes(), ) .with_kind(crate::ErrorKind::Serialization), IoFormat::TomlPretty => writer .write_all( serde_toml::to_string_pretty( &serde_toml::Value::try_from(value) .with_kind(crate::ErrorKind::Serialization)?, ) .with_kind(crate::ErrorKind::Serialization)? .as_bytes(), ) .with_kind(crate::ErrorKind::Serialization), } } pub fn to_vec(&self, value: &T) -> Result, Error> { match self { IoFormat::Json => serde_json::to_vec(value).with_kind(crate::ErrorKind::Serialization), IoFormat::JsonPretty => { serde_json::to_vec_pretty(value).with_kind(crate::ErrorKind::Serialization) } IoFormat::Yaml => serde_yaml::to_string(value) .with_kind(crate::ErrorKind::Serialization) .map(|s| s.into_bytes()), IoFormat::Cbor => { let mut res = Vec::new(); serde_cbor::ser::into_writer(value, &mut res) .with_kind(crate::ErrorKind::Serialization)?; Ok(res) } IoFormat::Toml => serde_toml::to_string( &serde_toml::Value::try_from(value).with_kind(crate::ErrorKind::Serialization)?, ) .with_kind(crate::ErrorKind::Serialization) .map(|s| s.into_bytes()), IoFormat::TomlPretty => serde_toml::to_string_pretty( &serde_toml::Value::try_from(value).with_kind(crate::ErrorKind::Serialization)?, ) .map(|s| s.into_bytes()) .with_kind(crate::ErrorKind::Serialization), } } /// BLOCKING pub fn from_reader Deserialize<'de>>( &self, mut reader: R, ) -> Result { match self { IoFormat::Json | IoFormat::JsonPretty => { serde_json::from_reader(reader).with_kind(crate::ErrorKind::Deserialization) } IoFormat::Yaml => { serde_yaml::from_reader(reader).with_kind(crate::ErrorKind::Deserialization) } IoFormat::Cbor => { serde_cbor::de::from_reader(reader).with_kind(crate::ErrorKind::Deserialization) } IoFormat::Toml | IoFormat::TomlPretty => { let mut s = String::new(); reader .read_to_string(&mut s) .with_kind(crate::ErrorKind::Deserialization)?; serde_toml::from_str(&s).with_kind(crate::ErrorKind::Deserialization) } } } pub async fn from_async_reader< R: tokio::io::AsyncRead + Unpin, T: for<'de> Deserialize<'de>, >( &self, reader: R, ) -> Result { use crate::util::io::*; match self { IoFormat::Json | IoFormat::JsonPretty => from_json_async_reader(reader).await, IoFormat::Yaml => from_yaml_async_reader(reader).await, IoFormat::Cbor => from_cbor_async_reader(reader).await, IoFormat::Toml | IoFormat::TomlPretty => from_toml_async_reader(reader).await, } } pub fn from_slice Deserialize<'de>>(&self, slice: &[u8]) -> Result { match self { IoFormat::Json | IoFormat::JsonPretty => { serde_json::from_slice(slice).with_kind(crate::ErrorKind::Deserialization) } IoFormat::Yaml => { serde_yaml::from_slice(slice).with_kind(crate::ErrorKind::Deserialization) } IoFormat::Cbor => { serde_cbor::de::from_reader(slice).with_kind(crate::ErrorKind::Deserialization) } IoFormat::Toml | IoFormat::TomlPretty => { serde_toml::from_str(std::str::from_utf8(slice)?) .with_kind(crate::ErrorKind::Deserialization) } } } } pub fn display_serializable(format: IoFormat, result: T) -> Result<(), Error> { format.to_writer(std::io::stdout(), &result)?; if format == IoFormat::JsonPretty { println!() } Ok(()) } #[derive(Deserialize, Serialize)] pub struct WithIoFormat { pub format: Option, #[serde(flatten)] pub rest: T, } impl FromArgMatches for WithIoFormat { fn from_arg_matches(matches: &ArgMatches) -> Result { Ok(Self { rest: T::from_arg_matches(matches)?, format: matches.get_one("format").copied(), }) } fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), clap::Error> { self.rest.update_from_arg_matches(matches)?; self.format = matches.get_one("format").copied(); Ok(()) } } impl CommandFactory for WithIoFormat { fn command() -> clap::Command { let cmd = T::command(); if !cmd.get_arguments().any(|a| a.get_id() == "format") { cmd.arg( clap::Arg::new("format") .long("format") .value_parser(|s: &str| s.parse::().map_err(|e| eyre!("{e}"))), ) } else { cmd } } fn command_for_update() -> clap::Command { let cmd = T::command_for_update(); if !cmd.get_arguments().any(|a| a.get_id() == "format") { cmd.arg( clap::Arg::new("format") .long("format") .value_parser(|s: &str| s.parse::().map_err(|e| eyre!("{e}"))), ) } else { cmd } } } pub trait HandlerExtSerde: HandlerFor { fn with_display_serializable(self) -> DisplaySerializable; } impl, C: Context> HandlerExtSerde for T { fn with_display_serializable(self) -> DisplaySerializable { DisplaySerializable(self) } } #[derive(Debug, Clone)] pub struct DisplaySerializable(pub T); impl HandlerTypes for DisplaySerializable { type Params = WithIoFormat; type InheritedParams = T::InheritedParams; type Ok = T::Ok; type Err = T::Err; } impl, C: Context> HandlerFor for DisplaySerializable { fn handle_sync( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { self.0.handle_sync(HandlerArgs { context, parent_method, method, params: params.rest, inherited_params, raw_params, }) } async fn handle_async( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { self.0 .handle_async(HandlerArgs { context, parent_method, method, params: params.rest, inherited_params, raw_params, }) .await } fn metadata(&self, method: VecDeque<&'static str>) -> OrdMap<&'static str, imbl_value::Value> { self.0.metadata(method) } fn method_from_dots(&self, method: &str) -> Option> { self.0.method_from_dots(method) } } impl PrintCliResult for DisplaySerializable where T::Ok: Serialize, Self::Err: From, { fn print( &self, HandlerArgs { params, .. }: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { display_serializable(params.format.unwrap_or_default(), result)?; Ok(()) } } impl CliBindings for DisplaySerializable where Context: crate::Context, Self: HandlerTypes, Self::Params: CommandFactory + FromArgMatches + Serialize, Self: PrintCliResult, { fn cli_command(&self) -> clap::Command { Self::Params::command() } fn cli_parse( &self, matches: &clap::ArgMatches, ) -> Result<(VecDeque<&'static str>, patch_db::Value), clap::Error> { Self::Params::from_arg_matches(matches).and_then(|a| { Ok(( VecDeque::new(), imbl_value::to_value(&a) .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?, )) }) } fn cli_display( &self, handle_args: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { self.print(handle_args, result) } } #[derive(Deserialize, Serialize, TS, Clone)] pub struct StdinDeserializable(pub T); impl Default for StdinDeserializable where T: Default, { fn default() -> Self { Self(T::default()) } } impl FromArgMatches for StdinDeserializable where T: DeserializeOwned, { fn from_arg_matches(matches: &ArgMatches) -> Result { let format = matches .get_one::("format") .copied() .unwrap_or_default(); Ok(Self(format.from_reader(&mut std::io::stdin()).map_err( |e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e), )?)) } fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), clap::Error> { let format = matches .get_one::("format") .copied() .unwrap_or_default(); self.0 = format .from_reader(&mut std::io::stdin()) .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?; Ok(()) } } impl clap::Args for StdinDeserializable where T: DeserializeOwned, { fn augment_args(cmd: clap::Command) -> clap::Command { if !cmd.get_arguments().any(|a| a.get_id() == "format") { cmd.arg( clap::Arg::new("format") .long("format") .value_parser(|s: &str| s.parse::().map_err(|e| eyre!("{e}"))), ) } else { cmd } } fn augment_args_for_update(cmd: clap::Command) -> clap::Command { if !cmd.get_arguments().any(|a| a.get_id() == "format") { cmd.arg( clap::Arg::new("format") .long("format") .value_parser(|s: &str| s.parse::().map_err(|e| eyre!("{e}"))), ) } else { cmd } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TS)] #[ts(export, type = "string")] pub struct Duration(std::time::Duration); impl Deref for Duration { type Target = std::time::Duration; fn deref(&self) -> &Self::Target { &self.0 } } impl From for Duration { fn from(t: std::time::Duration) -> Self { Duration(t) } } impl std::str::FromStr for Duration { type Err = Error; fn from_str(s: &str) -> Result { let units_idx = s.find(|c: char| c.is_alphabetic()).ok_or_else(|| { Error::new( eyre!("{}", t!("util.serde.must-specify-units-for-duration")), crate::ErrorKind::Deserialization, ) })?; let (num, units) = s.split_at(units_idx); use std::time::Duration; Ok(Duration(match units { "d" if num.contains(".") => Duration::from_secs_f64(num.parse::()? * 86_400_f64), "d" => Duration::from_secs(num.parse::()? * 86_400), "h" if num.contains(".") => Duration::from_secs_f64(num.parse::()? * 3_600_f64), "h" => Duration::from_secs(num.parse::()? * 3_600), "m" if num.contains(".") => Duration::from_secs_f64(num.parse::()? * 60_f64), "m" => Duration::from_secs(num.parse::()? * 60), "s" if num.contains(".") => Duration::from_secs_f64(num.parse()?), "s" => Duration::from_secs(num.parse()?), "ms" if num.contains(".") => Duration::from_secs_f64(num.parse::()? / 1_000_f64), "ms" => { let millis: u128 = num.parse()?; Duration::new((millis / 1_000) as u64, (millis % 1_000) as u32) } "us" | "µs" if num.contains(".") => { Duration::from_secs_f64(num.parse::()? / 1_000_000_f64) } "us" | "µs" => { let micros: u128 = num.parse()?; Duration::new((micros / 1_000_000) as u64, (micros % 1_000_000) as u32) } "ns" if num.contains(".") => { Duration::from_secs_f64(num.parse::()? / 1_000_000_000_f64) } "ns" => { let nanos: u128 = num.parse()?; Duration::new( (nanos / 1_000_000_000) as u64, (nanos % 1_000_000_000) as u32, ) } _ => { return Err(Error::new( eyre!("{}", t!("util.serde.invalid-units-for-duration")), crate::ErrorKind::Deserialization, )); } })) } } impl ValueParserFactory for Duration { type Parser = FromStrParser; fn value_parser() -> Self::Parser { FromStrParser::new() } } impl std::fmt::Display for Duration { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let nanos = self.as_nanos(); match () { _ if nanos % 86_400_000_000_000 == 0 => write!(f, "{}d", nanos / 86_400_000_000_000), _ if nanos % 3_600_000_000_000 == 0 => write!(f, "{}h", nanos / 3_600_000_000_000), _ if nanos % 60_000_000_000 == 0 => write!(f, "{}m", nanos / 60_000_000_000), _ if nanos % 1_000_000_000 == 0 => write!(f, "{}s", nanos / 1_000_000_000), _ if nanos % 1_000_000 == 0 => write!(f, "{}ms", nanos / 1_000_000), _ if nanos % 1_000 == 0 => write!(f, "{}µs", nanos / 1_000), _ => write!(f, "{}ns", nanos), } } } impl<'de> Deserialize<'de> for Duration { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserialize_from_str(deserializer) } } impl Serialize for Duration { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serialize_display(self, serializer) } } pub fn deserialize_number_permissive< 'de, D: serde::de::Deserializer<'de>, T: FromStr + num::cast::FromPrimitive, E: std::fmt::Display, >( deserializer: D, ) -> std::result::Result { struct Visitor + num::cast::FromPrimitive, E>(std::marker::PhantomData); impl<'de, T: FromStr + num::cast::FromPrimitive, Err: std::fmt::Display> serde::de::Visitor<'de> for Visitor { type Value = T; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "a parsable string") } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { v.parse().map_err(|e| serde::de::Error::custom(e)) } fn visit_f64(self, v: f64) -> Result where E: serde::de::Error, { T::from_f64(v).ok_or_else(|| { serde::de::Error::custom(format!( "{} cannot be represented by the requested type", v )) }) } fn visit_u64(self, v: u64) -> Result where E: serde::de::Error, { T::from_u64(v).ok_or_else(|| { serde::de::Error::custom(format!( "{} cannot be represented by the requested type", v )) }) } fn visit_i64(self, v: i64) -> Result where E: serde::de::Error, { T::from_i64(v).ok_or_else(|| { serde::de::Error::custom(format!( "{} cannot be represented by the requested type", v )) }) } } deserializer.deserialize_str(Visitor(std::marker::PhantomData)) } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Port(pub u16); impl<'de> Deserialize<'de> for Port { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { //TODO: if number, be permissive deserialize_number_permissive(deserializer).map(Port) } } impl Serialize for Port { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serialize_display(&self.0, serializer) } } #[derive(Debug, Clone)] pub struct Reversible> where for<'a> &'a Container: IntoDoubleEndedIterator<&'a T>, { reversed: bool, data: Container, phantom: PhantomData, } impl Reversible where for<'a> &'a Container: IntoDoubleEndedIterator<&'a T>, { pub fn new(data: Container) -> Self { Reversible { reversed: false, data, phantom: PhantomData, } } pub fn reverse(&mut self) { self.reversed = !self.reversed } pub fn iter( &self, ) -> itertools::Either< <&Container as IntoDoubleEndedIterator<&T>>::IntoIter, std::iter::Rev<<&Container as IntoDoubleEndedIterator<&T>>::IntoIter>, > { let iter = IntoDoubleEndedIterator::into_iter(&self.data); if self.reversed { itertools::Either::Right(iter.rev()) } else { itertools::Either::Left(iter) } } } impl Serialize for Reversible where for<'a> &'a Container: IntoDoubleEndedIterator<&'a T>, T: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let iter = IntoDoubleEndedIterator::into_iter(&self.data); let mut seq_ser = serializer.serialize_seq(match iter.size_hint() { (lower, Some(upper)) if lower == upper => Some(upper), _ => None, })?; if self.reversed { for elem in iter.rev() { seq_ser.serialize_element(elem)?; } } else { for elem in iter { seq_ser.serialize_element(elem)?; } } seq_ser.end() } } impl<'de, T, Container> Deserialize<'de> for Reversible where for<'a> &'a Container: IntoDoubleEndedIterator<&'a T>, Container: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Ok(Reversible::new(Deserialize::deserialize(deserializer)?)) } fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> where D: Deserializer<'de>, { Deserialize::deserialize_in_place(deserializer, &mut place.data) } } pub struct KeyVal { pub key: K, pub value: V, } impl Serialize for KeyVal { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut map = serializer.serialize_map(Some(1))?; map.serialize_entry(&self.key, &self.value)?; map.end() } } impl<'de, K: Deserialize<'de>, V: Deserialize<'de>> Deserialize<'de> for KeyVal { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct Visitor(PhantomData<(K, V)>); impl<'de, K: Deserialize<'de>, V: Deserialize<'de>> serde::de::Visitor<'de> for Visitor { type Value = KeyVal; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "A map with a single element") } fn visit_map(self, mut map: A) -> Result where A: serde::de::MapAccess<'de>, { let (key, value) = map .next_entry()? .ok_or_else(|| serde::de::Error::invalid_length(0, &"1"))?; Ok(KeyVal { key, value }) } } deserializer.deserialize_map(Visitor(PhantomData)) } } #[derive(TS)] #[ts(type = "string", concrete(T = Vec))] pub struct Base16(pub T); impl<'de, T: TryFrom>> Deserialize<'de> for Base16 { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; hex::decode(&s) .map_err(|_| { serde::de::Error::invalid_value( serde::de::Unexpected::Str(&s), &"a valid hex string", ) })? .try_into() .map_err(|_| serde::de::Error::custom("invalid length")) .map(Self) } } impl> Serialize for Base16 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(&hex::encode(self.0.as_ref())) } } impl> std::fmt::Display for Base16 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { hex::encode(self.0.as_ref()).fmt(f) } } #[derive(TS)] #[ts(type = "string", concrete(T = Vec))] pub struct Base32(pub T); impl> Base32 { pub fn to_lower_string(&self) -> String { base32::encode( base32::Alphabet::Rfc4648Lower { padding: false }, self.0.as_ref(), ) } } impl> std::fmt::Display for Base32 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { base32::encode( base32::Alphabet::Rfc4648 { padding: false }, self.0.as_ref(), ) .fmt(f) } } impl>> FromStr for Base32 { type Err = color_eyre::eyre::Report; fn from_str(s: &str) -> Result { base32::decode(base32::Alphabet::Rfc4648 { padding: false }, &s) .ok_or_else(|| eyre!("{s} is not a valid base32 string"))? .try_into() .map_err(|_| eyre!("base32 string is an invalid length")) .map(Self) } } impl<'de, T: TryFrom>> Deserialize<'de> for Base32 { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserialize_from_str(deserializer) } } impl> Serialize for Base32 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serialize_display(self, serializer) } } pub const BASE64: base64::engine::GeneralPurpose = base64::engine::general_purpose::GeneralPurpose::new( &base64::alphabet::STANDARD, base64::engine::GeneralPurposeConfig::new() .with_encode_padding(false) .with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent), ); #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, TS)] #[ts(type = "string", concrete(T = Vec))] pub struct Base64(pub T); impl> Base64 { pub fn to_padded_string(&self) -> String { base64::engine::general_purpose::STANDARD.encode(self.0.as_ref()) } } impl> std::fmt::Display for Base64 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&BASE64.encode(self.0.as_ref())) } } impl>> FromStr for Base64 { type Err = Error; fn from_str(s: &str) -> Result { BASE64 .decode(&s) .with_kind(ErrorKind::Deserialization)? .apply(TryFrom::try_from) .map(Self) .map_err(|_| { Error::new( eyre!("{}", t!("util.serde.failed-to-create-from-buffer")), ErrorKind::Deserialization, ) }) } } impl>> ValueParserFactory for Base64 { type Parser = FromStrParser; fn value_parser() -> Self::Parser { Self::Parser::new() } } impl<'de, T> Deserialize<'de> for Base64 where Base64: FromStr, as FromStr>::Err: std::fmt::Display, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserialize_from_str(deserializer) } } impl> Serialize for Base64 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serialize_display(self, serializer) } } impl Deref for Base64 { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Clone, Debug)] pub struct Regex(regex::Regex); impl From for regex::Regex { fn from(value: Regex) -> Self { value.0 } } impl From for Regex { fn from(value: regex::Regex) -> Self { Regex(value) } } impl AsRef for Regex { fn as_ref(&self) -> ®ex::Regex { &self.0 } } impl AsMut for Regex { fn as_mut(&mut self) -> &mut regex::Regex { &mut self.0 } } impl<'de> Deserialize<'de> for Regex { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserialize_from_str(deserializer).map(Self) } } impl Serialize for Regex { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serialize_display(&self.0, serializer) } } impl PartialEq for Regex { fn eq(&self, other: &Self) -> bool { InternedString::from_display(self.as_ref()) == InternedString::from_display(other.as_ref()) } } // TODO: make this not allocate #[derive(Debug)] pub struct NoOutput; impl<'de> Deserialize<'de> for NoOutput { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let _ = Value::deserialize(deserializer); Ok(NoOutput) } } pub fn apply_expr(input: jaq_core::Val, expr: &str) -> Result { let (expr, errs) = jaq_core::parse::parse(expr, jaq_core::parse::main()); let Some(expr) = expr else { return Err(Error::new( eyre!( "{}", t!( "util.serde.failed-to-parse-expression", errors = format!("{:?}", errs) ) ), crate::ErrorKind::InvalidRequest, )); }; let mut errs = Vec::new(); let mut defs = jaq_core::Definitions::core(); for def in jaq_std::std() { defs.insert(def, &mut errs); } let filter = defs.finish(expr, Vec::new(), &mut errs); if !errs.is_empty() { return Err(Error::new( eyre!( "{}", t!( "util.serde.failed-to-compile-expression", errors = format!("{:?}", errs) ) ), crate::ErrorKind::InvalidRequest, )); }; let inputs = jaq_core::RcIter::new(std::iter::empty()); let mut res_iter = filter.run(jaq_core::Ctx::new([], &inputs), input); let Some(res) = res_iter .next() .transpose() .map_err(|e| eyre!("{e}")) .with_kind(crate::ErrorKind::Deserialization)? else { return Err(Error::new( eyre!("{}", t!("util.serde.expr-returned-no-results")), crate::ErrorKind::InvalidRequest, )); }; if res_iter.next().is_some() { return Err(Error::new( eyre!("{}", t!("util.serde.expr-returned-too-many-results")), crate::ErrorKind::InvalidRequest, )); } Ok(res) } pub trait PemEncoding: Sized { fn from_pem(pem: &str) -> Result; fn to_pem(&self) -> Result; } impl PemEncoding for X509 { fn from_pem(pem: &str) -> Result { Self::from_pem(pem.as_bytes()).map_err(E::custom) } fn to_pem(&self) -> Result { String::from_utf8((&**self).to_pem().map_err(E::custom)?).map_err(E::custom) } } impl PemEncoding for Vec { fn from_pem(pem: &str) -> Result { X509::stack_from_pem(pem.as_bytes()).map_err(E::custom) } fn to_pem(&self) -> Result { self.iter() .map(|x| x.to_pem()) .try_fold(String::new(), |mut acc, x| { acc.push_str(&x?); acc.push_str("\n"); Ok(acc) }) } } impl PemEncoding for PKey { fn from_pem(pem: &str) -> Result { Self::private_key_from_pem(pem.as_bytes()).map_err(E::custom) } fn to_pem(&self) -> Result { String::from_utf8((&**self).private_key_to_pem_pkcs8().map_err(E::custom)?) .map_err(E::custom) } } impl PemEncoding for ssh_key::PrivateKey { fn from_pem(pem: &str) -> Result { Self::from_openssh(pem.as_bytes()).map_err(E::custom) } fn to_pem(&self) -> Result { self.to_openssh(ssh_key::LineEnding::LF) .map_err(E::custom) .map(|s| (&*s).clone()) } } impl PemEncoding for ed25519_dalek::VerifyingKey { fn from_pem(pem: &str) -> Result { use ed25519_dalek::pkcs8::DecodePublicKey; Self::from_public_key_pem(pem).map_err(E::custom) } fn to_pem(&self) -> Result { use ed25519_dalek::pkcs8::EncodePublicKey; self.to_public_key_pem(pkcs8::LineEnding::LF) .map_err(E::custom) } } impl PemEncoding for ed25519_dalek::SigningKey { fn from_pem(pem: &str) -> Result { use ed25519_dalek::pkcs8::DecodePrivateKey; Self::from_pkcs8_pem(pem).map_err(E::custom) } fn to_pem(&self) -> Result { use ed25519_dalek::pkcs8::EncodePrivateKey; self.to_pkcs8_pem(pkcs8::LineEnding::LF) .map_err(E::custom) .map(|s| s.as_str().to_owned()) } } #[derive(Clone, Debug)] pub struct Pkcs8Doc { pub tag: String, pub document: pkcs8::Document, } impl PemEncoding for Pkcs8Doc { fn from_pem(pem: &str) -> Result { let (tag, document) = pkcs8::Document::from_pem(pem).map_err(E::custom)?; Ok(Pkcs8Doc { tag: tag.into(), document, }) } fn to_pem(&self) -> Result { der::pem::encode_string( &self.tag, pkcs8::LineEnding::default(), self.document.as_bytes(), ) .map_err(E::custom) } } pub mod pem { use serde::{Deserialize, Deserializer, Serializer}; use crate::util::serde::PemEncoding; pub fn serialize( value: &T, serializer: S, ) -> Result { serializer.serialize_str(&value.to_pem()?) } pub fn deserialize<'de, T: PemEncoding, D: Deserializer<'de>>( deserializer: D, ) -> Result { let pem = String::deserialize(deserializer)?; Ok(T::from_pem(&pem)?) } } #[repr(transparent)] #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash, TS)] #[ts(type = "string", concrete(T = ed25519_dalek::VerifyingKey))] pub struct Pem(#[serde(with = "pem")] pub T); impl Pem { pub fn new(value: T) -> Self { Pem(value) } pub fn new_ref(value: &T) -> &Self { unsafe { std::mem::transmute(value) } } pub fn new_mut(value: &mut T) -> &mut Self { unsafe { std::mem::transmute(value) } } } impl Deref for Pem { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } impl std::fmt::Display for Pem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.to_pem::() .map_err(|_| std::fmt::Error::default())? .fmt(f) } } impl FromStr for Pem { type Err = Error; fn from_str(s: &str) -> Result { Ok(Self( T::from_pem::(s).with_kind(ErrorKind::Pem)?, )) } } impl ValueParserFactory for Pem { type Parser = FromStrParser; fn value_parser() -> Self::Parser { Self::Parser::new() } } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, TS)] #[ts(export, type = "string | number[]")] pub struct MaybeUtf8String(pub Vec); impl std::fmt::Debug for MaybeUtf8String { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Ok(s) = std::str::from_utf8(&self.0) { s.fmt(f) } else { self.0.fmt(f) } } } impl<'de> Deserialize<'de> for MaybeUtf8String { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct Visitor; impl<'de> serde::de::Visitor<'de> for Visitor { type Value = Vec; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "a string or byte array") } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { Ok(v.as_bytes().to_owned()) } fn visit_string(self, v: String) -> Result where E: serde::de::Error, { Ok(v.into_bytes()) } fn visit_bytes(self, v: &[u8]) -> Result where E: serde::de::Error, { Ok(v.to_owned()) } fn visit_byte_buf(self, v: Vec) -> Result where E: serde::de::Error, { Ok(v) } fn visit_unit(self) -> Result where E: serde::de::Error, { Ok(Vec::new()) } fn visit_seq(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, { std::iter::repeat_with(|| seq.next_element::().transpose()) .take_while(|a| a.is_some()) .flatten() .collect::, _>>() } } deserializer.deserialize_any(Visitor).map(Self) } } impl Serialize for MaybeUtf8String { fn serialize(&self, serializer: S) -> Result where S: Serializer, { if let Ok(s) = std::str::from_utf8(&self.0) { serializer.serialize_str(s) } else { serializer.serialize_bytes(&self.0) } } } pub fn is_partial_of(partial: &Value, full: &Value) -> bool { match (partial, full) { (Value::Object(partial), Value::Object(full)) => partial.iter().all(|(k, v)| { if let Some(v_full) = full.get(k) { is_partial_of(v, v_full) } else { // null in partial matches a missing key in full (both represent absence) v.is_null() } }), (Value::Array(partial), Value::Array(full)) => partial .iter() .all(|v| full.iter().any(|v_full| is_partial_of(v, v_full))), (_, _) => partial == full, } } pub fn hash_serializable( value: &T, ) -> Result, Error> { let mut digest = D::new(); value .serialize(HashingSerializer { digest: &mut digest, }) .with_kind(ErrorKind::Serialization)?; Ok(digest.finalize()) }