server: brand the service pseudo-client host (was services.local)
All checks were successful
CI / check (push) Successful in 3m47s

The service pseudo-clients (NickServ etc.) wore a hardcoded services.local host,
so they showed as services@services.local. Add a configurable [server]
service_host (empty defaults to the server name), used when introducing them, so
they appear as services@services.tchatou.fr.
This commit is contained in:
Jean Chevronnet 2026-07-16 19:15:48 +00:00
parent 2f9790feac
commit 7e838cee49
No known key found for this signature in database
3 changed files with 18 additions and 1 deletions

View file

@ -261,6 +261,11 @@ pub struct Server {
// ircd rejects a digit-leading SVSNICK and falls back to the raw uuid.
#[serde(default = "default_guest_nick")]
pub guest_nick: String,
// Hostname the service pseudo-clients wear (NickServ!services@<here>). Empty
// falls back to the server name, so NickServ shows as ...@services.tchatou.fr
// rather than the generic default.
#[serde(default)]
pub service_host: String,
}
fn default_protocol() -> u32 {

View file

@ -102,6 +102,7 @@ pub struct Engine {
// burst is done, so a relink doesn't enforce every already-online user.
synced: bool,
guest_nick: String, // base for the Guest#### rename on enforcement
service_host: String, // hostname the service pseudo-clients wear
enforce_seq: u32, // counter appended to guest_nick
pending_enforce: Vec<PendingEnforce>, // registered nicks awaiting identify-or-rename
bot_uids: HashMap<String, String>, // casefolded bot nick -> live uid (per connection)
@ -229,6 +230,7 @@ impl Engine {
sid: String::new(),
synced: false,
guest_nick: "Guest".to_string(),
service_host: "services.local".to_string(),
enforce_seq: 0,
pending_enforce: Vec::new(),
bot_uids: HashMap::new(),
@ -677,6 +679,13 @@ impl Engine {
}
}
// The hostname the service pseudo-clients wear (NickServ!services@<host>).
pub fn set_service_host(&mut self, host: &str) {
if !host.is_empty() {
self.service_host = host.to_string();
}
}
// A user arrived on (or changed to) a registered nick: if they aren't logged
// into that account, prompt them to IDENTIFY and schedule a rename. Gated on
// `synced` so a netburst can't enforce every already-online user; a user who
@ -808,7 +817,7 @@ impl Engine {
uid: svc.uid().to_string(),
nick: svc.nick().to_string(),
ident: "services".to_string(),
host: svc.host().to_string(),
host: self.service_host.clone(),
gecos: svc.gecos().to_string(),
});
}

View file

@ -178,6 +178,9 @@ async fn main() -> Result<()> {
engine.lock().await.set_opers(cfg.opers());
engine.lock().await.set_sid(cfg.server.sid.clone());
engine.lock().await.set_guest_nick(&cfg.server.guest_nick);
// Service pseudo-clients wear the configured host, or the server name.
let service_host = if cfg.server.service_host.is_empty() { &cfg.server.name } else { &cfg.server.service_host };
engine.lock().await.set_service_host(service_host);
engine.lock().await.set_log_channel(cfg.log.as_ref().map(|l| l.channel.clone()));
if let Some(expire) = &cfg.expire {
engine.lock().await.set_expiry(expire.account_ttl(), expire.channel_ttl(), expire.warn_ttl());