|
| 1 | +use auth_impls::DecodingKey; |
| 2 | +use impls::postgres_store::Certificate; |
1 | 3 | use serde::Deserialize; |
| 4 | +use std::net::SocketAddr; |
2 | 5 |
|
3 | 6 | #[derive(Deserialize)] |
4 | | -pub(crate) struct Config { |
5 | | - pub(crate) server_config: ServerConfig, |
6 | | - pub(crate) postgresql_config: PostgreSQLConfig, |
| 7 | +struct Config { |
| 8 | + server_config: ServerConfig, |
| 9 | + postgresql_config: Option<PostgreSQLConfig>, |
7 | 10 | } |
8 | 11 |
|
9 | 12 | #[derive(Deserialize)] |
10 | | -pub(crate) struct ServerConfig { |
11 | | - pub(crate) host: String, |
12 | | - pub(crate) port: u16, |
13 | | - pub(crate) rsa_pub_file_path: Option<String>, |
| 13 | +struct ServerConfig { |
| 14 | + bind_address: SocketAddr, |
| 15 | + rsa_pub_file_path: Option<String>, |
14 | 16 | } |
15 | 17 |
|
| 18 | +// All fields can be overriden by their corresponding environment variables |
16 | 19 | #[derive(Deserialize)] |
17 | | -pub(crate) struct PostgreSQLConfig { |
18 | | - pub(crate) username: Option<String>, // Optional in TOML, can be overridden by env |
19 | | - pub(crate) password: Option<String>, // Optional in TOML, can be overridden by env |
20 | | - pub(crate) host: String, |
21 | | - pub(crate) port: u16, |
22 | | - pub(crate) default_database: String, |
23 | | - pub(crate) vss_database: String, |
24 | | - pub(crate) tls: Option<TlsConfig>, |
| 20 | +struct PostgreSQLConfig { |
| 21 | + // VSS_POSTGRESQL_USERNAME |
| 22 | + username: Option<String>, |
| 23 | + // VSS_POSTGRESQL_PASSWORD |
| 24 | + password: Option<String>, |
| 25 | + // VSS_POSTGRESQL_ADDRESS |
| 26 | + address: Option<SocketAddr>, |
| 27 | + // VSS_POSTGRESQL_DEFAULT_DATABASE |
| 28 | + default_database: Option<String>, |
| 29 | + // VSS_POSTGRESQL_VSS_DATABASE |
| 30 | + vss_database: Option<String>, |
| 31 | + // Set VSS_POSTGRESQL_TLS=1 for tls: Some(TlsConfig { crt_file_path: None }) |
| 32 | + // Set VSS_POSTGRESQL_CRT_FILE_PATH=ca.crt for tls: Some(TlsConfig { crt_file_path: String::from("ca.crt") }) |
| 33 | + tls: Option<TlsConfig>, |
25 | 34 | } |
26 | 35 |
|
27 | 36 | #[derive(Deserialize)] |
28 | | -pub(crate) struct TlsConfig { |
29 | | - pub(crate) ca_file: Option<String>, |
| 37 | +struct TlsConfig { |
| 38 | + crt_file_path: Option<String>, |
30 | 39 | } |
31 | 40 |
|
32 | | -impl PostgreSQLConfig { |
33 | | - pub(crate) fn to_postgresql_endpoint(&self) -> String { |
34 | | - let username_env = std::env::var("VSS_POSTGRESQL_USERNAME"); |
35 | | - let username = username_env.as_ref() |
36 | | - .ok() |
37 | | - .or_else(|| self.username.as_ref()) |
38 | | - .expect("PostgreSQL database username must be provided in config or env var VSS_POSTGRESQL_USERNAME must be set."); |
39 | | - let password_env = std::env::var("VSS_POSTGRESQL_PASSWORD"); |
40 | | - let password = password_env.as_ref() |
41 | | - .ok() |
42 | | - .or_else(|| self.password.as_ref()) |
43 | | - .expect("PostgreSQL database password must be provided in config or env var VSS_POSTGRESQL_PASSWORD must be set."); |
44 | | - |
45 | | - format!("postgresql://{}:{}@{}:{}", username, password, self.host, self.port) |
46 | | - } |
| 41 | +pub(crate) struct Configuration { |
| 42 | + pub(crate) bind_address: SocketAddr, |
| 43 | + pub(crate) jwt_rsa_public_key: Option<DecodingKey>, |
| 44 | + pub(crate) postgresql_prefix: String, |
| 45 | + pub(crate) default_db: String, |
| 46 | + pub(crate) vss_db: String, |
| 47 | + // The Some(None) variant maps to a TLS connection with no additional certificates |
| 48 | + pub(crate) tls_config: Option<Option<Certificate>>, |
47 | 49 | } |
48 | 50 |
|
49 | | -pub(crate) fn load_config(config_path: &str) -> Result<Config, Box<dyn std::error::Error>> { |
50 | | - let config_str = std::fs::read_to_string(config_path)?; |
51 | | - let config: Config = toml::from_str(&config_str)?; |
52 | | - Ok(config) |
| 51 | +fn load_postgresql_prefix(config: Option<&PostgreSQLConfig>) -> Result<String, String> { |
| 52 | + let username_env = std::env::var("VSS_POSTGRESQL_USERNAME").ok(); |
| 53 | + let username = username_env.as_ref() |
| 54 | + .or(config.and_then(|c| c.username.as_ref())) |
| 55 | + .ok_or("PostgreSQL database username must be provided in config or env var VSS_POSTGRESQL_USERNAME must be set.")?; |
| 56 | + |
| 57 | + let password_env = std::env::var("VSS_POSTGRESQL_PASSWORD").ok(); |
| 58 | + let password = password_env.as_ref() |
| 59 | + .or(config.and_then(|c| c.password.as_ref())) |
| 60 | + .ok_or("PostgreSQL database password must be provided in config or env var VSS_POSTGRESQL_PASSWORD must be set.")?; |
| 61 | + |
| 62 | + let address_env: Option<SocketAddr> = |
| 63 | + if let Some(addr) = std::env::var("VSS_POSTGRESQL_ADDRESS").ok() { |
| 64 | + let socket_addr = addr |
| 65 | + .parse() |
| 66 | + .map_err(|e| format!("Unable to parse postgresql address env var: {}", e))?; |
| 67 | + Some(socket_addr) |
| 68 | + } else { |
| 69 | + None |
| 70 | + }; |
| 71 | + let address = address_env.as_ref() |
| 72 | + .or(config.and_then(|c| c.address.as_ref())) |
| 73 | + .ok_or("PostgreSQL service address must be provided in config or env var VSS_POSTGRESQL_ADDRESS must be set.")?; |
| 74 | + |
| 75 | + Ok(format!("postgresql://{}:{}@{}", username, password, address)) |
| 76 | +} |
| 77 | + |
| 78 | +pub(crate) fn load_configuration(config_file_path: &str) -> Result<Configuration, String> { |
| 79 | + let config_file = std::fs::read_to_string(config_file_path) |
| 80 | + .map_err(|e| format!("Failed to read configuration file: {}", e))?; |
| 81 | + let Config { |
| 82 | + server_config: ServerConfig { bind_address, rsa_pub_file_path }, |
| 83 | + postgresql_config, |
| 84 | + } = toml::from_str(&config_file) |
| 85 | + .map_err(|e| format!("Failed to parse configuration file: {}", e))?; |
| 86 | + |
| 87 | + let jwt_rsa_public_key = if let Some(file_path) = rsa_pub_file_path { |
| 88 | + let rsa_pub_file = std::fs::read(file_path) |
| 89 | + .map_err(|e| format!("Failed to read RSA public key file: {}", e))?; |
| 90 | + let rsa_public_key = DecodingKey::from_rsa_pem(&rsa_pub_file) |
| 91 | + .map_err(|e| format!("Failed to parse RSA public key file: {}", e))?; |
| 92 | + Some(rsa_public_key) |
| 93 | + } else { |
| 94 | + None |
| 95 | + }; |
| 96 | + |
| 97 | + let postgresql_prefix = load_postgresql_prefix(postgresql_config.as_ref())?; |
| 98 | + |
| 99 | + let default_db_env = std::env::var("VSS_POSTGRESQL_DEFAULT_DATABASE").ok(); |
| 100 | + let default_db = default_db_env |
| 101 | + .or(postgresql_config.as_ref().and_then(|c| c.default_database.clone())) |
| 102 | + .ok_or(String::from("PostgreSQL default database name must be provided in config or env var VSS_POSTGRESQL_DEFAULT_DATABASE must be set."))?; |
| 103 | + |
| 104 | + let vss_db_env = std::env::var("VSS_POSTGRESQL_VSS_DATABASE").ok(); |
| 105 | + let vss_db = vss_db_env |
| 106 | + .or(postgresql_config.as_ref().and_then(|c| c.vss_database.clone())) |
| 107 | + .ok_or(String::from("PostgreSQL vss database name must be provided in config or env var VSS_POSTGRESQL_VSS_DATABASE must be set."))?; |
| 108 | + |
| 109 | + let crt_file_path_env = std::env::var("VSS_POSTGRESQL_CRT_FILE_PATH").ok(); |
| 110 | + let crt_file_path = crt_file_path_env.or(postgresql_config |
| 111 | + .as_ref() |
| 112 | + .and_then(|c| c.tls.as_ref()) |
| 113 | + .and_then(|tls| tls.crt_file_path.clone())); |
| 114 | + let certificate = if let Some(file_path) = crt_file_path { |
| 115 | + let crt_file = std::fs::read(&file_path) |
| 116 | + .map_err(|e| format!("Failed to read certificate file: {}", e))?; |
| 117 | + let certificate = Certificate::from_pem(&crt_file) |
| 118 | + .map_err(|e| format!("Failed to parse certificate file: {}", e))?; |
| 119 | + Some(certificate) |
| 120 | + } else { |
| 121 | + None |
| 122 | + }; |
| 123 | + |
| 124 | + let tls_config_env = std::env::var("VSS_POSTGRESQL_TLS").ok(); |
| 125 | + let tls_config = (certificate.is_some() |
| 126 | + || tls_config_env.is_some() |
| 127 | + || postgresql_config.and_then(|c| c.tls).is_some()) |
| 128 | + .then_some(certificate); |
| 129 | + |
| 130 | + Ok(Configuration { |
| 131 | + bind_address, |
| 132 | + jwt_rsa_public_key, |
| 133 | + postgresql_prefix, |
| 134 | + default_db, |
| 135 | + vss_db, |
| 136 | + tls_config, |
| 137 | + }) |
53 | 138 | } |
0 commit comments