From 16648d47d1d80e7950dc3f14879d765d1fbc5613 Mon Sep 17 00:00:00 2001 From: Johnny Date: Tue, 2 Oct 2018 00:05:07 +0000 Subject: [PATCH] Adds logging of throttle activation and customizable message upon update. --- evennia/accounts/accounts.py | 2 +- evennia/server/throttle.py | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 1ce0f4d9f9..a6a29fab72 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -436,7 +436,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): logger.log_sec('Authentication Failure: %s (IP: %s).' % (username, ip)) # Update throttle - if ip: LOGIN_THROTTLE.update(ip) + if ip: LOGIN_THROTTLE.update(ip, 'Too many authentication failures') return None, errors diff --git a/evennia/server/throttle.py b/evennia/server/throttle.py index 56c88c63f2..944b7f880e 100644 --- a/evennia/server/throttle.py +++ b/evennia/server/throttle.py @@ -1,4 +1,5 @@ from collections import defaultdict, deque +from evennia.utils import logger import time class Throttle(object): @@ -50,22 +51,34 @@ class Throttle(object): if ip: return self.storage.get(ip, deque(maxlen=self.cache_size)) else: return self.storage - def update(self, ip): + def update(self, ip, failmsg='Exceeded threshold.'): """ - Store the time of the latest failure/ + Store the time of the latest failure. Args: ip (str): IP address of requestor + failmsg (str, optional): Message to display in logs upon activation + of throttle. Returns: None """ + # Get current status + previously_throttled = self.check(ip) + # Enforce length limits if not self.storage[ip].maxlen: self.storage[ip] = deque(maxlen=self.cache_size) self.storage[ip].append(time.time()) + + # See if this update caused a change in status + currently_throttled = self.check(ip) + + # If this makes it engage, log a single activation event + if (not previously_throttled and currently_throttled): + logger.log_sec('Throttle Activated: %s (IP: %s, %i hits in %i seconds.)' % (failmsg, ip, self.limit, self.timeout)) def check(self, ip): """