mirror of
https://github.com/solero/houdini.git
synced 2025-10-18 05:18:13 +00:00
Initial support for multiple clients and cross-client play
This commit is contained in:
@@ -3,6 +3,7 @@ import enum
|
||||
import itertools
|
||||
import importlib
|
||||
import sys
|
||||
import config
|
||||
from types import FunctionType
|
||||
|
||||
from houdini.converters import _listener, _ArgumentDeserializer, get_converter, do_conversion, _ConverterContext
|
||||
@@ -51,7 +52,7 @@ class Priority(enum.Enum):
|
||||
|
||||
class _Listener(_ArgumentDeserializer):
|
||||
|
||||
__slots__ = ['priority', 'packet', 'overrides', 'before', 'after']
|
||||
__slots__ = ['priority', 'packet', 'overrides', 'before', 'after', 'client_type']
|
||||
|
||||
def __init__(self, packet, callback, **kwargs):
|
||||
super().__init__(packet.id, callback, **kwargs)
|
||||
@@ -60,6 +61,7 @@ class _Listener(_ArgumentDeserializer):
|
||||
self.priority = kwargs.get('priority', Priority.Low)
|
||||
self.before = kwargs.get('before')
|
||||
self.after = kwargs.get('after')
|
||||
self.client_type = kwargs.get('client')
|
||||
|
||||
self.overrides = kwargs.get('overrides', [])
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import config
|
||||
|
||||
from houdini import handlers
|
||||
from houdini import handlers, ClientType
|
||||
from houdini.handlers import XMLPacket
|
||||
from houdini.converters import VersionChkConverter
|
||||
|
||||
@@ -10,7 +10,15 @@ from houdini.data.buddy import BuddyList
|
||||
@handlers.handler(XMLPacket('verChk'))
|
||||
@handlers.allow_once
|
||||
async def handle_version_check(p, version: VersionChkConverter):
|
||||
if not version == 153:
|
||||
if config.client['MultiClientSupport']:
|
||||
if config.client['LegacyVersionChk'] == version:
|
||||
p.client_type = ClientType.Legacy
|
||||
elif config.client['VanillaVersionChk'] == version:
|
||||
p.client_type = ClientType.Vanilla
|
||||
elif config.client['DefaultVersionChk'] == version:
|
||||
p.client_type = config.client['DefaultClientType']
|
||||
|
||||
if p.client_type is None:
|
||||
await p.send_xml({'body': {'action': 'apiKO', 'r': '0'}})
|
||||
await p.close()
|
||||
else:
|
||||
@@ -20,7 +28,7 @@ async def handle_version_check(p, version: VersionChkConverter):
|
||||
@handlers.handler(XMLPacket('rndK'))
|
||||
@handlers.allow_once
|
||||
async def handle_random_key(p, data):
|
||||
await p.send_xml({'body': {'action': 'rndK', 'r': '-1'}, 'k': 'houdini'})
|
||||
await p.send_xml({'body': {'action': 'rndK', 'r': '-1'}, 'k': config.client['AuthStaticKey']})
|
||||
|
||||
|
||||
async def get_server_presence(p, pid):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from houdini import handlers
|
||||
from houdini import handlers, ClientType
|
||||
from houdini.handlers import XMLPacket, login
|
||||
from houdini.handlers.login import get_server_presence
|
||||
from houdini.converters import Credentials
|
||||
@@ -27,7 +27,7 @@ async def handle_login(p, credentials: Credentials):
|
||||
data = await Penguin.query.where(Penguin.username == username).gino.first()
|
||||
|
||||
if data is None:
|
||||
p.logger.info('{} failed to login: penguin does not exist')
|
||||
p.logger.info('{} failed to login: penguin does not exist'.format(username))
|
||||
return await p.send_error_and_disconnect(100)
|
||||
|
||||
password_correct = await loop.run_in_executor(None, bcrypt.checkpw,
|
||||
@@ -84,16 +84,19 @@ async def handle_login(p, credentials: Credentials):
|
||||
confirmation_hash = Crypto.hash(os.urandom(24))
|
||||
|
||||
tr = p.server.redis.multi_exec()
|
||||
tr.setex('{}.lkey'.format(data.id), p.server.server_config['KeyTTL'], login_key)
|
||||
tr.setex('{}.ckey'.format(data.id), p.server.server_config['KeyTTL'], confirmation_hash)
|
||||
tr.setex('{}.lkey'.format(data.username), p.server.server_config['KeyTTL'], login_key)
|
||||
tr.setex('{}.ckey'.format(data.username), p.server.server_config['KeyTTL'], confirmation_hash)
|
||||
await tr.execute()
|
||||
|
||||
world_populations, buddy_presence = await get_server_presence(p, data.id)
|
||||
|
||||
raw_login_data = '|'.join([str(data.id), str(data.id), data.username, login_key, str(data.approval),
|
||||
str(data.rejection)])
|
||||
await p.send_xt('l', raw_login_data, confirmation_hash, '', world_populations, buddy_presence,
|
||||
data.email)
|
||||
if p.client_type == ClientType.Vanilla:
|
||||
raw_login_data = '|'.join([str(data.id), str(data.id), data.username, login_key, str(data.approval),
|
||||
str(data.rejection)])
|
||||
await p.send_xt('l', raw_login_data, confirmation_hash, '', world_populations, buddy_presence,
|
||||
data.email)
|
||||
else:
|
||||
await p.send_xt('l', data.id, login_key, world_populations, buddy_presence)
|
||||
|
||||
handle_version_check = login.handle_version_check
|
||||
handle_random_key = login.handle_random_key
|
||||
|
@@ -1,8 +1,11 @@
|
||||
from houdini import handlers
|
||||
import config
|
||||
|
||||
from houdini import handlers, ClientType
|
||||
from houdini.handlers import XMLPacket, login
|
||||
from houdini.converters import WorldCredentials
|
||||
from houdini.converters import WorldCredentials, Credentials
|
||||
from houdini.data.penguin import Penguin
|
||||
from houdini.data.moderator import Ban
|
||||
from houdini.crypto import Crypto
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
@@ -10,20 +13,26 @@ handle_version_check = login.handle_version_check
|
||||
handle_random_key = login.handle_random_key
|
||||
|
||||
|
||||
@handlers.handler(XMLPacket('login'))
|
||||
@handlers.handler(XMLPacket('login'), client=ClientType.Vanilla)
|
||||
@handlers.allow_once
|
||||
@handlers.depends_on_packet(XMLPacket('verChk'), XMLPacket('rndK'))
|
||||
async def handle_login(p, credentials: WorldCredentials):
|
||||
tr = p.server.redis.multi_exec()
|
||||
tr.get('{}.lkey'.format(credentials.id))
|
||||
tr.get('{}.ckey'.format(credentials.id))
|
||||
tr.delete('{}.lkey'.format(credentials.id), '{}.ckey'.format(credentials.id))
|
||||
tr.get('{}.lkey'.format(credentials.username))
|
||||
tr.get('{}.ckey'.format(credentials.username))
|
||||
tr.delete('{}.lkey'.format(credentials.username), '{}.ckey'.format(credentials.username))
|
||||
login_key, confirmation_hash, _ = await tr.execute()
|
||||
|
||||
if login_key is None or confirmation_hash is None:
|
||||
return await p.close()
|
||||
|
||||
if login_key.decode() != credentials.login_key or confirmation_hash.decode() != credentials.confirmation_hash:
|
||||
login_key = login_key.decode()
|
||||
login_hash = Crypto.encrypt_password(login_key + config.client['AuthStaticKey']) + login_key
|
||||
|
||||
if credentials.client_key != login_hash:
|
||||
return await p.close()
|
||||
|
||||
if login_key != credentials.login_key or confirmation_hash.decode() != credentials.confirmation_hash:
|
||||
return await p.close()
|
||||
|
||||
data = await Penguin.get(credentials.id)
|
||||
@@ -47,5 +56,5 @@ async def handle_login(p, credentials: WorldCredentials):
|
||||
p.logger.info('{} logged in successfully'.format(data.username))
|
||||
|
||||
p.data = data
|
||||
p.login_key = credentials.login_key
|
||||
p.login_key = login_key
|
||||
await p.send_xt('l')
|
||||
|
Reference in New Issue
Block a user