headless_lms_models/library/oauth/
tokens.rs1use hmac::{Hmac, KeyInit, Mac};
2use rand::RngExt;
3use rand::distr::SampleString;
4use rand::rng;
5use secrecy::{ExposeSecret, SecretString};
6use sha2::Sha256;
7
8use crate::library::oauth::Digest;
9
10const ACCESS_TOKEN_LENGTH: usize = 64;
11
12const USER_CODE_ALPHABET: &[u8] = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ";
14const USER_CODE_GROUP_LEN: usize = 4;
16
17pub fn generate_access_token() -> String {
19 rand::distr::Alphanumeric.sample_string(&mut rng(), ACCESS_TOKEN_LENGTH)
20}
21
22pub fn generate_user_code() -> String {
30 let mut rng = rng();
31 let mut code = String::with_capacity(USER_CODE_GROUP_LEN * 2 + 1);
32 for i in 0..(USER_CODE_GROUP_LEN * 2) {
33 if i == USER_CODE_GROUP_LEN {
34 code.push('-');
35 }
36 let idx = rng.random_range(0..USER_CODE_ALPHABET.len());
37 code.push(USER_CODE_ALPHABET[idx] as char);
38 }
39 code
40}
41
42pub fn token_digest_sha256(token_plaintext: &str, key: &SecretString) -> Digest {
51 let mut mac = Hmac::<Sha256>::new_from_slice(key.expose_secret().as_bytes())
53 .expect("HMAC can take key of any size");
54 mac.update(token_plaintext.as_bytes());
55 let result = mac.finalize();
56 let code_bytes = result.into_bytes();
57 let mut arr = [0u8; Digest::LEN];
58 arr.copy_from_slice(&code_bytes);
59 Digest::new(arr)
60}