1
use server::config::{ConfigError, config};
2

            
3
fn get_env_var(var_name: &str) -> String {
4
    std::env::var(var_name).unwrap_or_else(|_| panic!("{var_name} must be set"))
5
}
6

            
7
/// Public-facing SSH endpoint advertised in the
8
/// `/account/ssh-key` "key added" snippet. All three values are
9
/// optional — operators set them via env (`SSH_HOSTNAME`,
10
/// `SSH_PORT`, `SSH_HOST_FINGERPRINT`) on the deployment ConfigMap.
11
#[derive(Debug, Clone)]
12
pub struct SshConnectInfo {
13
    pub hostname: String,
14
    pub port: u16,
15
    pub host_fingerprint: String,
16
}
17

            
18
impl SshConnectInfo {
19
    fn from_env() -> Self {
20
        Self {
21
            hostname: std::env::var("SSH_HOSTNAME")
22
                .unwrap_or_else(|_| "ssh.example.invalid".to_string()),
23
            port: std::env::var("SSH_PORT")
24
                .ok()
25
                .and_then(|raw| raw.parse::<u16>().ok())
26
                .unwrap_or(2222),
27
            host_fingerprint: std::env::var("SSH_HOST_FINGERPRINT")
28
                .unwrap_or_else(|_| "(not configured)".to_string()),
29
        }
30
    }
31
}
32

            
33
#[derive(Debug, Clone)]
34
pub struct Config {
35
    pub site_url: String,
36

            
37
    pub redis_url: String,
38
    pub client_origin: String,
39

            
40
    pub access_token_private_key: String,
41
    pub access_token_public_key: String,
42
    pub access_token_expires_in: String,
43
    pub access_token_max_age: i64,
44

            
45
    pub refresh_token_private_key: String,
46
    pub refresh_token_public_key: String,
47
    pub refresh_token_expires_in: String,
48
    pub refresh_token_max_age: i64,
49

            
50
    pub ssh: SshConnectInfo,
51
}
52

            
53
impl Config {
54
    pub async fn init() -> Result<Config, ConfigError> {
55
        let site_url = config("site_url")
56
            .await?
57
            .ok_or(ConfigError::NoConfig("site_url".to_string()))?
58
            .to_string();
59

            
60
        let client_origin = config("client_origin")
61
            .await?
62
            .ok_or(ConfigError::NoConfig("client_origin".to_string()))?
63
            .to_string();
64

            
65
        let redis_url = config("redis_url")
66
            .await?
67
            .ok_or(ConfigError::NoConfig("redis_url".to_string()))?
68
            .to_string();
69

            
70
        let access_token_private_key = config("access_token_private_key")
71
            .await?
72
            .ok_or(ConfigError::NoConfig(
73
                "access_token_private_key".to_string(),
74
            ))?
75
            .to_string();
76

            
77
        let access_token_public_key = config("access_token_public_key")
78
            .await?
79
            .ok_or(ConfigError::NoConfig("access_token_public_key".to_string()))?
80
            .to_string();
81

            
82
        let access_token_expires_in = config("access_token_expired_in")
83
            .await?
84
            .ok_or(ConfigError::NoConfig("access_token_expired_in".to_string()))?
85
            .to_string();
86

            
87
        let access_token_max_age = config("access_token_maxage")
88
            .await?
89
            .ok_or(ConfigError::NoConfig("access_token_maxage".to_string()))?
90
            .to_string();
91

            
92
        let refresh_token_private_key = config("refresh_token_private_key")
93
            .await?
94
            .ok_or(ConfigError::NoConfig(
95
                "refresh_token_private_key".to_string(),
96
            ))?
97
            .to_string();
98

            
99
        let refresh_token_public_key = config("refresh_token_public_key")
100
            .await?
101
            .ok_or(ConfigError::NoConfig(
102
                "refresh_token_public_key".to_string(),
103
            ))?
104
            .to_string();
105

            
106
        let refresh_token_expires_in = config("refresh_token_expired_in")
107
            .await?
108
            .ok_or(ConfigError::NoConfig(
109
                "refresh_token_expired_in".to_string(),
110
            ))?
111
            .to_string();
112

            
113
        let refresh_token_max_age = config("refresh_token_maxage")
114
            .await?
115
            .ok_or(ConfigError::NoConfig("refresh_token_maxage".to_string()))?
116
            .to_string();
117

            
118
        Ok(Config {
119
            site_url,
120
            redis_url,
121
            client_origin,
122
            access_token_private_key,
123
            access_token_public_key,
124
            refresh_token_private_key,
125
            refresh_token_public_key,
126
            access_token_expires_in,
127
            refresh_token_expires_in,
128
            access_token_max_age: access_token_max_age.parse::<i64>().unwrap(),
129
            refresh_token_max_age: refresh_token_max_age.parse::<i64>().unwrap(),
130
            ssh: SshConnectInfo::from_env(),
131
        })
132
    }
133
}