diff --git a/config/default.toml b/config/default.toml index 6980e45..600f2bd 100644 --- a/config/default.toml +++ b/config/default.toml @@ -1,5 +1,5 @@ debug = true -source_code = "https://git.batsense.net/libre-solutions/vanigam" +source_code = "https://git.batsense.net/libre-solutions/vanikam" allow_registration = true [server] @@ -12,7 +12,7 @@ port = 7000 #IP address. Enter 0.0.0.0 to listen on all available addresses ip= "0.0.0.0" # enter your hostname, eg: example.com -domain = "localhost:7000" +hostname = "http://localhost:7000" #cookie_secret = "" [database] @@ -24,3 +24,10 @@ domain = "localhost:7000" # pool = 4 url = "postgres://example.org" # hack for tests to run successfully pool = 4 + +[email] +username="vanikam_mailer" +password="vanikam_mailer_password" +server_hostname="smtp.vanikam.example.com" +from="vanikam@example.com" +reply_to="vanikam@example.com" diff --git a/src/identity/adapters/output/mailer/lettre/mod.rs b/src/identity/adapters/output/mailer/lettre/mod.rs index ef06fa3..58abb85 100644 --- a/src/identity/adapters/output/mailer/lettre/mod.rs +++ b/src/identity/adapters/output/mailer/lettre/mod.rs @@ -2,12 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -use std::sync::Arc; - -use lettre::{ - message::header::ContentType, transport::smtp::authentication::Credentials, AsyncSmtpTransport, - Message, Tokio1Executor, -}; +use lettre::{transport::smtp::authentication::Credentials, AsyncSmtpTransport, Tokio1Executor}; use crate::settings::Settings; @@ -16,25 +11,14 @@ pub struct LettreMailer { mailer: AsyncSmtpTransport, from: String, reply_to: String, - to: String, } impl LettreMailer { pub async fn new(s: &Settings) -> Self { - let email = Message::builder() - .from("NoBody ".parse().unwrap()) - .reply_to("Yuin ".parse().unwrap()) - .to("Hei ".parse().unwrap()) - .subject("Happy new async year") - .header(ContentType::TEXT_PLAIN) - .body(String::from("Be happy with async!")) - .unwrap(); + let creds = Credentials::new(s.email.username.clone(), s.email.password.clone()); - let creds = Credentials::new("smtp_username".to_owned(), "smtp_password".to_owned()); - - // Open a remote connection to gmail let mailer: AsyncSmtpTransport = - AsyncSmtpTransport::::relay("smtp.gmail.com") + AsyncSmtpTransport::::relay(&s.email.server_hostname) .unwrap() .credentials(creds) .build(); @@ -42,14 +26,7 @@ impl LettreMailer { Self { mailer, from: String::default(), // TODO: create settings module to read config - to: String::default(), reply_to: String::default(), } - - // Send the email - // match mailer.send(email).await { - // Ok(_) => println!("Email sent successfully!"), - // Err(e) => panic!("Could not send email: {e:?}"), - // }; } } diff --git a/src/main.rs b/src/main.rs index e652fae..3275444 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,7 @@ async fn main() { log::info!( "Starting server at: {} {}", socket_addr, - settings.server.domain + settings.server.hostname ); HttpServer::new(move || { App::new() diff --git a/src/settings/email.rs b/src/settings/email.rs new file mode 100644 index 0000000..58c88e6 --- /dev/null +++ b/src/settings/email.rs @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: 2024 Aravinth Manivannan +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::env; + +use config::{builder::DefaultState, ConfigBuilder}; +use serde::{Deserialize, Serialize}; +use validator::Validate; + +#[derive(Debug, Clone, Serialize, Deserialize, Validate, Eq, PartialEq)] +pub struct Email { + pub username: String, + pub password: String, + pub server_hostname: String, + #[validate(email)] + pub from: String, + #[validate(email)] + pub reply_to: String, +} + +impl Email { + pub fn env_override(mut s: ConfigBuilder) -> ConfigBuilder { + for (parameter, env_var_name) in [ + ("email.username", "VANIKAM_email_USERNAME"), + ("email.password", "VANIKAM_email_PASSWORD"), + ("email.server_hostname", "VANIKAM_email_SERVER_HOSTNAME"), + ("email.from", "VANIKAM_email_FROM"), + ("email.reply_to", "VANIKAM_email_REPLY_TO"), + ] + .iter() + { + if let Ok(val) = env::var(env_var_name) { + log::debug!("Overriding [{parameter}] with environment variable {env_var_name}"); + s = s.set_override(parameter, val).unwrap(); + } + } + + s + } +} + +#[cfg(test)] +mod tests { + use crate::env_helper; + + use super::*; + + #[test] + fn test_db_env_override() { + let init_settings = crate::settings::Settings::new().unwrap(); + env_helper!( + init_settings, + "VANIKAM_email_USERNAME", + "email_username", + email.username + ); + env_helper!( + init_settings, + "VANIKAM_email_PASSWORD", + "email_password", + email.password + ); + env_helper!( + init_settings, + "VANIKAM_email_FROM", + "from@example.com", + email.from + ); + env_helper!( + init_settings, + "VANIKAM_email_REPLY_TO", + "reploy_to@example.com", + email.reply_to + ); + env_helper!( + init_settings, + "VANIKAM_email_SERVER_HOSTNAME", + "smtp.example.com", + email.server_hostname + ); + } +} diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 4e34281..441d401 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -7,33 +7,36 @@ use std::{env, fs}; use config::builder::DefaultState; use config::{Config, ConfigBuilder, ConfigError, File}; - use serde::Deserialize; use url::Url; +use validator::Validate; pub mod database; +pub mod email; pub mod server; use database::{DBType, Database}; +use email::Email; use server::Server; -#[derive(Debug, Clone, Deserialize, Eq, PartialEq)] +#[derive(Debug, Clone, Validate, Deserialize, Eq, PartialEq)] pub struct Settings { pub debug: bool, pub log: String, + #[validate(url)] pub source_code: String, pub allow_registration: bool, pub database: Database, pub server: Server, - // pub smtp: Option, + pub email: Email, } impl Settings { fn env_override(mut s: ConfigBuilder) -> ConfigBuilder { for (parameter, env_var_name) in [ - ("debug", "VANIGAM_debug"), - ("source_code", "VANIGAM_source_code"), - ("allow_registration", "VANIGAM_allow_registration"), + ("debug", "VANIKAM_debug"), + ("source_code", "VANIKAM_source_code"), + ("allow_registration", "VANIKAM_allow_registration"), ] .iter() { @@ -44,9 +47,17 @@ impl Settings { } s = Database::env_override(s); + s = Email::env_override(s); Server::env_override(s) } + fn run_validations(&self) { + self.validate().unwrap(); + self.email.validate().unwrap(); + self.database.validate().unwrap(); + self.server.validate().unwrap(); + } + pub fn new() -> Result { let mut s = Config::builder(); @@ -66,7 +77,7 @@ impl Settings { .set_default("log", "INFO") .expect("unable to set log default config"); - if let Ok(path) = env::var("VANIGAM_CONFIG") { + if let Ok(path) = env::var("VANIKAM_CONFIG") { let absolute_path = Path::new(&path).canonicalize().unwrap(); log::info!( "Loading config file from {}", @@ -94,6 +105,7 @@ impl Settings { settings.check_url(); settings.database.set_database_type(); + settings.run_validations(); Ok(settings) } diff --git a/src/settings/server.rs b/src/settings/server.rs index 20f4b2b..6aa6a04 100644 --- a/src/settings/server.rs +++ b/src/settings/server.rs @@ -1,15 +1,17 @@ // SPDX-FileCopyrightText: 2024 Aravinth Manivannan // // SPDX-License-Identifier: AGPL-3.0-or-later +use std::env; use config::{builder::DefaultState, ConfigBuilder}; use serde::Deserialize; -use std::env; +use validator::Validate; -#[derive(Debug, Clone, Deserialize, Eq, PartialEq)] +#[derive(Debug, Clone, Validate, Deserialize, Eq, PartialEq)] pub struct Server { pub port: u32, - pub domain: String, + #[validate(url)] + pub hostname: String, pub ip: String, pub cookie_secret: String, } @@ -22,9 +24,9 @@ impl Server { pub fn env_override(mut s: ConfigBuilder) -> ConfigBuilder { for (parameter, env_var_name) in [ ("server.port", "PORT"), - ("server.domain", "VANIGAM_server_DOMAIN"), - ("server.cookie_secret", "VANIGAM_server_COOKIE_SECRET"), - ("server.ip", "VANIGAM_server_IP"), + ("server.hostname", "VANIKAM_server_HOSTNAME"), + ("server.cookie_secret", "VANIKAM_server_COOKIE_SECRET"), + ("server.ip", "VANIKAM_server_IP"), ] .iter() { @@ -50,14 +52,14 @@ mod tests { env_helper!(init_settings, "PORT", 22, server.port); env_helper!( init_settings, - "VANIGAM_server_DOMAIN", - "test_server_env_override.org", - server.domain + "VANIKAM_server_HOSTNAME", + "https://test_server_env_override.org", + server.hostname ); - env_helper!(init_settings, "VANIGAM_server_IP", "1.1.1.1", server.ip); + env_helper!(init_settings, "VANIKAM_server_IP", "1.1.1.1", server.ip); env_helper!( init_settings, - "VANIGAM_server_COOKIE_SECRET", + "VANIKAM_server_COOKIE_SECRET", "asdfasdflkjhasdlkfhalksdf", server.cookie_secret );