208 lines
5.3 KiB
Rust
208 lines
5.3 KiB
Rust
|
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<Self, Vec<Error>>;
|
||
|
}
|
||
|
|
||
|
impl FromValue for Name {
|
||
|
fn from_value(value: Value) -> Result<Self, Vec<Error>> {
|
||
|
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<Self, Vec<Error>> {
|
||
|
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::<IpAddr>().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<Self, Vec<Error>> {
|
||
|
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<Self, Vec<Error>> {
|
||
|
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<T: FromValue> FromValue for Vec<T> {
|
||
|
fn from_value(value: serde_json::Value) -> Result<Self, Vec<Error>> {
|
||
|
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<Self, Vec<Error>> {
|
||
|
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)
|
||
|
}
|
||
|
}
|
||
|
}
|