LOGIN from an already-identified session reclaims the nick without a needless re-verify
All checks were successful
CI / check (push) Successful in 5m18s

This commit is contained in:
Jean Chevronnet 2026-07-20 21:08:42 +00:00
parent c2a7dfa8f7
commit 7fa7831390
No known key found for this signature in database
3 changed files with 25 additions and 4 deletions

View file

@ -114,7 +114,7 @@ impl Service for NickServ {
match cmd.as_deref() {
Some("REGISTER") => register::handle(me, from, args, ctx, db),
Some("IDENTIFY") | Some("ID") => identify::handle(me, from, args, ctx, db),
Some("LOGIN") => login::handle(me, from, args, ctx, db),
Some("LOGIN") => login::handle(me, &self.guest_nick, &mut self.guest_seq, from, args, ctx, net, db),
Some("LOGOUT") | Some("LOGOFF") => logout::handle(me, &self.guest_nick, &mut self.guest_seq, from, ctx, net, db),
Some("CERT") => cert::handle(me, from, args, ctx, db),
Some("INFO") => info::handle(me, from, args, ctx, net, db),

View file

@ -1,15 +1,22 @@
use echo_api::{AuthThen, Sender, ServiceCtx, Store};
use echo_api::{AuthThen, NetView, Sender, ServiceCtx, Store};
use super::identify;
use super::{ghost, identify};
// LOGIN <nick> <password>: identify to the account owning <nick> and, on success,
// reclaim the nick — freeing any ghost holding it and moving you onto it. A
// one-shot IDENTIFY + RECOVER for someone who connected under a guest nick.
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) {
#[allow(clippy::too_many_arguments)]
pub fn handle(me: &str, guest_nick: &str, guest_seq: &mut u32, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &mut dyn Store) {
let (Some(&nick), Some(&password)) = (args.get(1), args.get(2)) else {
ctx.notice(me, from.uid, "Syntax: LOGIN <nick> <password>");
return;
};
// Already identified to this account: don't burn a needless ~1s re-verify — just
// reclaim the nick, exactly like RECOVER (which needs no password for an owner).
if from.account.is_some() && db.resolve_account(nick) == from.account {
ghost::handle(me, guest_nick, guest_seq, from, args, ctx, net, db, true);
return;
}
let Some((account, verifier)) = identify::precheck(me, from, "LOGIN", nick, ctx, db) else {
return;
};