mirror of
https://github.com/modrinth/code.git
synced 2026-09-04 22:10:15 +00:00
feat: bring back email domain blacklist
This commit is contained in:
@@ -314,7 +314,7 @@ vars! {
|
|||||||
SENDY_LIST_ID: String = "none";
|
SENDY_LIST_ID: String = "none";
|
||||||
SENDY_API_KEY: String = "none";
|
SENDY_API_KEY: String = "none";
|
||||||
|
|
||||||
SKIP_EMAIL_CHECK_DOMAINS: String = "";
|
SKIP_EMAIL_CHECK_DOMAINS: StringCsv = StringCsv(vec![]);
|
||||||
|
|
||||||
NEVERBOUNCE_API_KEY: String = "";
|
NEVERBOUNCE_API_KEY: String = "";
|
||||||
NEVERBOUNCE_BASE_URL: String = neverbounce::DEFAULT_API_URL;
|
NEVERBOUNCE_BASE_URL: String = neverbounce::DEFAULT_API_URL;
|
||||||
@@ -323,6 +323,8 @@ vars! {
|
|||||||
USERCHECK_GATE_ID: String = "";
|
USERCHECK_GATE_ID: String = "";
|
||||||
USERCHECK_BASE_URL: String = crate::util::usercheck::DEFAULT_API_URL;
|
USERCHECK_BASE_URL: String = crate::util::usercheck::DEFAULT_API_URL;
|
||||||
|
|
||||||
|
EMAIL_DOMAIN_BLACKLIST: StringCsv = StringCsv(vec![]);
|
||||||
|
|
||||||
CLICKHOUSE_REPLICATED: bool = false;
|
CLICKHOUSE_REPLICATED: bool = false;
|
||||||
CLICKHOUSE_URL: String = "http://localhost:8123";
|
CLICKHOUSE_URL: String = "http://localhost:8123";
|
||||||
CLICKHOUSE_USER: String = "default";
|
CLICKHOUSE_USER: String = "default";
|
||||||
|
|||||||
@@ -1901,17 +1901,54 @@ impl From<NewAccount> for AccountRegisterFlow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Domains listed in `SKIP_EMAIL_CHECK_DOMAINS` bypass every email check.
|
/// List entries are matched literally, unless they begin with `*.`, in which
|
||||||
|
/// case they match any subdomain of the remaining suffix.
|
||||||
|
fn matches_domain_entry(domain: &str, entry: &str) -> bool {
|
||||||
|
let entry = entry.trim().to_ascii_lowercase();
|
||||||
|
|
||||||
|
match entry.strip_prefix("*.") {
|
||||||
|
Some(suffix) => domain
|
||||||
|
.strip_suffix(suffix)
|
||||||
|
.is_some_and(|subdomain| subdomain.ends_with('.')),
|
||||||
|
None => entry == domain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn domain_of(email: &str) -> Option<String> {
|
||||||
|
email
|
||||||
|
.rsplit_once('@')
|
||||||
|
.map(|(_, domain)| domain.to_ascii_lowercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn domain_matches_list(domain: &str, list: &[String]) -> bool {
|
||||||
|
list.iter().any(|entry| matches_domain_entry(domain, entry))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Domains listed in `SKIP_EMAIL_CHECK_DOMAINS` bypass every email check,
|
||||||
|
/// including the blacklist.
|
||||||
fn email_checks_skipped(email: &str) -> bool {
|
fn email_checks_skipped(email: &str) -> bool {
|
||||||
let Some((_, domain)) = email.rsplit_once('@') else {
|
domain_of(email).is_some_and(|domain| {
|
||||||
return false;
|
domain_matches_list(&domain, &ENV.SKIP_EMAIL_CHECK_DOMAINS)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_email_domain_is_not_blacklisted(email: &str) -> Result<(), ApiError> {
|
||||||
|
let Some(domain) = domain_of(email) else {
|
||||||
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
ENV.SKIP_EMAIL_CHECK_DOMAINS
|
if !domain_matches_list(&domain, &ENV.EMAIL_DOMAIN_BLACKLIST) {
|
||||||
.split(',')
|
return Ok(());
|
||||||
.map(str::trim)
|
}
|
||||||
.filter(|skipped| !skipped.is_empty())
|
|
||||||
.any(|skipped| skipped.eq_ignore_ascii_case(domain))
|
info!(
|
||||||
|
email.domain = domain.as_str(),
|
||||||
|
"blacklisted email domain, denying",
|
||||||
|
);
|
||||||
|
|
||||||
|
Err(ApiError::Request(eyre!(
|
||||||
|
"This domain name may not be used ({domain})!"
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the UserCheck gate, which covers both password and OAuth signups.
|
/// Runs the UserCheck gate, which covers both password and OAuth signups.
|
||||||
@@ -1923,6 +1960,8 @@ async fn ensure_email_passes_gate(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_email_domain_is_not_blacklisted(email)?;
|
||||||
|
|
||||||
let action = check_email_gate(redis, email)
|
let action = check_email_gate(redis, email)
|
||||||
.await
|
.await
|
||||||
.wrap_request_err("checking email address")?;
|
.wrap_request_err("checking email address")?;
|
||||||
|
|||||||
Reference in New Issue
Block a user