diff --git a/.env.template b/.env.template index 79b93f4..7c0200d 100644 --- a/.env.template +++ b/.env.template @@ -95,6 +95,14 @@ ## Controls if new users can register # SIGNUPS_ALLOWED=true +## Controls if new users from a list of comma-separated domains can register +## even if SIGNUPS_ALLOWED is set to false +## +## WARNING: There is currently no validation that prevents anyone from +## signing up with any made-up email address from one of these +## whitelisted domains! +# SIGNUPS_DOMAINS_WHITELIST=example.com,example.net,example.org + ## Token for the admin interface, preferably use a long random string ## One option is to use 'openssl rand -base64 48' ## If not set, the admin panel is disabled diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 9c9e7da..b91e724 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -90,7 +90,7 @@ fn register(data: JsonUpcase, conn: DbConn) -> EmptyResult { } } None => { - if CONFIG.signups_allowed() || Invitation::take(&data.Email, &conn) { + if CONFIG.signups_allowed() || Invitation::take(&data.Email, &conn) || CONFIG.can_signup_user(&data.Email) { User::new(data.Email.clone()) } else { err!("Registration not allowed or user already exists") diff --git a/src/config.rs b/src/config.rs index 1f18549..f75b9e6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -243,6 +243,8 @@ make_config! { disable_icon_download: bool, true, def, false; /// Allow new signups |> Controls if new users can register. Note that while this is disabled, users could still be invited signups_allowed: bool, true, def, true; + /// Allow signups only from this list of comma-separated domains + signups_domains_whitelist: String, true, def, "".to_string(); /// Allow invitations |> Controls whether users can be invited by organization admins, even when signups are disabled invitations_allowed: bool, true, def, true; /// Password iterations |> Number of server-side passwords hashing iterations. @@ -491,6 +493,16 @@ impl Config { self.update_config(builder) } + pub fn can_signup_user(&self, email: &str) -> bool { + let e: Vec<&str> = email.rsplitn(2, "@").collect(); + if e.len() != 2 || e[0].is_empty() || e[1].is_empty() { + warn!("Failed to parse email address '{}'", email); + return false + } + + self.signups_domains_whitelist().split(",").any(|d| d == e[0]) + } + pub fn delete_user_config(&self) -> Result<(), Error> { crate::util::delete_file(&CONFIG_FILE)?;