From 8ab0de26908448b9d294e814d6871a65dfd9ea31 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 24 Oct 2026 11:25:17 +0200 Subject: [PATCH] Keep wrong join-code streak when a correct code is tried (#1174) Fixes #1088 Co-authored-by: Claude Haiku 5.5 --- apps/figcraft-server/src/abuse.rs | 6 +++--- apps/figcraft-server/src/codes_tests.rs | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/figcraft-server/src/abuse.rs b/apps/figcraft-server/src/abuse.rs index baf1882b..2ea939c3 100644 --- a/apps/figcraft-server/src/abuse.rs +++ b/apps/figcraft-server/src/abuse.rs @@ -120,15 +120,15 @@ impl Abuse { open } - /// `ip` tried a join code that was right (`ok`) or wrong: a right one forgives the wrong ones - /// before it; enough wrong ones in a row lock the address out. + /// `ip` tried a join code that was right (`ok`) or wrong: a right one doesn't forgive the wrong + /// ones before it (they only decay with time); enough wrong ones lock the address out. pub fn code_tried(&mut self, ip: IpAddr, ok: bool, now: Instant) { if !ok { self.wrong_codes.take(now); } for (k, times) in ip_blocks(ip) { let a = self.address(k, f64::from(times), now); - if ok || now.saturating_duration_since(a.wrong_at) > CODE_LOCKOUT { + if now.saturating_duration_since(a.wrong_at) > CODE_LOCKOUT { a.wrong = 0; } if !ok { diff --git a/apps/figcraft-server/src/codes_tests.rs b/apps/figcraft-server/src/codes_tests.rs index 6392e552..1e440a32 100644 --- a/apps/figcraft-server/src/codes_tests.rs +++ b/apps/figcraft-server/src/codes_tests.rs @@ -262,17 +262,21 @@ fn the_limits_on_codes_over_time() { let t0 = Instant::now(); let me = ip("198.51.100.9"); let mut abuse = Abuse::new(AbuseConfig { open: false, connects_per_minute: 30, publishes_per_hour: 10, messages_per_second: 200 }); - // A right code forgives the wrong ones before it. + // A right code, even from a neighbour in the same /64, doesn't forgive the wrong ones. + let a = ip("2001:db8:1:2::1"); + let b = ip("2001:db8:1:2::2"); for _ in 0..WRONG_CODES - 1 { + abuse.code_tried(a, false, t0); + } + abuse.code_tried(b, true, t0); + abuse.code_tried(a, true, t0); + assert_eq!(abuse.code_locked(a, t0), None); + abuse.code_tried(a, false, t0); + assert_eq!(abuse.code_locked(a, t0), Some(CODE_LOCKOUT)); + // Wrong codes: locked for the lockout, then free again. + for _ in 0..WRONG_CODES { abuse.code_tried(me, false, t0); } - abuse.code_tried(me, true, t0); - for _ in 0..WRONG_CODES - 1 { - abuse.code_tried(me, false, t0); - } - assert_eq!(abuse.code_locked(me, t0), None); - // One more: locked for the lockout, then free again. - abuse.code_tried(me, false, t0); assert_eq!(abuse.code_locked(me, t0), Some(CODE_LOCKOUT)); assert!(abuse.code_locked(me, t0 + CODE_LOCKOUT - Duration::from_secs(1)).is_some()); assert_eq!(abuse.code_locked(me, t0 + CODE_LOCKOUT), None);