예제 #1
0
async def handle_login(p, credentials: WorldCredentials):
    async with p.server.redis.pipeline(transaction=True) as tr:
        tr.get(f'{credentials.username}.lkey')
        tr.get(f'{credentials.username}.ckey')
        tr.delete(f'{credentials.username}.lkey',
                  f'{credentials.username}.ckey')
        login_key, confirmation_hash, _ = await tr.execute()

    if login_key is None or confirmation_hash is None:
        return await p.close()

    login_key = login_key.decode()
    login_hash = Crypto.encrypt_password(login_key +
                                         p.server.config.auth_key) + 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)

    p.login_key = login_key
    await world_login(p, data)
예제 #2
0
async def handle_login(p, credentials: WorldCredentials):
    tr = p.server.redis.multi_exec()
    tr.get(f'{credentials.username}.lkey')
    tr.get(f'{credentials.username}.ckey')
    tr.delete(f'{credentials.username}.lkey', f'{credentials.username}.ckey')
    login_key, confirmation_hash, _ = await tr.execute()

    if login_key is None or confirmation_hash is None:
        return await p.close()

    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)

    p.login_key = login_key
    await world_login(p, data)
예제 #3
0
async def handle_login(p, credentials: WorldCredentials):
    if len(p.server.penguins_by_id) >= p.server.server_config['Capacity']:
        return await p.send_error_and_disconnect(103)

    tr = p.server.redis.multi_exec()
    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()

    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)

    if data is None:
        return await p.send_error_and_disconnect(100)

    if not data.active:
        return await p.close()

    if data.permaban:
        return await p.close()

    active_ban = await Ban.query.where((Ban.penguin_id == data.id) & (
        Ban.expires >= datetime.now())).gino.scalar()
    if active_ban is not None:
        return await p.close()

    if data.id in p.server.penguins_by_id:
        await p.server.penguins_by_id[data.id].close()

    p.logger.info('{} logged in successfully'.format(data.username))

    p.data = data
    p.login_key = login_key
    await p.send_xt('l')
예제 #4
0
async def handle_legacy_login(p, credentials: Credentials):
    tr = p.server.redis.multi_exec()
    tr.get(f'{credentials.username}.lkey')
    tr.delete(f'{credentials.username}.lkey', '{credentials.username}.ckey')
    login_key, _ = await tr.execute()

    login_key = login_key.decode()
    login_hash = Crypto.encrypt_password(
        login_key + config.client['AuthStaticKey']) + login_key

    if login_key is None or login_hash != credentials.password:
        return await p.close()

    data = await Penguin.query.where(Penguin.username == credentials.username
                                     ).gino.first()

    p.login_key = login_key
    await world_login(p, data)
예제 #5
0
async def handle_legacy_login(p, credentials: Credentials):
    async with p.server.redis.pipeline(transaction=True) as tr:
        tr.get(f'{credentials.username}.lkey')
        tr.delete(f'{credentials.username}.lkey',
                  f'{credentials.username}.ckey')
        login_key, _ = await tr.execute()

    try:
        login_key = login_key.decode()
    except AttributeError:
        return await p.close()

    login_hash = Crypto.encrypt_password(login_key +
                                         p.server.config.auth_key) + login_key

    if login_key is None or login_hash != credentials.password:
        return await p.close()

    data = await Penguin.query.where(Penguin.username == credentials.username
                                     ).gino.first()

    p.login_key = login_key
    await world_login(p, data)
예제 #6
0
async def handle_login(p, credentials: Credentials):
    loop = asyncio.get_event_loop()

    username, password = credentials.username, credentials.password
    p.logger.info('{} is logging in!'.format(username))

    data = await Penguin.query.where(Penguin.username == username).gino.first()

    if data is None:
        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, password.encode('utf-8'),
        data.password.encode('utf-8'))

    ip_addr = p.peer_name[0]
    flood_key = '{}.flood'.format(ip_addr)

    if not password_correct:
        p.logger.info(
            '{} failed to login: incorrect password'.format(username))

        if await p.server.redis.exists(flood_key):
            tr = p.server.redis.multi_exec()
            tr.incr(flood_key)
            tr.expire(flood_key, p.server.server_config['LoginFailureTimer'])
            failure_count, _ = await tr.execute()

            if failure_count >= p.server.server_config['LoginFailureLimit']:
                return await p.send_error_and_disconnect(150)
        else:
            await p.server.redis.setex(
                flood_key, p.server.server_config['LoginFailureTimer'], 1)

        return await p.send_error_and_disconnect(101)

    failure_count = await p.server.redis.get(flood_key)
    if failure_count:
        max_attempts_exceeded = int(
            failure_count) >= p.server.server_config['LoginFailureLimit']

        if max_attempts_exceeded:
            return await p.send_error_and_disconnect(150)
        else:
            await p.server.redis.delete(flood_key)

    preactivation_hours = 0
    if not data.active:
        preactivation_expiry = data.registration_date + timedelta(days=7)
        preactivation_expiry = preactivation_expiry - datetime.now()
        preactivation_hours = preactivation_expiry.total_seconds() // 3600
        if preactivation_hours <= 0 or p.client_type == ClientType.Legacy:
            return await p.send_error_and_disconnect(900)

    if data.permaban:
        return await p.send_error_and_disconnect(603)

    if data.grounded:
        return await p.send_error_and_disconnect(913)

    if data.timer_active:
        if not data.timer_start < datetime.now().time() < data.timer_end:
            return await p.send_error_and_disconnect(911, data.timer_start,
                                                     data.timer_end)

        if await data.minutes_played_today >= data.timer_total.total_seconds(
        ) // 60:
            return await p.send_error_and_disconnect(910, data.timer_total)

    active_ban = await Ban.query.where(Ban.penguin_id == 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))

    tr = p.server.redis.multi_exec()
    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)

    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)
        ])
        if not data.active:
            await p.send_xt('l', raw_login_data, confirmation_hash, '',
                            world_populations, buddy_presence, data.email,
                            int(preactivation_hours))
        else:
            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)
예제 #7
0
def encode_music_track(track_pattern):
    encoded_track_pattern = track_pattern[::-1]
    encoded_track_pattern = Crypto.hash(encoded_track_pattern)
    return encoded_track_pattern[16:32] + encoded_track_pattern[0:16]
예제 #8
0
async def handle_login(p, credentials: Credentials):
    loop = asyncio.get_event_loop()

    username, password = credentials.username, credentials.password
    p.logger.info(f'{username} is logging in!')

    data = await Penguin.query.where(func.lower(Penguin.username) == username
                                     ).gino.first()

    if data is None:
        p.logger.info(f'{username} failed to login: penguin does not exist')
        return 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]
    flood_key = f'{ip_addr}.flood'

    if not password_correct:
        p.logger.info(f'{username} failed to login: incorrect password')

        if await p.server.redis.exists(flood_key):
            async with p.server.redis.pipeline(transaction=True) as tr:
                tr.incr(flood_key)
                tr.expire(flood_key, p.server.config.login_failure_timer)
                failure_count, _ = await tr.execute()

            if failure_count >= p.server.config.login_failure_limit:
                return await p.send_error_and_disconnect(150)
        else:
            await p.server.redis.setex(flood_key,
                                       p.server.config.login_failure_timer, 1)

        return await p.send_error_and_disconnect(101)

    failure_count = await p.server.redis.get(flood_key)
    if failure_count:
        max_attempts_exceeded = int(
            failure_count) >= p.server.config.login_failure_limit

        if max_attempts_exceeded:
            return await p.send_error_and_disconnect(150)
        else:
            await p.server.redis.delete(flood_key)

    preactivation_hours = 0
    if not data.active:
        preactivation_expiry = data.registration_date + timedelta(
            days=p.server.config.preactivation_days)
        preactivation_expiry = preactivation_expiry - datetime.now()
        preactivation_hours = preactivation_expiry.total_seconds() // 3600
        if preactivation_hours <= 0 or p.client_type == ClientType.Legacy:
            return await p.send_error_and_disconnect(900)

    if data.permaban:
        return await p.send_error_and_disconnect(603)

    if data.grounded:
        return await p.send_error_and_disconnect(913)

    if data.timer_active:
        if not data.timer_start < datetime.now().time() < data.timer_end:
            return await p.send_error_and_disconnect(911, data.timer_start,
                                                     data.timer_end)

        minutes_played_today = await get_minutes_played_today(p)
        if minutes_played_today >= data.timer_total.total_seconds() // 60:
            return await p.send_error_and_disconnect(910, data.timer_total)

    active_ban = await Ban.query.where((Ban.penguin_id == data.id) & (
        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:
            return await p.send_error_and_disconnect(601, hours_left)

    p.logger.info(f'{username} has logged in successfully')

    random_key = Crypto.generate_random_key()
    login_key = Crypto.hash(random_key[::-1])
    confirmation_hash = Crypto.hash(os.urandom(24))

    async with p.server.redis.pipeline(transaction=True) as tr:
        tr.setex(f'{data.username}.lkey', p.server.config.auth_ttl, login_key)
        tr.setex(f'{data.username}.ckey', p.server.config.auth_ttl,
                 confirmation_hash)
        await tr.execute()

    world_populations, buddy_presence = await get_server_presence(p, data)

    if p.client_type == ClientType.Vanilla:
        raw_login_data = f'{data.id}|{data.id}|{data.username}|{login_key}|houdini|{data.approval}|{data.rejection}'
        if not data.active:
            await p.send_xt('l', raw_login_data, confirmation_hash, '',
                            world_populations, buddy_presence, data.email,
                            int(preactivation_hours))
        else:
            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, buddy_presence,
                        world_populations)