Skip to main content

shared/utils/crypto/
secure_token.rs

1use crate::error::{CoreError, InternalError, Result};
2use base64::{Engine, prelude::BASE64_URL_SAFE_NO_PAD};
3use rand::TryRngCore;
4use sha2::{Digest, Sha256};
5
6#[derive(Clone)]
7pub struct SecureToken {
8    size: usize,
9}
10
11impl Default for SecureToken {
12    fn default() -> Self {
13        Self::with_size32()
14    }
15}
16
17impl SecureToken {
18    pub fn with_size32() -> Self {
19        Self { size: 32 }
20    }
21    pub fn with_size64() -> Self {
22        Self { size: 64 }
23    }
24}
25
26impl SecureToken {
27    pub fn generate(&self) -> Result<String> {
28        let mut bytes = vec![0u8; self.size];
29
30        rand::rngs::OsRng
31            .try_fill_bytes(&mut bytes)
32            .map_err(|_| CoreError::Internal(InternalError::Hashing))?;
33
34        Ok(BASE64_URL_SAFE_NO_PAD.encode(&bytes))
35    }
36    pub fn hash(&self, token: &str) -> String {
37        let mut hasher = Sha256::new();
38        hasher.update(token.as_bytes());
39
40        format!("{:x}", hasher.finalize())
41    }
42
43    pub fn verify(&self, a: &str, b: &str) -> bool {
44        if a.len() != b.len() {
45            return false;
46        }
47
48        a.bytes()
49            .zip(b.bytes())
50            .fold(0, |acc, (a, b)| acc | (a ^ b))
51            == 0
52    }
53}