support_kit/encryption/
token_control.rs1use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
2use rand::Rng;
3use secrecy::{ExposeSecret, SecretString};
4
5use crate::{AuthTokenGenerationFailure, AuthTokenVerificationFailure, Configuration, TokenError};
6
7#[derive(serde::Deserialize, serde::Serialize)]
9pub struct TokenContents {
10 pub sub: String,
12 pub exp: usize,
14}
15
16pub struct TokenControl(pub Configuration);
17
18impl TokenControl {
19 pub fn from_config(config: Configuration) -> Self {
20 Self(config)
21 }
22
23 pub fn auth_token(&self, id: uuid::Uuid) -> crate::Result<String> {
24 let secret = self.0.secret.clone();
25
26 Ok(generate_auth_token(&id, &secret)?)
27 }
28
29 pub fn validate_auth_token(&self, token: String) -> crate::Result<uuid::Uuid> {
30 let secret = self.0.secret.clone();
31
32 Ok(validate_auth_token(token, &secret)?)
33 }
34
35 pub fn random(&self) -> String {
36 generate_randomized_token()
37 }
38}
39
40#[tracing::instrument(name = "Generating session auth token", skip(id, secret))]
42pub fn generate_auth_token(id: &uuid::Uuid, secret: &SecretString) -> Result<String, TokenError> {
43 let header = Header {
44 kid: Some(secret.expose_secret().to_owned()),
45 alg: Algorithm::HS512,
46 ..Default::default()
47 };
48
49 let claim = TokenContents {
50 sub: id.to_string(),
51 exp: 10000000000,
52 };
53
54 Ok(encode(
55 &header,
56 &claim,
57 &EncodingKey::from_secret(secret.expose_secret().as_bytes()),
58 )
59 .map_err(AuthTokenGenerationFailure::from)?)
60}
61
62#[tracing::instrument(
64 level = "debug",
65 name = "Validate session auth token",
66 skip(token, secret)
67)]
68pub fn validate_auth_token(token: String, secret: &SecretString) -> Result<uuid::Uuid, TokenError> {
69 let raw_token = decode::<TokenContents>(
70 &token,
71 &DecodingKey::from_secret(secret.expose_secret().as_bytes()),
72 &Validation::new(jsonwebtoken::Algorithm::HS512),
73 )
74 .map_err(AuthTokenVerificationFailure::from)?
75 .claims
76 .sub;
77
78 Ok(uuid::Uuid::parse_str(&raw_token)?)
79}
80
81pub fn generate_randomized_token() -> String {
83 let mut rng = rand::thread_rng();
84
85 std::iter::repeat_with(|| rng.sample(rand::distributions::Alphanumeric))
86 .map(char::from)
87 .take(25)
88 .collect()
89}