diff --git a/README.md b/README.md index 8051393..b924fab 100644 --- a/README.md +++ b/README.md @@ -14,34 +14,33 @@ ## Configuration Forgery reads the following environment variables: -- `FORGE_URL`: url of the forgejo instance (e.g. https://git.deuxfleurs.fr) -- `FORGE_API_TOKEN`: Forgejo API token *granting admin access*. Required. You - can generate an API token using the Forgejo web interface in `Settings -> +- `FORGE_URL` (**mandatory**): url of the forgejo instance (e.g. + https://git.deuxfleurs.fr) +- `FORGE_API_TOKEN` (**mandatory**): Forgejo API token *granting admin access*. + You can generate an API token using the Forgejo web interface in `Settings -> Applications -> Generate New Token`. -- `ORG_NAME`: organization name (used in the notification email sent when - locking accounts) -- `ADMIN_CONTACT_EMAIL`: email that can be used to contact admins of your - instance (included in the notification email sent when locking accounts) -- `ACTUALLY_BAN_USERS`: define it to `true` to actually lock user accounts, send - notification emails and eventually delete user accounts. If not defined (the - default) or set to `false`, no actual action is taken: spammers are only - listed in the database. The variable should be set in production, but probably - not for testing. -- `STORAGE_BACKEND`: either `local` (default) or `s3`. Chose `local` to store - the application state to local files, or `s3` to store them in S3-compatible - storage (see below for corresponding configuration variables). -- `LISTEN_ADDR`: address on which the webserver listens (default: `0.0.0.0`) -- `LISTEN_PORT`: port on which the webserver listens (default: `8080`) +- `ACTUALLY_BAN_USERS` (default: `false`): define it to `true` to actually lock + user accounts, send notification emails and eventually delete user accounts. + Otherwise, no actual action is taken: spammers are only listed in the + database. The variable should be set in production, but probably not for + testing. +- `STORAGE_BACKEND` (default: `local`): either `local` or `s3`. Chose `local` to + store the application state to local files, or `s3` to store them in + S3-compatible storage (see below for corresponding configuration variables). +- `BIND_ADDR` (default: `127.0.0.1:8080`): address on which the webserver listens Environment variables read when `ACTUALLY_BAN_USERS=true`: - `SMTP_ADDRESS`: address of the SMTP relay used to send email notifications - `SMTP_USERNAME`: SMTP username - `SMTP_PASSWORD`: SMTP password +- `ADMIN_CONTACT_EMAIL`: email that can be used to contact admins of your + instance (included in the notification email sent when locking accounts) +- `ORG_NAME`: organization name (used in the notification email sent when + locking accounts) Environment variables read when `STORAGE_BACKEND=local`: -- `STORAGE_LOCAL_DIR`: path to a local directory where to store the application - data (as two files `db.json` and `model.json`). Defaults to `.` if not - defined. +- `STORAGE_LOCAL_DIR` (default: `.`): path to a local directory where to store + the application data (as two files `db.json` and `model.json`). Environment variables read when `STORAGE_BACKEND=s3`: - `STORAGE_S3_BUCKET`: name of the bucket where to store the application data diff --git a/src/email.rs b/src/email.rs index 826f7af..a7117e7 100644 --- a/src/email.rs +++ b/src/email.rs @@ -39,13 +39,13 @@ impl SmtpConfig { pub async fn send_locked_account_notice( config: &Config, smtp: &SmtpConfig, + admin_contact_email: &str, + org_name: &str, login: &str, email: &str, ) -> anyhow::Result<()> { let grace_period_days = crate::GRACE_PERIOD.as_secs() / (24 * 3600); - let org_name = &config.org_name; let forge_url = &config.forge_url; - let admin_contact_email = &config.admin_contact_email; let email = Message::builder() .from(smtp.username.parse().unwrap()) diff --git a/src/main.rs b/src/main.rs index 4afa9fd..5e74104 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,23 +56,20 @@ const GUESS_LEGIT_THRESHOLD: f32 = 0.3; pub struct Config { pub forge_url: Url, pub forge_api_token: String, - pub org_name: String, - pub admin_contact_email: String, pub actually_ban: ActuallyBan, - pub listen_addr: String, - pub listen_port: u16, + pub bind_addr: String, } impl Config { async fn from_env() -> anyhow::Result { let forge_url_s = env_var("FORGE_URL")?; let forge_api_token = env_var("FORGE_API_TOKEN")?; - let org_name = env_var("ORG_NAME")?; - let admin_contact_email = env_var("ADMIN_CONTACT_EMAIL")?; let actually_ban = match env_var("ACTUALLY_BAN_USERS").as_deref() { Ok("true") => ActuallyBan::Yes { smtp: SmtpConfig::from_env().await?, + admin_contact_email: env_var("ADMIN_CONTACT_EMAIL")?, + org_name: env_var("ORG_NAME")?, }, Ok("false") => ActuallyBan::No, Ok(_) => { @@ -83,21 +80,13 @@ impl Config { Err(_) => ActuallyBan::No, }; - let listen_addr = env_var("LISTEN_ADDR").unwrap_or(String::from("0.0.0.0")); - let listen_port: u16 = match env_var("LISTEN_PORT").map(|s| u16::from_str_radix(&s, 10)) { - Ok(Err(e)) => return Err(anyhow!("LISTEN_PORT: invalid value ({})", e)), - Ok(Ok(p)) => p, - Err(_) => 8080, - }; + let bind_addr = env_var("BIND_ADDR").unwrap_or(String::from("127.0.0.1:8080")); Ok(Config { forge_url: Url::parse(&forge_url_s).context("parsing FORGE_URL")?, forge_api_token, - org_name, - admin_contact_email, actually_ban, - listen_addr, - listen_port, + bind_addr, }) } } @@ -105,7 +94,11 @@ impl Config { // Whether we are actually banning users or are instead in "testing" mode where // we don't do anything. (Defaults to "No".) pub enum ActuallyBan { - Yes { smtp: SmtpConfig }, + Yes { + smtp: SmtpConfig, + admin_contact_email: String, + org_name: String, + }, No, } @@ -496,15 +489,7 @@ async fn main() -> anyhow::Result<()> { .spawn(async move { workers::lock_and_notify_users(config, storage, forge, db).await }) }; - println!( - "Listening on http://{}:{}", - (if config.listen_addr == "0.0.0.0" { - "127.0.0.1" - } else { - &config.listen_addr - }), - config.listen_port - ); + println!("Listening on http://{}", &config.bind_addr); let app = Router::new() .route("/", get(get_index).post(post_classified_index)) @@ -516,10 +501,9 @@ async fn main() -> anyhow::Result<()> { .with_state(shared_state); let webserver = { - let listener = - tokio::net::TcpListener::bind((config.listen_addr.clone(), config.listen_port)) - .await - .unwrap(); + let listener = tokio::net::TcpListener::bind(&config.bind_addr) + .await + .unwrap(); axum::serve(listener, app) }; diff --git a/src/workers.rs b/src/workers.rs index 4648d06..2b21772 100644 --- a/src/workers.rs +++ b/src/workers.rs @@ -237,9 +237,21 @@ pub async fn try_lock_and_notify_user( if !notified { match &config.actually_ban { - ActuallyBan::Yes { smtp } => { + ActuallyBan::Yes { + smtp, + admin_contact_email, + org_name, + } => { eprintln!("Sending notification email to user {login}"); - email::send_locked_account_notice(config, smtp, &login, &email).await?; + email::send_locked_account_notice( + config, + smtp, + &admin_contact_email, + &org_name, + &login, + &email, + ) + .await?; eprintln!("Success"); } ActuallyBan::No => {