Skip to main content

cedros_data/
config.rs

1use crate::error::{CedrosDataError, Result};
2
3#[derive(Debug, Clone)]
4pub struct CedrosDataConfig {
5    pub postgres_uri: String,
6}
7
8impl CedrosDataConfig {
9    pub fn from_env() -> Result<Self> {
10        let postgres_uri =
11            std::env::var("POSTGRES_URI").map_err(|_| CedrosDataError::MissingPostgresUri)?;
12        Ok(Self { postgres_uri })
13    }
14}
15
16#[cfg(feature = "http")]
17#[derive(Debug, Clone)]
18pub struct HttpServerConfig {
19    pub bind_addr: String,
20    pub cors_allowed_origins: Vec<String>,
21    pub enable_cedros_login_profile: bool,
22    pub cedros_login_verify_url: Option<String>,
23    pub allow_unauthenticated_http: bool,
24}
25
26#[cfg(feature = "http")]
27impl Default for HttpServerConfig {
28    fn default() -> Self {
29        Self {
30            bind_addr: "127.0.0.1:8080".to_string(),
31            cors_allowed_origins: Vec::new(),
32            enable_cedros_login_profile: false,
33            cedros_login_verify_url: None,
34            allow_unauthenticated_http: false,
35        }
36    }
37}
38
39#[cfg(feature = "storage")]
40#[derive(Clone)]
41pub struct StorageConfig {
42    pub access_key: String,
43    pub secret_key: String,
44    pub bucket: String,
45    pub region: String,
46    pub endpoint: Option<String>,
47    pub cdn_base_url: Option<String>,
48    pub path_prefix: Option<String>,
49}
50
51#[cfg(feature = "storage")]
52impl std::fmt::Debug for StorageConfig {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        f.debug_struct("StorageConfig")
55            .field("bucket", &self.bucket)
56            .field("region", &self.region)
57            .field("endpoint", &self.endpoint)
58            .field("access_key", &redact_key(&self.access_key))
59            .field("secret_key", &"[REDACTED]")
60            .finish()
61    }
62}
63
64#[cfg(feature = "storage")]
65impl StorageConfig {
66    pub fn from_env() -> Result<Self> {
67        let access_key = required_env("STORAGE_ACCESS_KEY")?;
68        let secret_key = required_env("STORAGE_SECRET_KEY")?;
69        let bucket = required_env("STORAGE_BUCKET")?;
70        let region = required_env("STORAGE_REGION")?;
71        let endpoint = optional_env("STORAGE_ENDPOINT");
72        let cdn_base_url = optional_env("STORAGE_CDN_BASE_URL");
73        let path_prefix = optional_env("STORAGE_PATH_PREFIX");
74
75        Ok(Self {
76            access_key,
77            secret_key,
78            bucket,
79            region,
80            endpoint,
81            cdn_base_url,
82            path_prefix,
83        })
84    }
85
86    /// Returns a redacted view of the config safe for API responses.
87    pub fn redacted_summary(&self) -> serde_json::Value {
88        serde_json::json!({
89            "bucket": self.bucket,
90            "region": self.region,
91            "endpoint": self.endpoint,
92            "cdn_base_url": self.cdn_base_url,
93            "path_prefix": self.path_prefix,
94            "access_key": redact_key(&self.access_key),
95        })
96    }
97}
98
99#[cfg(feature = "storage")]
100fn required_env(name: &str) -> Result<String> {
101    std::env::var(name).map_err(|_| {
102        CedrosDataError::InvalidRequest(format!("missing required environment variable {name}"))
103    })
104}
105
106#[cfg(feature = "storage")]
107fn optional_env(name: &str) -> Option<String> {
108    std::env::var(name).ok().filter(|v| !v.is_empty())
109}
110
111#[cfg(feature = "storage")]
112fn redact_key(key: &str) -> String {
113    if key.len() <= 6 {
114        return "***".to_string();
115    }
116    format!("{}***{}", &key[..3], &key[key.len() - 3..])
117}