account_registration: GC the per-IP rate-limit table on the tick (an entry per distinct registering IP was never dropped)

This commit is contained in:
Jean Chevronnet 2026-08-17 22:13:37 +00:00
parent e28efb03e6
commit 7563daf3a3
2 changed files with 22 additions and 0 deletions

View file

@ -23,6 +23,7 @@ use std::collections::HashMap;
use crate::command::{CmdResult, Command};
use crate::http::{json_str, urlencode};
use crate::module::Module;
use crate::server::{now, Server};
use crate::Uid;
@ -30,6 +31,26 @@ use crate::Uid;
#[derive(Default)]
struct RateState(HashMap<String, Vec<u64>>);
/// Ticks the rate-limit table: prunes each IP's timestamps to the window and drops
/// IPs with none left, so the map can't accumulate one entry per distinct IP that
/// ever issued a REGISTER over the process lifetime.
pub struct AcctRegGc;
impl Module for AcctRegGc {
fn name(&self) -> &'static str {
"account_registration"
}
fn on_tick(&mut self, s: &mut Server) {
let window = s.conf_num("acctregister_ratetime", 3600u64);
let n = now();
if let Some(st) = s.ext.get_mut::<RateState>() {
st.0.retain(|_, hist| {
hist.retain(|&t| n.saturating_sub(t) < window);
!hist.is_empty()
});
}
}
}
fn enabled(s: &Server) -> bool {
s.conf_bool("account_registration", false) && s.conf("acctregister_registerurl").is_some()
}

View file

@ -112,6 +112,7 @@ pub fn default_modules() -> Vec<Box<dyn Module>> {
Box::new(operprefix::OperPrefix),
Box::new(permchannels::PermChannels::default()),
Box::new(chathistory::ChatHistoryGc),
Box::new(account_registration::AcctRegGc),
]
}