use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::convert::{TryFrom, TryInto}; pub type GroupId = [u8; 16]; pub static ROOT_GROUP_ID: GroupId = [0; 16]; #[derive(Deserialize, Serialize)] pub struct Group { pub name: String, pub parent: GroupId, pub title: String, } #[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize)] pub struct AdId([u8; 16]); impl AdId { pub fn random() -> Self { Self(rand::random()) } } impl AsRef<[u8]> for AdId { fn as_ref(&self) -> &[u8] { &self.0 } } impl TryFrom<&[u8]> for AdId { type Error = std::array::TryFromSliceError; fn try_from(v: &[u8]) -> Result { Ok(Self(v.try_into()?)) } } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Ad { pub author: String, pub password: String, pub price: String, pub pubkey: Option, pub quantity: String, pub time: u64, pub title: String, } #[derive(Clone, Debug, Serialize)] pub struct AdWithId { pub id: String, pub ad: Ad, pub selected: bool, } pub enum PubkeyDecodeError { BadChecksum, BadFormat, } /// Decode pubkey from base 58 /// Verify checksum if provided /// Accepts any checksum length >=3 pub fn format_pubkey(raw: &str) -> Result { let mut iter = raw.splitn(2, ':'); let raw_pubkey = iter.next().ok_or(PubkeyDecodeError::BadFormat)?; if raw_pubkey.len() < 43 || raw_pubkey.len() > 44 { return Err(PubkeyDecodeError::BadFormat); } let mut pubkey = [0u8; 32]; bs58::decode(raw_pubkey) .into(&mut pubkey) .map_err(|_| PubkeyDecodeError::BadFormat)?; let mut hasher1 = Sha256::new(); hasher1.update(&pubkey.as_ref()[..32]); let mut hasher2 = Sha256::new(); hasher2.update(hasher1.finalize()); let checksum = bs58::encode(hasher2.finalize()).into_string(); if let Some(given_checksum) = iter.next() { if given_checksum.len() < 3 { return Err(PubkeyDecodeError::BadFormat); } if !checksum.starts_with(given_checksum) { return Err(PubkeyDecodeError::BadChecksum); } } Ok(format!( "{}:{}", bs58::encode(pubkey).into_string(), &checksum[..3] )) }