use sha2::{Digest, Sha256}; use std::fmt; /// This represents an instance that write logs. /// Private IDs are only shared with the server when writing logs. #[derive(Clone, PartialEq, Eq)] pub struct PrivateID([u8; SHA256_SIZE]); impl PrivateID { /// Safely generate a new PrivateId for use in Config objects. /// You should persist this across runs of an instance of your app, so that /// it can append to the same log file on each run. pub fn new() -> Self { let mut id: [u8; 32] = rand::random(); id[0] &= 248; id[31] = (id[31] & 127) | 64; Self(id) } /// Parse a PrivateID from its base 16 representation. pub fn from_hex(data: String) -> Result { let mut id: [u8; 32] = [0; 32]; hex::decode_to_slice(data, &mut id)?; Ok(Self(id)) } /// Show a private ID as its base 16 representation. pub fn as_hex(&self) -> String { hex::encode(self.0) } pub fn as_public(&self) -> PublicID { let mut hasher = Sha256::new(); hasher.update(&self.0); PublicID(hasher.finalize().into()) } } impl fmt::Display for PrivateID { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self.as_hex()) } } impl fmt::Debug for PrivateID { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "PrivateID({})", self.as_hex()) } } const SHA256_SIZE: usize = 32; #[derive(Clone, PartialEq, Eq)] pub struct PublicID([u8; SHA256_SIZE]); impl PublicID { /// Parse a PublicID from its base 16 representation. pub fn from_hex(data: String) -> Result { let mut id: [u8; 32] = [0; 32]; hex::decode_to_slice(data, &mut id)?; Ok(Self(id)) } /// Show a public ID as its base 16 representation. pub fn as_hex(&self) -> String { hex::encode(self.0) } } impl fmt::Display for PublicID { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self.as_hex()) } } impl fmt::Debug for PublicID { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "PublicID({})", self.as_hex()) } } #[cfg(test)] mod tests { use super::*; #[test] fn id() { let id = PrivateID::new(); assert_ne!(id.as_hex(), "".to_string()); } #[test] fn encode_decode() { let id = PrivateID::new(); let as_hex = id.as_hex(); let other_id = PrivateID::from_hex(as_hex).unwrap(); assert_eq!(id, other_id); } #[test] fn to_public() { let id = PrivateID::from_hex( "6451f1641112c13e80daa7237d62391b028e638fef9cf91fd7ea347a5290a643".to_string(), ) .unwrap(); let pub_id = id.as_public(); assert_eq!( pub_id, PublicID::from_hex( "db3a35df70555653e5fcff5bbc06e1573ad67e00744b56691c15cde72d17c449".to_string() ) .unwrap() ); } }