use std::fmt::{Debug, Display, Formatter, Pointer}; use std::ops::Deref; use crypto::digest::Digest; use crypto::sha1::Sha1; use serde::{Deserialize, Deserializer}; use serde::de::{Error, Visitor}; use hex::{FromHex, ToHex}; // sha1 digests are 20 bytes long pub const SHA1_DIGEST_BYTES: usize = 20; pub type Sha1DigestBytes = [u8; SHA1_DIGEST_BYTES]; #[derive(PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct Sha1Digest(pub Sha1DigestBytes); impl Debug for Sha1Digest { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "Sha1Digest {{{}}}", self.0.encode_hex::()) } } impl Display for Sha1Digest { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0.encode_hex::()) } } impl Sha1Digest { pub fn verify(&self, s: &str) -> Result<(), Sha1Digest> { let mut st = Sha1::new(); let mut dig = [0u8; SHA1_DIGEST_BYTES]; st.input_str(s); st.result(&mut dig); if self.0 == dig { return Ok(()); } Err(Sha1Digest(dig)) } } struct Sha1DigestVisitor; impl <'a> Visitor<'a> for Sha1DigestVisitor { type Value = Sha1Digest; fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { write!(formatter, "a valid SHA-1 digest (40-character hex string)") } fn visit_str(self, v: &str) -> Result where E: Error, { Sha1DigestBytes::from_hex(v).map_err(|e| E::custom(e)).map(Sha1Digest) } } impl<'a> Deserialize<'a> for Sha1Digest { fn deserialize(deserializer: D) -> Result where D: Deserializer<'a>, { deserializer.deserialize_any(Sha1DigestVisitor) } }