OperServ: enforce FORBID EMAIL at registration and SET EMAIL

FORBID accepted and stored EMAIL patterns, but nothing ever checked them:
a forbidden address still registered and could be set via NickServ SET
EMAIL. Both paths now reject a matching address (new ForbiddenEmail
outcome), matching how NICK and CHAN forbids already gate registration.
This commit is contained in:
Jean Chevronnet 2026-07-16 03:11:57 +00:00
parent 01ea0fa95e
commit b749cd2969
No known key found for this signature in database
4 changed files with 28 additions and 0 deletions

View file

@ -1268,6 +1268,8 @@ enum RegOutcome {
VerifyRequired,
/// The name is on the OperServ FORBID list.
Forbidden,
/// The supplied email matches an OperServ FORBID EMAIL pattern.
ForbiddenEmail,
Exists,
RateLimited,
Frozen,
@ -1284,6 +1286,7 @@ fn reg_reply(reply: &RegReply, outcome: RegOutcome, account: &str) -> Vec<NetAct
RegOutcome::Ok => ("success", "*", "Account registered."),
RegOutcome::VerifyRequired => ("verification_required", "VERIFICATION_REQUIRED", "Registered — check your email for a code, then VERIFY."),
RegOutcome::Forbidden => ("error", "BAD_ACCOUNT_NAME", "That account name is forbidden by network policy."),
RegOutcome::ForbiddenEmail => ("error", "BAD_EMAIL", "That email address is forbidden by network policy."),
RegOutcome::Exists => ("error", "ACCOUNT_EXISTS", "That account name is already registered."),
RegOutcome::RateLimited => ("error", "TEMPORARILY_UNAVAILABLE", "Too many registrations, please wait a moment."),
RegOutcome::Frozen => ("error", "TEMPORARILY_UNAVAILABLE", "Registrations are temporarily frozen by network staff."),
@ -1311,6 +1314,7 @@ fn reg_reply(reply: &RegReply, outcome: RegOutcome, account: &str) -> Vec<NetAct
notice(format!("Your nick \x02{nick}\x02 is now registered and you're logged in. Welcome!")),
],
RegOutcome::Forbidden => vec![notice("That nickname is forbidden and can't be registered.".to_string())],
RegOutcome::ForbiddenEmail => vec![notice("That email address is forbidden by network policy. Use a different one.".to_string())],
RegOutcome::Exists => vec![notice(format!("\x02{nick}\x02 is already registered. If it's yours, use \x02IDENTIFY <password>\x02."))],
RegOutcome::RateLimited => vec![notice("Registrations are busy right now. Please try again in a moment.".to_string())],
RegOutcome::Frozen => vec![notice("Registrations are temporarily frozen by network staff. Please try again later.".to_string())],