use std::net::IpAddr; use serde::Serialize; use serde_json::Value; use crate::errors::Error; use crate::macros::{push_error, append_errors, check_type}; use crate::resources::dns::external::rdata::RDataValidationError; use crate::resources::dns::internal::base::{Name, Text}; use crate::validation; #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "lowercase")] pub enum ValueType { Object, Array, String, Number, Null, Bool, } impl ValueType { pub fn from_value(value: &Value) -> ValueType { match value { Value::Array(_) => ValueType::Array, Value::Bool(_) => ValueType::Bool, Value::Null => ValueType::Null, Value::Number(_) => ValueType::Number, Value::Object(_) => ValueType::Object, Value::String(_) => ValueType::String, } } } pub enum InputDataError { TypeError { expected: ValueType, found: ValueType }, MissingValue, } pub trait FromValue: Sized { fn from_value(value: Value) -> Result>; } impl FromValue for Name { fn from_value(value: Value) -> Result> { let mut errors = Vec::new(); let value = check_type!(value, String, errors); if !errors.is_empty() { return Err(errors); } let name = push_error!( validation::normalize_domain(&value.unwrap()), errors ); if errors.is_empty() { Ok(Name::new(name.unwrap())) } else { Err(errors) } } } impl FromValue for IpAddr { fn from_value(value: Value) -> Result> { let mut errors = Vec::new(); let address = check_type!(value, String, errors); let address = if let Some(address) = address { // TODO: replace with custom validation push_error!(address.parse::().map_err(|e| { Error::from(RDataValidationError::IpAddress { input: address }) .with_cause(&e.to_string()) }), errors) } else { None }; if errors.is_empty() { Ok(address.unwrap()) } else { Err(errors) } } } impl FromValue for u32 { fn from_value(value: Value) -> Result> { let mut errors = Vec::new(); let number = check_type!(value, Number, errors); let address = if let Some(number) = number { push_error!( number.as_u64() .ok_or(Error::from(RDataValidationError::Number { min: u32::MIN.into(), max: u32::MAX.into()})) .and_then(|number| { u32::try_from(number).map_err(|e| { Error::from(RDataValidationError::Number { min: u32::MIN.into(), max: u32::MAX.into()}) .with_cause(&e.to_string()) }) }), errors ) } else { None }; if errors.is_empty() { Ok(address.unwrap()) } else { Err(errors) } } } impl FromValue for u16 { fn from_value(value: Value) -> Result> { let mut errors = Vec::new(); let number = check_type!(value, Number, errors); let address = if let Some(number) = number { push_error!( number.as_u64() .ok_or(Error::from(RDataValidationError::Number { min: u16::MIN.into(), max: u16::MAX.into()})) .and_then(|number| { u16::try_from(number).map_err(|e| { Error::from(RDataValidationError::Number { min: u16::MIN.into(), max: u16::MAX.into()}) .with_cause(&e.to_string()) }) }), errors ) } else { None }; if errors.is_empty() { Ok(address.unwrap()) } else { Err(errors) } } } impl FromValue for Vec { fn from_value(value: serde_json::Value) -> Result> { let mut errors = Vec::new(); let array = check_type!(value, Array, errors); if !errors.is_empty() { return Err(errors); } let array = array.unwrap(); let mut list = Vec::new(); for (index, item) in array.into_iter().enumerate() { let res = append_errors!( T::from_value(item), errors, &format!("/{index}") ); if let Some(item) = res { list.push(item); } } if errors.is_empty() { Ok(list) } else { Err(errors) } } } impl FromValue for Text { fn from_value(value: Value) -> Result> { let mut errors = Vec::new(); let data = check_type!(value, String, errors); let data = if let Some(data) = data { append_errors!(validation::parse_txt_data(&data), errors) } else { None }; if errors.is_empty() { Ok(Text ::new(data.unwrap())) } else { Err(errors) } } }