//! Used to determine which post belongs to who. //! //! Mostly for determining if a poster owns a post. use super::*; use std::{ net::SocketAddr, }; use cryptohelpers::sha256; /// A user's unique ID. /// /// This is composed by the user's address and their session ID. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct UserID(SocketAddr, session::SessionID); static COUNTER: GlobalCounter = GlobalCounter::new(); impl UserID { /// Generate a token from this instance. /// /// User tokens are deterministically generated and can be deterministically verified. pub fn generate_token(&self) -> u64 { let cnt = COUNTER.get(); let mut trunc = [0u8; std::mem::size_of::()]; let hash = GloballySalted::new(self).compute_sha256_hash(); bytes::move_slice(&mut trunc[..], hash.as_ref()); u64::from_le_bytes(trunc) ^ cnt } /// Validate a token for this instance created with `generate_token`. pub fn validate_token(&self, val: u64) -> bool { let mut trunc = [0u8; std::mem::size_of::()]; let hash = GloballySalted::new(self).compute_sha256_hash(); bytes::move_slice(&mut trunc[..], hash.as_ref()); COUNTER.valid(u64::from_le_bytes(trunc) ^ val) } } /// A user not bound to a session. #[derive(Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct User { addr: SocketAddr, } impl User { /// Get the user ID for this session. pub fn id_for_session(&self, session: &session::Session) -> UserID { UserID(self.addr, session.session_id().clone()) } }