Move login flood control to redis storage

This commit is contained in:
Ben 2019-08-05 19:17:05 +01:00
parent d31105ac29
commit ffdc515880
2 changed files with 13 additions and 19 deletions

View File

@ -10,7 +10,6 @@ import asyncio
import bcrypt import bcrypt
import time import time
import os import os
import config
from datetime import datetime from datetime import datetime
@ -29,41 +28,38 @@ async def handle_login(p, credentials: Credentials):
if data is None: if data is None:
p.logger.info('{} failed to login: penguin does not exist') p.logger.info('{} failed to login: penguin does not exist')
await p.send_error_and_disconnect(100) return await p.send_error_and_disconnect(100)
password_correct = await loop.run_in_executor(None, bcrypt.checkpw, password_correct = await loop.run_in_executor(None, bcrypt.checkpw,
password.encode('utf-8'), data.password.encode('utf-8')) password.encode('utf-8'), data.password.encode('utf-8'))
ip_addr = p.peer_name[0] ip_addr = p.peer_name[0]
flood_key = '{}.flood'.format(ip_addr)
if not password_correct: if not password_correct:
p.logger.info('{} failed to login: incorrect password'.format(username)) p.logger.info('{} failed to login: incorrect password'.format(username))
if ip_addr in p.server.login_attempts: if await p.server.redis.exists(flood_key):
last_failed_attempt, failure_count = p.server.login_attempts[ip_addr] tr = p.server.redis.multi_exec()
tr.incr(flood_key)
failure_count = 1 if login_timestamp - last_failed_attempt >= p.server.server_config['LoginFailureTimer'] \ tr.expire(flood_key, p.server.server_config['LoginFailureTimer'])
else failure_count + 1 failure_count, _ = await tr.execute()
p.server.login_attempts[ip_addr] = [login_timestamp, failure_count]
if failure_count >= p.server.server_config['LoginFailureLimit']: if failure_count >= p.server.server_config['LoginFailureLimit']:
return await p.send_error_and_disconnect(150) return await p.send_error_and_disconnect(150)
else: else:
p.server.login_attempts[ip_addr] = [login_timestamp, 1] await p.server.redis.setex(flood_key, p.server.server_config['LoginFailureTimer'], 1)
return await p.send_error_and_disconnect(101) return await p.send_error_and_disconnect(101)
if ip_addr in p.server.login_attempts: failure_count = await p.server.redis.get(flood_key)
previous_attempt, failure_count = p.server.login_attempts[ip_addr] if failure_count:
max_attempts_exceeded = int(failure_count) >= p.server.server_config['LoginFailureLimit']
max_attempts_exceeded = failure_count >= p.server.server_config['LoginFailureLimit'] if max_attempts_exceeded:
timer_surpassed = (login_timestamp - previous_attempt) > p.server.server_config['LoginFailureTimer']
if max_attempts_exceeded and not timer_surpassed:
return await p.send_error_and_disconnect(150) return await p.send_error_and_disconnect(150)
else: else:
del p.server.login_attempts[ip_addr] await p.server.redis.delete(flood_key)
if not data.active: if not data.active:
return await p.send_error_and_disconnect(900) return await p.send_error_and_disconnect(900)

View File

@ -70,8 +70,6 @@ class Houdini:
self.penguins_by_id = {} self.penguins_by_id = {}
self.penguins_by_username = {} self.penguins_by_username = {}
self.login_attempts = {}
self.xt_listeners = XTListenerManager(self) self.xt_listeners = XTListenerManager(self)
self.xml_listeners = XMLListenerManager(self) self.xml_listeners = XMLListenerManager(self)
self.commands = CommandManager(self) self.commands = CommandManager(self)