Skip to main content

rustauth_core/context/
secrets.rs

1use std::fmt;
2
3use crate::crypto::{JweSecretSource, SecretConfig, SecretSource};
4use crate::env::is_production_posture;
5use crate::error::RustAuthError;
6use crate::options::RustAuthOptions;
7
8use super::AuthEnvironment;
9
10pub(super) const DEFAULT_SECRET: &str = "rustauth-secret-123456789012345678901";
11
12#[derive(Clone, PartialEq, Eq)]
13pub enum SecretMaterial {
14    Single(String),
15    Rotating(SecretConfig),
16}
17
18impl fmt::Debug for SecretMaterial {
19    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            Self::Single(_) => formatter
22                .debug_tuple("Single")
23                .field(&"<redacted>")
24                .finish(),
25            Self::Rotating(config) => formatter.debug_tuple("Rotating").field(config).finish(),
26        }
27    }
28}
29
30impl JweSecretSource for SecretMaterial {
31    fn current_jwe_secret(&self) -> Result<String, RustAuthError> {
32        match self {
33            Self::Single(secret) => secret.current_jwe_secret(),
34            Self::Rotating(config) => config.current_jwe_secret(),
35        }
36    }
37
38    fn all_jwe_secrets(&self) -> Result<Vec<crate::crypto::JweSecret>, RustAuthError> {
39        match self {
40            Self::Single(secret) => secret.all_jwe_secrets(),
41            Self::Rotating(config) => config.all_jwe_secrets(),
42        }
43    }
44}
45
46impl SecretSource for &SecretMaterial {
47    fn encrypt_current(&self, data: &str) -> Result<String, RustAuthError> {
48        match self {
49            SecretMaterial::Single(secret) => secret.encrypt_current(data),
50            SecretMaterial::Rotating(config) => config.encrypt_current(data),
51        }
52    }
53
54    fn decrypt_payload(&self, data: &str) -> Result<String, RustAuthError> {
55        match self {
56            SecretMaterial::Single(secret) => secret.decrypt_payload(data),
57            SecretMaterial::Rotating(config) => config.decrypt_payload(data),
58        }
59    }
60}
61
62pub(super) fn resolve_legacy_secret(
63    options: &RustAuthOptions,
64    environment: &AuthEnvironment,
65) -> Option<String> {
66    options
67        .secret
68        .clone()
69        .or_else(|| environment.rustauth_secret.clone())
70}
71
72pub(super) fn validate_secret(
73    secret: &str,
74    options: &RustAuthOptions,
75) -> Result<(), RustAuthError> {
76    if secret.is_empty() {
77        return Err(RustAuthError::InvalidConfig(
78            "RustAuth secret is missing".to_owned(),
79        ));
80    }
81    if is_production_posture(options) && secret == DEFAULT_SECRET {
82        return Err(RustAuthError::InvalidConfig(
83            "default secret cannot be used in production".to_owned(),
84        ));
85    }
86    Ok(())
87}