Handle the account-registration relay from an ircd

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.
This commit is contained in:
Jean Chevronnet 2026-07-11 20:38:28 +00:00
parent 9285105afd
commit 18a28ed49b
No known key found for this signature in database
3 changed files with 53 additions and 1 deletions

View file

@ -3,7 +3,7 @@ pub mod service;
pub mod state; pub mod state;
use crate::proto::{NetAction, NetEvent}; use crate::proto::{NetAction, NetEvent};
use db::Db; use db::{Db, RegError};
use service::{Sender, Service, ServiceCtx}; use service::{Sender, Service, ServiceCtx};
use state::Network; use state::Network;
@ -46,10 +46,35 @@ impl Engine {
Vec::new() Vec::new()
} }
NetEvent::Privmsg { from, to, text } => self.dispatch(&from, &to, &text), 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(), _ => 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<NetAction> {
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, // 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. // handing it the sender's resolved nick and the account store.
fn dispatch(&mut self, from: &str, to: &str, text: &str) -> Vec<NetAction> { fn dispatch(&mut self, from: &str, to: &str, text: &str) -> Vec<NetAction> {

View file

@ -81,6 +81,23 @@ impl Protocol for InspIrcd {
} }
} }
"QUIT" => vec![NetEvent::Quit { uid: source.unwrap_or_default() }], "QUIT" => vec![NetEvent::Quit { uid: source.unwrap_or_default() }],
// account-registration relay from an ircd:
// ACCTREGISTER <reqid> <origin> <kind> <account> <p2> :<p3>
"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() }], _ => vec![NetEvent::Unknown { line: line.to_string() }],
} }
} }
@ -105,6 +122,13 @@ impl Protocol for InspIrcd {
NetAction::Notice { from, to, text } => { NetAction::Notice { from, to, text } => {
vec![format!(":{} NOTICE {} :{}", from, to, text)] vec![format!(":{} NOTICE {} :{}", from, to, text)]
} }
// ACCTREGRESULT <reqid> <kind> <account> <status> <code> :<message>
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()], NetAction::Raw(s) => vec![s.clone()],
} }
} }

View file

@ -12,6 +12,8 @@ pub enum NetEvent {
Privmsg { from: String, to: String, text: String }, Privmsg { from: String, to: String, text: String },
UserConnect { uid: String, nick: String }, UserConnect { uid: String, nick: String },
Quit { uid: 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 }, Unknown { line: String },
} }
@ -24,6 +26,7 @@ pub enum NetAction {
IntroduceUser { uid: String, nick: String, ident: String, host: String, gecos: String }, IntroduceUser { uid: String, nick: String, ident: String, host: String, gecos: String },
Privmsg { from: String, to: String, text: String }, Privmsg { from: String, to: String, text: String },
Notice { 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), Raw(String),
} }