Rate-limit REPORT and REQUEST on the real host instead of the spoofable nick

This commit is contained in:
Jean Chevronnet 2026-07-19 13:39:03 +00:00
parent b2ffc01e52
commit 3648c48d2e
No known key found for this signature in database
8 changed files with 27 additions and 32 deletions

View file

@ -460,10 +460,10 @@ impl Db {
/// File an abuse report, rate-limited per reporter. Returns the new report's
/// id, or None if the reporter filed one too recently.
pub fn report_file(&mut self, reporter: &str, target: &str, reason: &str) -> Option<u64> {
pub fn report_file(&mut self, reporter: &str, cooldown_key: &str, target: &str, reason: &str) -> Option<u64> {
const COOLDOWN: u64 = 30;
let now = now();
let key = reporter.to_ascii_lowercase();
let key = cooldown_key.to_ascii_lowercase();
if self.report_times.get(&key).is_some_and(|&t| now.saturating_sub(t) < COOLDOWN) {
return None;
}
@ -516,10 +516,10 @@ impl Db {
/// Open a help-desk ticket, rate-limited per requester (shares the report
/// throttle namespace). Returns the new ticket's id, or None if too soon.
pub fn help_request(&mut self, requester: &str, message: &str) -> Option<u64> {
pub fn help_request(&mut self, requester: &str, cooldown_key: &str, message: &str) -> Option<u64> {
const COOLDOWN: u64 = 30;
let now = now();
let tkey = format!("help:{}", requester.to_ascii_lowercase());
let tkey = format!("help:{}", cooldown_key.to_ascii_lowercase());
if self.report_times.get(&tkey).is_some_and(|&t| now.saturating_sub(t) < COOLDOWN) {
return None;
}

View file

@ -344,8 +344,8 @@ impl Store for Db {
fn news(&self, kind: NewsKind) -> Vec<NewsView> {
Db::news(self, kind)
}
fn report_file(&mut self, reporter: &str, target: &str, reason: &str) -> Option<u64> {
Db::report_file(self, reporter, target, reason)
fn report_file(&mut self, reporter: &str, cooldown_key: &str, target: &str, reason: &str) -> Option<u64> {
Db::report_file(self, reporter, cooldown_key, target, reason)
}
fn report_close(&mut self, id: u64) -> bool {
Db::report_close(self, id)
@ -359,8 +359,8 @@ impl Store for Db {
fn report(&self, id: u64) -> Option<ReportView> {
Db::report(self, id)
}
fn help_request(&mut self, requester: &str, message: &str) -> Option<u64> {
Db::help_request(self, requester, message)
fn help_request(&mut self, requester: &str, cooldown_key: &str, message: &str) -> Option<u64> {
Db::help_request(self, requester, cooldown_key, message)
}
fn help_take(&mut self, id: u64, handler: &str) -> bool {
Db::help_take(self, id, handler)

View file

@ -218,7 +218,7 @@ impl Engine {
let threshold = self.db.channel(channel).map(|c| c.kickers.votekick).unwrap_or(0);
let botnick = self.db.channel(channel).and_then(|c| c.assigned_bot.clone());
let (Some(botnick), true) = (botnick, threshold > 0) else { return None };
let Some(botuid) = self.network.uid_by_nick(&botnick).map(str::to_string) else { return None };
let botuid = self.network.uid_by_nick(&botnick).map(str::to_string)?;
let Some(target_uid) = self.network.uid_by_nick(target_nick).map(str::to_string) else {
return Some(vec![NetAction::Privmsg { from: botuid, to: channel.to_string(), text: format!("There's no \x02{target_nick}\x02 here to vote on.") }]);
};