From 18a28ed49b13d8e615903660528fe8b0cc99f045 Mon Sep 17 00:00:00 2001 From: Jean Date: Sat, 11 Jul 2026 20:38:28 +0000 Subject: [PATCH] Handle the account-registration relay from an ircd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the registration authority, fedserv accepts an account-registration request relayed over the server link (ACCTREGISTER), creates the account through the same store as classic NickServ REGISTER, and replies (ACCTREGRESULT) with success or an error carrying the IRCv3 FAIL code — one account-creation path for both the classic command and the draft/account-registration capability. --- src/engine/mod.rs | 27 ++++++++++++++++++++++++++- src/proto/inspircd.rs | 24 ++++++++++++++++++++++++ src/proto/mod.rs | 3 +++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 1fc2777..288343c 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -3,7 +3,7 @@ pub mod service; pub mod state; use crate::proto::{NetAction, NetEvent}; -use db::Db; +use db::{Db, RegError}; use service::{Sender, Service, ServiceCtx}; use state::Network; @@ -46,10 +46,35 @@ impl Engine { Vec::new() } NetEvent::Privmsg { from, to, text } => self.dispatch(&from, &to, &text), + NetEvent::AccountRequest { reqid, kind, account, p2, p3, .. } => { + self.account_request(reqid, kind, account, p2, p3) + } _ => Vec::new(), } } + // Authority side of the IRCv3 account-registration relay: create the account + // (same store as classic NickServ REGISTER) and answer the requesting ircd. + fn account_request(&mut self, reqid: String, kind: String, account: String, p2: String, p3: String) -> Vec { + if !kind.eq_ignore_ascii_case("REGISTER") { + return Vec::new(); // VERIFY / RESEND / STATUS: later + } + let email = if p2.is_empty() || p2 == "*" { None } else { Some(p2) }; + let (status, code, message) = match self.db.register(&account, &p3, email) { + Ok(()) => ("success", "*", "Account registered."), + Err(RegError::Exists) => ("error", "ACCOUNT_EXISTS", "That account name is already registered."), + Err(RegError::Internal) => ("error", "TEMPORARILY_UNAVAILABLE", "Registration is unavailable, try again later."), + }; + vec![NetAction::AccountResponse { + reqid, + kind, + account, + status: status.to_string(), + code: code.to_string(), + message: message.to_string(), + }] + } + // Route a PRIVMSG addressed to a service (by uid or nick) into that service, // handing it the sender's resolved nick and the account store. fn dispatch(&mut self, from: &str, to: &str, text: &str) -> Vec { diff --git a/src/proto/inspircd.rs b/src/proto/inspircd.rs index f2f4f04..166a202 100644 --- a/src/proto/inspircd.rs +++ b/src/proto/inspircd.rs @@ -81,6 +81,23 @@ impl Protocol for InspIrcd { } } "QUIT" => vec![NetEvent::Quit { uid: source.unwrap_or_default() }], + // account-registration relay from an ircd: + // ACCTREGISTER : + "ACCTREGISTER" => { + let a: Vec<&str> = tokens.by_ref().take(5).collect(); + if a.len() == 5 { + vec![NetEvent::AccountRequest { + reqid: a[0].to_string(), + origin: a[1].to_string(), + kind: a[2].to_string(), + account: a[3].to_string(), + p2: a[4].to_string(), + p3: trailing(rest), + }] + } else { + vec![] + } + } _ => vec![NetEvent::Unknown { line: line.to_string() }], } } @@ -105,6 +122,13 @@ impl Protocol for InspIrcd { NetAction::Notice { from, to, text } => { vec![format!(":{} NOTICE {} :{}", from, to, text)] } + // ACCTREGRESULT : + NetAction::AccountResponse { reqid, kind, account, status, code, message } => { + vec![self.from_us(format!( + "ACCTREGRESULT {} {} {} {} {} :{}", + reqid, kind, account, status, code, message + ))] + } NetAction::Raw(s) => vec![s.clone()], } } diff --git a/src/proto/mod.rs b/src/proto/mod.rs index 96ac572..4bdd21d 100644 --- a/src/proto/mod.rs +++ b/src/proto/mod.rs @@ -12,6 +12,8 @@ pub enum NetEvent { Privmsg { from: String, to: String, text: String }, UserConnect { uid: String, nick: String }, Quit { uid: String }, + // An ircd relaying an IRCv3 account-registration request to us as the authority. + AccountRequest { reqid: String, origin: String, kind: String, account: String, p2: String, p3: String }, Unknown { line: String }, } @@ -24,6 +26,7 @@ pub enum NetAction { IntroduceUser { uid: String, nick: String, ident: String, host: String, gecos: String }, Privmsg { from: String, to: String, text: String }, Notice { from: String, to: String, text: String }, + AccountResponse { reqid: String, kind: String, account: String, status: String, code: String, message: String }, Raw(String), }