use std::io;
use chrono::prelude::*;
use hex::{self, FromHex, FromHexError};
use serde::Deserialize;
use crate::crypto::pwhash;
use crate::{box_, secretbox};
pub trait MyTryFromBytes: Sized {
type Err: 'static + Sized + ::std::error::Error;
fn try_from(_: &[u8]) -> Result<Self, Self::Err>;
}
impl MyTryFromBytes for box_::PublicKey {
type Err = io::Error;
fn try_from(slice: &[u8]) -> Result<Self, Self::Err> {
box_::PublicKey::from_slice(slice).ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"can't derive PublicKey from invalid binary data",
)
})
}
}
impl MyTryFromBytes for secretbox::Nonce {
type Err = io::Error;
fn try_from(slice: &[u8]) -> Result<Self, Self::Err> {
secretbox::Nonce::from_slice(slice).ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"can't derive Nonce from invalid binary data",
)
})
}
}
impl MyTryFromBytes for pwhash::Salt {
type Err = io::Error;
fn try_from(slice: &[u8]) -> Result<Self, Self::Err> {
pwhash::Salt::from_slice(slice).ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"can't derive Nonce from invalid binary data",
)
})
}
}
impl MyTryFromBytes for Vec<u8> {
type Err = io::Error;
fn try_from(slice: &[u8]) -> Result<Self, Self::Err> {
Ok(Vec::from(slice))
}
}
pub fn from_base64<'d, T, D>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'d>,
T: MyTryFromBytes,
{
use serde::de::Error;
String::deserialize(deserializer)
.and_then(|string| {
base64::decode(&string)
.map_err(|err| Error::custom(err.to_string()))
})
.and_then(|ref bytes| {
T::try_from(bytes).map_err(|err| {
Error::custom(format!("{}", &err as &dyn (::std::error::Error)))
})
})
}
pub fn as_base64<T, S>(key: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: AsRef<[u8]>,
S: serde::Serializer,
{
serializer.serialize_str(&base64::encode(key.as_ref()))
}
pub fn from_hex<'d, T, D>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'d>,
T: MyTryFromBytes,
{
use serde::de::Error;
String::deserialize(deserializer)
.and_then(|string| {
FromHex::from_hex(string.as_str())
.map_err(|err: FromHexError| Error::custom(err.to_string()))
})
.and_then(|bytes: Vec<u8>| {
T::try_from(&bytes).map_err(|err| {
Error::custom(format!("{}", &err as &dyn (::std::error::Error)))
})
})
}
pub fn as_hex<T, S>(key: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: AsRef<[u8]>,
S: serde::Serializer,
{
serializer.serialize_str(&hex::encode(key))
}
pub fn from_rfc3339<'d, D>(
deserializer: D,
) -> Result<chrono::DateTime<Utc>, D::Error>
where
D: serde::Deserializer<'d>,
{
use serde::de::Error;
String::deserialize(deserializer)
.and_then(|string| {
DateTime::<FixedOffset>::parse_from_rfc3339(&string)
.map_err(|err| Error::custom(err.to_string()))
})
.map(|dt| dt.with_timezone(&Utc))
}
pub fn as_rfc3339<S>(
key: &chrono::DateTime<Utc>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&key.to_rfc3339())
}