registration: add a Hold verdict so captcha/challenge modules pend the client for the challenge instead of tearing the link down

This commit is contained in:
Jean Chevronnet 2026-08-17 19:06:17 +00:00
parent 99eb9c74f3
commit 4b86de3b62
4 changed files with 23 additions and 9 deletions

View file

@ -545,13 +545,19 @@ impl Ircd {
fn complete_registration(&mut self, uid: Uid) {
for m in &mut self.modules {
if m.on_user_register(&mut self.server, uid) == ModResult::Deny {
self.server.send(
uid,
"ERROR :Closing link (registration refused)".to_string(),
);
self.server.remove_user(uid, "Registration refused");
return;
match m.on_user_register(&mut self.server, uid) {
ModResult::Deny => {
self.server.send(
uid,
"ERROR :Closing link (registration refused)".to_string(),
);
self.server.remove_user(uid, "Registration refused");
return;
}
// a challenge is pending: keep the connection, don't welcome yet.
// A later command (the CAPTCHA/VERIFYCHALLENGE reply) re-runs this.
ModResult::Hold => return,
_ => {}
}
}
// x-line: refuse a banned host / ip before welcoming

View file

@ -15,6 +15,12 @@ pub enum ModResult {
Passthru,
Allow,
Deny,
/// `on_user_register` only: hold the client in the pre-registration state (a
/// challenge is pending) without completing OR refusing the link. Registration
/// resumes on a later command once the hold clears (e.g. the client presents a
/// CAPTCHA/VERIFYCHALLENGE token). If they never do, the registration timeout
/// reaps them like any other stalled connection.
Hold,
}
/// A queued notify-event, drained by the core after each command.

View file

@ -93,7 +93,8 @@ impl Module for CloudflareChallenge {
let msg = template.replace("{url}", &link);
srv.send(uid, format!(":{} NOTICE {nick} :{msg}", srv.name));
}
ModResult::Deny
// Hold the connection for the challenge (VERIFYCHALLENGE <token>), don't drop it.
ModResult::Hold
}
}

View file

@ -103,7 +103,8 @@ impl Module for ReCaptcha {
let msg = template.replace("{url}", &link);
srv.send(uid, format!(":{} NOTICE {nick} :{msg}", srv.name));
}
ModResult::Deny
// Hold the connection for the challenge (CAPTCHA <token>), don't tear it down.
ModResult::Hold
}
}