mirror of
https://github.com/solero/houdini.git
synced 2024-11-14 14:48:21 +00:00
Initial login handlers
This commit is contained in:
parent
8412f325ff
commit
fcff0cd405
@ -184,7 +184,7 @@ class VersionChkConverter(IConverter):
|
|||||||
description = """Used for checking the verChk version number"""
|
description = """Used for checking the verChk version number"""
|
||||||
|
|
||||||
async def convert(self, ctx):
|
async def convert(self, ctx):
|
||||||
return ctx.argument[0].get('v')
|
return int(ctx.argument[0].get('v'))
|
||||||
|
|
||||||
|
|
||||||
class ConnectedPenguinConverter(IConverter):
|
class ConnectedPenguinConverter(IConverter):
|
||||||
|
@ -9,7 +9,9 @@ class Crypto:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def hash(undigested):
|
def hash(undigested):
|
||||||
return hashlib.md5(undigested.encode('utf-8')).hexdigest()
|
if type(undigested) == str:
|
||||||
|
undigested = undigested.encode('utf-8')
|
||||||
|
return hashlib.md5(undigested).hexdigest()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_random_key():
|
def generate_random_key():
|
||||||
|
@ -66,6 +66,11 @@ class Penguin(db.Model):
|
|||||||
RejectionDe = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
|
RejectionDe = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
|
||||||
RejectionRu = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
|
RejectionRu = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def approval(self):
|
||||||
|
return int('{}{}0{}{}{}{}'.format(self.ApprovalRu * 1, self.ApprovalDe * 1, self.ApprovalEs * 1,
|
||||||
|
self.ApprovalFr * 1, self.ApprovalPt * 1, self.ApprovalEn * 1), 2)
|
||||||
|
|
||||||
|
|
||||||
class ActivationKey(db.Model):
|
class ActivationKey(db.Model):
|
||||||
__tablename__ = 'activation_key'
|
__tablename__ = 'activation_key'
|
||||||
|
@ -1,14 +1,119 @@
|
|||||||
from Houdini import Handlers
|
from Houdini import Handlers
|
||||||
from Houdini.Handlers import XMLPacket
|
from Houdini.Handlers import XMLPacket, Login
|
||||||
from Houdini.Converters import CredentialsConverter, VersionChkConverter
|
from Houdini.Converters import CredentialsConverter
|
||||||
|
from Houdini.Data.Penguin import Penguin
|
||||||
|
from Houdini.Data.Buddy import BuddyList
|
||||||
|
from Houdini.Data.Moderator import Ban
|
||||||
|
from Houdini.Crypto import Crypto
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import bcrypt
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import config
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
@Handlers.handler(XMLPacket('login'))
|
@Handlers.handler(XMLPacket('login'))
|
||||||
async def handle_login(p, credentials: CredentialsConverter):
|
async def handle_login(p, credentials: CredentialsConverter):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
|
login_timestamp = time.time()
|
||||||
username, password = credentials
|
username, password = credentials
|
||||||
p.logger.info('{}:{} is logging in!'.format(username, password))
|
p.logger.info('{} is logging in!'.format(username))
|
||||||
|
|
||||||
|
data = await Penguin.query.where(Penguin.Username == username).gino.first()
|
||||||
|
|
||||||
@Handlers.handler(XMLPacket('verChk'))
|
if data is None:
|
||||||
async def handle_version_check(p, version: VersionChkConverter):
|
p.logger.info('{} failed to login: penguin does not exist')
|
||||||
p.logger.info('Version: {}'.format(version))
|
await p.send_error_and_disconnect(100)
|
||||||
|
|
||||||
|
password_correct = await loop.run_in_executor(None, bcrypt.checkpw,
|
||||||
|
password.encode('utf-8'), data.Password.encode('utf-8'))
|
||||||
|
|
||||||
|
ip_addr = p.peer_name[0]
|
||||||
|
|
||||||
|
if not password_correct:
|
||||||
|
p.logger.info('{} failed to login: incorrect password'.format(username))
|
||||||
|
|
||||||
|
if ip_addr in p.server.login_attempts:
|
||||||
|
last_failed_attempt, failure_count = p.server.login_attempts[ip_addr]
|
||||||
|
|
||||||
|
failure_count = 1 if login_timestamp - last_failed_attempt >= p.server.server_config['LoginFailureTimer'] \
|
||||||
|
else failure_count + 1
|
||||||
|
|
||||||
|
p.server.login_attempts[ip_addr] = [login_timestamp, failure_count]
|
||||||
|
|
||||||
|
if failure_count >= p.server.server_config['LoginFailureLimit']:
|
||||||
|
return await p.send_error_and_disconnect(150)
|
||||||
|
else:
|
||||||
|
p.server.login_attempts[ip_addr] = [login_timestamp, 1]
|
||||||
|
|
||||||
|
return await p.send_error_and_disconnect(101)
|
||||||
|
|
||||||
|
if ip_addr in p.server.login_attempts:
|
||||||
|
previous_attempt, failure_count = p.server.login_attempts[ip_addr]
|
||||||
|
|
||||||
|
max_attempts_exceeded = failure_count >= p.server.server_config['LoginFailureLimit']
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
del p.server.login_attempts[ip_addr]
|
||||||
|
|
||||||
|
if not data.Active:
|
||||||
|
return await p.send_error_and_disconnect(900)
|
||||||
|
|
||||||
|
if data.Permaban:
|
||||||
|
return await p.send_error_and_disconnect(603)
|
||||||
|
|
||||||
|
active_ban = await Ban.query.where(Ban.PenguinID == data.ID and Ban.Expires >= datetime.now()).gino.first()
|
||||||
|
|
||||||
|
if active_ban is not None:
|
||||||
|
hours_left = round((active_ban.Expires - datetime.now()).total_seconds() / 60 / 60)
|
||||||
|
|
||||||
|
if hours_left == 0:
|
||||||
|
return await p.send_error_and_disconnect(602)
|
||||||
|
else:
|
||||||
|
await p.send_error_and_disconnect(601, hours_left)
|
||||||
|
|
||||||
|
p.logger.info('{} has logged in successfully'.format(username))
|
||||||
|
|
||||||
|
random_key = Crypto.generate_random_key()
|
||||||
|
login_key = Crypto.hash(random_key[::-1])
|
||||||
|
confirmation_hash = Crypto.hash(os.urandom(24))
|
||||||
|
|
||||||
|
await p.server.redis.setex('{}.lkey'.format(data.ID), p.server.server_config['KeyTTL'], login_key)
|
||||||
|
await p.server.redis.setex('{}.ckey'.format(data.ID), p.server.server_config['KeyTTL'], confirmation_hash)
|
||||||
|
|
||||||
|
buddy_worlds = []
|
||||||
|
world_populations = []
|
||||||
|
|
||||||
|
servers_config = config.servers
|
||||||
|
|
||||||
|
for server_name, server_config in servers_config.items():
|
||||||
|
if server_config['World']:
|
||||||
|
server_population = await p.server.redis.get('{}.population'.format(server_name))
|
||||||
|
server_population = int(server_population) / (server_config['Capacity'] / 6) if server_population else 0
|
||||||
|
|
||||||
|
server_players = await p.server.redis.smembers('{}.players'.format(server_name))
|
||||||
|
|
||||||
|
world_populations.append('{},{}'.format(server_config['Id'], server_population))
|
||||||
|
|
||||||
|
if not len(server_players) > 0:
|
||||||
|
p.logger.debug('Skipping buddy iteration for {}'.format(server_name))
|
||||||
|
continue
|
||||||
|
|
||||||
|
buddies = await BuddyList.select('BuddyID').where(BuddyList.PenguinID == data.ID).gino.all()
|
||||||
|
for buddy_id in buddies:
|
||||||
|
if str(buddy_id) in server_players:
|
||||||
|
buddy_worlds.append(server_config['Id'])
|
||||||
|
break
|
||||||
|
|
||||||
|
raw_login_data = '|'.join([str(data.ID), str(data.ID), data.Username, login_key, str(data.approval), '1'])
|
||||||
|
await p.send_xt('l', raw_login_data, confirmation_hash, 'friendsKey', '|'.join(world_populations), data.Email)
|
||||||
|
|
||||||
|
handle_version_check = Login.handle_version_check
|
||||||
|
handle_random_key = Login.handle_random_key
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
from Houdini import Handlers
|
||||||
|
from Houdini.Handlers import XMLPacket
|
||||||
|
from Houdini.Converters import VersionChkConverter
|
||||||
|
|
||||||
|
|
||||||
|
@Handlers.handler(XMLPacket('verChk'))
|
||||||
|
async def handle_version_check(p, version: VersionChkConverter):
|
||||||
|
if not version == 153:
|
||||||
|
await p.send_xml({'body': {'action': 'apiKO', 'r': '0'}})
|
||||||
|
await p.close()
|
||||||
|
else:
|
||||||
|
await p.send_xml({'body': {'action': 'apiOK', 'r': '0'}})
|
||||||
|
|
||||||
|
|
||||||
|
@Handlers.handler(XMLPacket('rndK'))
|
||||||
|
async def handle_random_key(p, data):
|
||||||
|
await p.send_xml({'body': {'action': 'rndK', 'r': '-1'}, 'k': 'houdini'})
|
@ -68,6 +68,8 @@ class HoudiniFactory:
|
|||||||
self.penguins_by_id = {}
|
self.penguins_by_id = {}
|
||||||
self.penguins_by_username = {}
|
self.penguins_by_username = {}
|
||||||
|
|
||||||
|
self.login_attempts = {}
|
||||||
|
|
||||||
self.xt_listeners, self.xml_listeners = {}, {}
|
self.xt_listeners, self.xml_listeners = {}, {}
|
||||||
self.commands = {}
|
self.commands = {}
|
||||||
self.plugins = {}
|
self.plugins = {}
|
||||||
|
Loading…
Reference in New Issue
Block a user