modo/auth/session/
token.rs1use sha2::{Digest, Sha256};
2use std::fmt;
3
4#[derive(Clone, PartialEq, Eq, Hash)]
13pub struct SessionToken([u8; 32]);
14
15impl SessionToken {
16 pub fn generate() -> Self {
18 let mut bytes = [0u8; 32];
19 rand::fill(&mut bytes);
20 Self(bytes)
21 }
22
23 pub fn from_hex(s: &str) -> Result<Self, &'static str> {
30 if s.len() != 64 {
31 return Err("token must be 64 hex characters");
32 }
33 let mut bytes = [0u8; 32];
34 for (i, chunk) in s.as_bytes().chunks(2).enumerate() {
35 let hi = hex_digit(chunk[0]).ok_or("invalid hex character")?;
36 let lo = hex_digit(chunk[1]).ok_or("invalid hex character")?;
37 bytes[i] = (hi << 4) | lo;
38 }
39 Ok(Self(bytes))
40 }
41
42 pub fn as_hex(&self) -> String {
46 crate::encoding::hex::encode(&self.0)
47 }
48
49 pub fn hash(&self) -> String {
56 let digest = Sha256::digest(self.0);
57 crate::encoding::hex::encode(&digest)
58 }
59}
60
61impl fmt::Debug for SessionToken {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 write!(f, "SessionToken(****)")
64 }
65}
66
67impl fmt::Display for SessionToken {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 f.write_str("****")
70 }
71}
72
73fn hex_digit(b: u8) -> Option<u8> {
74 match b {
75 b'0'..=b'9' => Some(b - b'0'),
76 b'a'..=b'f' => Some(b - b'a' + 10),
77 b'A'..=b'F' => Some(b - b'A' + 10),
78 _ => None,
79 }
80}