rustauth_core/context/
secrets.rs1use 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}