diff --git a/Cargo.lock b/Cargo.lock index b87820a..8a889d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1718,6 +1718,7 @@ dependencies = [ "quoted_printable", "r2d2", "regex", + "serde", "tokio", "tokio-native-tls", ] diff --git a/lldap_config.docker_template.toml b/lldap_config.docker_template.toml index 855744f..be992bd 100644 --- a/lldap_config.docker_template.toml +++ b/lldap_config.docker_template.toml @@ -66,3 +66,25 @@ database_url = "sqlite:///data/users.db?mode=rwc" ## each password. ## Randomly generated on first run if it doesn't exist. key_file = "/data/private_key" + +## Options to configure SMTP parameters, to send password reset emails. +## To set these options from environment variables, use the following format +## (example with "password"): LLDAP_SMTP_OPTIONS__PASSWORD +#[smtp_options] +## Whether to enabled password reset via email, from LLDAP. +#enable_password_reset=true +## The SMTP server. +#server="smtp.gmail.com" +## The SMTP port. +#port=587 +## Whether to connect with TLS. +#tls_required=true +## The SMTP user, usually your email address. +#user="sender@gmail.com" +## The SMTP password. +#password="password" +## The header field, optional: how the sender appears in the email. The first +## is a free-form name, followed by an email between <>. +#from="LLDAP Admin " +## Same for reply-to, optional. +#reply_to="Do not reply " diff --git a/server/Cargo.toml b/server/Cargo.toml index 4f8a3e1..94452d2 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -57,6 +57,7 @@ rev = "eb59676a940b15f77871aefe1e46d7b5bf85f40a" version = "0.10.0-rc.3" features = [ "builder", + "serde", "smtp-transport", "tokio1-native-tls", "tokio1", diff --git a/server/src/infra/cli.rs b/server/src/infra/cli.rs index cd0be24..175cac0 100644 --- a/server/src/infra/cli.rs +++ b/server/src/infra/cli.rs @@ -21,7 +21,7 @@ pub enum Command { #[derive(Debug, Clap, Clone)] pub struct RunOpts { - /// Change config file name + /// Change config file name. #[clap(short, long, default_value = "lldap_config.toml")] pub config_file: String, @@ -33,7 +33,11 @@ pub struct RunOpts { #[clap(long)] pub ldaps_port: Option, - /// Set verbose logging + /// Change HTTP API port. Default: 17170 + #[clap(long)] + pub http_port: Option, + + /// Set verbose logging. #[clap(short, long)] pub verbose: bool, } diff --git a/server/src/infra/configuration.rs b/server/src/infra/configuration.rs index cc68fce..49eda50 100644 --- a/server/src/infra/configuration.rs +++ b/server/src/infra/configuration.rs @@ -1,13 +1,39 @@ +use crate::infra::cli::RunOpts; use anyhow::{Context, Result}; use figment::{ providers::{Env, Format, Serialized, Toml}, Figment, }; +use lettre::message::Mailbox; use lldap_auth::opaque::{server::ServerSetup, KeyPair}; -use log::*; use serde::{Deserialize, Serialize}; -use crate::infra::cli::RunOpts; +#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)] +#[builder(pattern = "owned")] +pub struct MailOptions { + #[builder(default = "false")] + pub enable_password_reset: bool, + #[builder(default = "None")] + pub from: Option, + #[builder(default = "None")] + pub reply_to: Option, + #[builder(default = r#""localhost".to_string()"#)] + pub server: String, + #[builder(default = "587")] + pub port: u16, + #[builder(default = r#""admin".to_string()"#)] + pub user: String, + #[builder(default = r#""".to_string()"#)] + pub password: String, + #[builder(default = "true")] + pub tls_required: bool, +} + +impl std::default::Default for MailOptions { + fn default() -> Self { + MailOptionsBuilder::default().build().unwrap() + } +} #[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)] #[builder( @@ -35,11 +61,19 @@ pub struct Configuration { pub verbose: bool, #[builder(default = r#"String::from("server_key")"#)] pub key_file: String, + #[builder(default)] + pub smtp_options: MailOptions, #[serde(skip)] #[builder(field(private), setter(strip_option))] server_setup: Option, } +impl std::default::Default for Configuration { + fn default() -> Self { + ConfigurationBuilder::default().build().unwrap() + } +} + impl ConfigurationBuilder { pub fn build(self) -> Result { let server_setup = get_server_setup(self.key_file.as_deref().unwrap_or("server_key"))?; @@ -77,6 +111,10 @@ impl Configuration { self.ldaps_port = port; } + if let Some(port) = cli_opts.http_port { + self.http_port = port; + } + self } } @@ -108,7 +146,7 @@ pub fn init(cli_opts: RunOpts) -> Result { ConfigurationBuilder::default().build().unwrap(), )) .merge(Toml::file(config_file)) - .merge(Env::prefixed("LLDAP_")) + .merge(Env::prefixed("LLDAP_").split("__")) .extract()?; let mut config = config.merge_with_cli(cli_opts);