nickserv/chanserv: catch styled/fullwidth look-alike names too, and add a [register] confusable_check toggle (REHASH-reloadable)
All checks were successful
CI / check (push) Successful in 3m48s

This commit is contained in:
Jean Chevronnet 2026-07-19 00:15:08 +00:00
parent c2b70f5004
commit 89ac01d0b0
No known key found for this signature in database
11 changed files with 72 additions and 12 deletions

View file

@ -132,10 +132,12 @@ impl Service for ChanServ {
return;
}
// Refuse a look-alike / mixed-script channel name (e.g. a Cyrillic
// homoglyph of a real channel).
if let Some(reason) = echo_api::confusable_reason(chan) {
ctx.notice(me, from.uid, reason);
return;
// homoglyph of a real channel), unless the guard is turned off.
if db.confusable_check_enabled() {
if let Some(reason) = echo_api::confusable_reason(chan) {
ctx.notice(me, from.uid, reason);
return;
}
}
match db.register_channel(chan, account) {
Ok(()) => {

View file

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

View file

@ -1,9 +1,9 @@
use echo_api::{Sender, ServiceCtx};
use echo_api::{Sender, ServiceCtx, Store};
use echo_api::RegReply;
// REGISTER <password> [email]: register the sender's current nick. The engine
// derives the password off-thread, commits, and answers.
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx) {
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &dyn Store) {
let Some(password) = args.get(1) else {
ctx.notice(me, from.uid, "Syntax: REGISTER <password> [email]");
return;
@ -12,10 +12,13 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx) {
ctx.notice(me, from.uid, reason);
return;
}
// Refuse a look-alike / mixed-script nick before it can be used to impersonate.
if let Some(reason) = echo_api::confusable_reason(from.nick) {
ctx.notice(me, from.uid, reason);
return;
// Refuse a look-alike / mixed-script nick before it can be used to impersonate,
// unless the guard is turned off.
if db.confusable_check_enabled() {
if let Some(reason) = echo_api::confusable_reason(from.nick) {
ctx.notice(me, from.uid, reason);
return;
}
}
let email = args.get(2).map(|s| s.to_string());
ctx.defer_register(from.nick, *password, email, RegReply::NickServ {