server: Extract configuration utilities

This commit is contained in:
Valentin Tolmer
2025-10-10 23:02:44 +02:00
committed by nitnelave
parent 0f8f9e1244
commit 1382c67de9
+46 -39
View File
@@ -5,9 +5,9 @@ use crate::{
}, },
database_string::DatabaseUrl, database_string::DatabaseUrl,
}; };
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, anyhow, bail};
use figment::{ use figment::{
Figment, Figment, Provider,
providers::{Env, Format, Serialized, Toml}, providers::{Env, Format, Serialized, Toml},
}; };
use figment_file_provider_adapter::FileAdapter; use figment_file_provider_adapter::FileAdapter;
@@ -556,6 +556,45 @@ fn expected_keys(dict: &figment::value::Dict) -> HashSet<String> {
keys keys
} }
fn check_for_unexpected_env_variables<P: Provider>(env_variable_provider: P) {
use figment::Profile;
let expected_keys = expected_keys(
&Figment::from(Serialized::defaults(
ConfigurationBuilder::default().private_build().unwrap(),
))
.data()
.unwrap()[&Profile::default()],
);
extract_keys(&env_variable_provider.data().unwrap()[&Profile::default()])
.iter()
.filter(|k| !expected_keys.contains(k.as_str()))
.for_each(|k| {
eprintln!("WARNING: Unknown environment variable: {k}");
});
}
fn generate_jwt_sample_error() -> String {
use rand::{Rng, seq::SliceRandom};
struct Symbols;
impl rand::distributions::Distribution<char> for Symbols {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
*b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+,-./:;<=>?_~!@#$%^&*()[]{}:;".choose(rng).unwrap() as char
}
}
format!(
"The JWT secret must be initialized to a random string, preferably at least 32 characters long. \
Either set the `jwt_secret` config value or the `LLDAP_JWT_SECRET` environment variable. \
You can generate the value by running\n\
LC_ALL=C tr -dc 'A-Za-z0-9!#%&'\\''()*+,-./:;<=>?@[\\]^_{{|}}~' </dev/urandom | head -c 32; echo ''\n\
or you can use this random value: {}",
rand::thread_rng()
.sample_iter(&Symbols)
.take(32)
.collect::<String>()
)
}
pub fn init<C>(overrides: C) -> Result<Configuration> pub fn init<C>(overrides: C) -> Result<Configuration>
where where
C: TopLevelCommandOpts + ConfigOverrider, C: TopLevelCommandOpts + ConfigOverrider,
@@ -581,22 +620,7 @@ where
if config.verbose { if config.verbose {
println!("Configuration: {:#?}", &config); println!("Configuration: {:#?}", &config);
} }
{ check_for_unexpected_env_variables(env_variable_provider());
use figment::{Profile, Provider};
let expected_keys = expected_keys(
&Figment::from(Serialized::defaults(
ConfigurationBuilder::default().private_build().unwrap(),
))
.data()
.unwrap()[&Profile::default()],
);
extract_keys(&env_variable_provider().data().unwrap()[&Profile::default()])
.iter()
.filter(|k| !expected_keys.contains(k.as_str()))
.for_each(|k| {
eprintln!("WARNING: Unknown environment variable: LLDAP_{k}");
});
}
config.server_setup = Some(get_server_setup( config.server_setup = Some(get_server_setup(
&config.key_file, &config.key_file,
config config
@@ -606,27 +630,10 @@ where
.unwrap_or_default(), .unwrap_or_default(),
figment_config, figment_config,
)?); )?);
if config.jwt_secret.is_none() { config
use rand::{Rng, seq::SliceRandom}; .jwt_secret
struct Symbols; .as_ref()
.ok_or_else(|| anyhow!("{}", generate_jwt_sample_error()))?;
impl rand::prelude::Distribution<char> for Symbols {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
*b"01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+,-./:;<=>?_~!@#$%^&*()[]{}:;".choose(rng).unwrap() as char
}
}
bail!(
"The JWT secret must be initialized to a random string, preferably at least 32 characters long. \
Either set the `jwt_secret` config value or the `LLDAP_JWT_SECRET` environment variable. \
You can generate the value by running\n\
LC_ALL=C tr -dc 'A-Za-z0-9!#%&'\\''()*+,-./:;<=>?@[\\]^_{{|}}~' </dev/urandom | head -c 32; echo ''\n\
or you can use this random value: {}",
rand::thread_rng()
.sample_iter(&Symbols)
.take(32)
.collect::<String>()
);
}
if config.smtp_options.tls_required.is_some() { if config.smtp_options.tls_required.is_some() {
println!( println!(
"DEPRECATED: smtp_options.tls_required field is deprecated, it never did anything. You can replace it with smtp_options.smtp_encryption." "DEPRECATED: smtp_options.tls_required field is deprecated, it never did anything. You can replace it with smtp_options.smtp_encryption."