else: del user_info['clan_id'] del user_info['clan_rank'] clan = clan_rank = None # user_info: {id, name, priv, pw_bcrypt, silence_end} p = Player.login(user_info, utc_offset=utc_offset, osu_ver=s[0], pm_private=pm_private, login_time=login_time, clan=clan, clan_rank=clan_rank) data = bytearray(packets.userID(p.id)) data += packets.protocolVersion(19) data += packets.banchoPrivileges(p.bancho_priv | ClientPrivileges.Supporter) if first_login: data += packets.sendMessage( 'Ruji', 'Welcome to Iteki!\n\nIteki has a relatively unique experience from other servers as it is based on different source code and has many unique features.' '\n\nTo get started, you may be interested in knowing some useful commands:\n\n!req <rank/love> <set/map> - this is our request system:' '\nTo use this command you must first /np a map to Ruji (our bot) and you will then be able to request maps.' '\nThe choice between rank/love depends on whether you would like to request the map to be ranked or loved.\nThe map/set choices are depending on whether you want the entire set to be requested, or just the difficulty you did /np to.' '\n\nThats all you need to know for now.\nIf you have any issues please report them and have fun playing Iteki!\n\n', p.name, 1) if p.priv & Privileges.Nominator and not p.priv & Privileges.Staff: request = await glob.db.fetch('SELECT COUNT(id) AS count FROM requests' )
'login_time': login_time, 'clan': clan, 'clan_priv': clan_priv } p = Player( **user_info, # {id, name, priv, pw_bcrypt, silence_end} **extras # {utc_offset, osu_ver, pm_private, # login_time, clan, clan_priv} ) for mode in GameMode: p.recent_scores[mode] = None # TODO: sql? p.stats[mode] = None data = bytearray(packets.protocolVersion(19)) data += packets.userID(p.id) # *real* client privileges are sent with this packet, # then the user's apparent privileges are sent in the # userPresence packets to other players. we'll send # supporter along with the user's privileges here, # but not in userPresence (so that only donators # show up with the yellow name in-game, but everyone # gets osu!direct & other in-game perks). data += packets.banchoPrivileges(p.bancho_priv | ClientPrivileges.Supporter) data += packets.notification('Welcome back to the gulag!\n' f'Current build: v{glob.version}')
# sort out geoloc | SPEEEEEEEEEEEEEED gains ip = headers['X-Real-IP'] reader = database.Reader('ext/geoloc.mmdb') geoloc = reader.city(ip) country, user['lat'], user['lon'] = (geoloc.country.iso_code, geoloc.location.latitude, geoloc.location.longitude) user['country'] = country_codes[country] await glob.db.execute('UPDATE users SET country = %s WHERE id = %s', [country.lower(), user['id']]) # update country code in db friends = {row['user2'] async for row in glob.db.iterall('SELECT user2 FROM friends WHERE user1 = %s', [user['id']])} # select all friends from db ucache = glob.cache['user'] if str(token) not in ucache: ucache[str(token)] = user['id'] # cache token to use outside of this request data = bytearray(packets.userID(user['id'])) # initiate login by providing the user's id data += packets.protocolVersion(19) # no clue what this does data += packets.banchoPrivileges(1 << 4) # force priv to developer for now data += (packets.userPresence(user) + packets.userStats(user)) # provide user & other user's presence/stats (for f9 + user stats) data += packets.notification(f'Welcome to Asahi v{glob.version}') # send notification as indicator they've logged in i guess data += packets.channelInfoEnd() # no clue what this does either data += packets.menuIcon() # set main menu icon data += packets.friends(*friends) # send user friend list data += packets.silenceEnd(0) # force to 0 for now since silences arent a thing #data += packets.sendMessage(user['name'], 'test message lol so cool', user['name'], user['id']) # test message # add user to cache? pcache = glob.players pcache.append(user) for p in pcache: # enqueue other users to client data += (packets.userPresence(p) + packets.userStats(p))
p_row['priv'] |= int(Privileges.Verified) await glob.db.execute( 'UPDATE users SET priv = priv | %s WHERE id = %s', [p_row['priv'], p_row['id']]) p_row |= { 'utc_offset': utc_offset, 'pm_private': pm_private, 'osu_ver': osu_ver } p = Player(**p_row) data = bytearray( packets.userID(p.id) + packets.protocolVersion(19) + packets.banchoPrivileges(p.bancho_priv) + packets.notification('Welcome back to the gulag!\n' f'Current build: {glob.version}') + # tells osu! to load channels from config, i believe? packets.channelInfoEnd()) # channels for c in glob.channels: if not p.priv & c.read: continue # no priv to read # autojoinable channels if c.auto_join and await p.join_channel(c): # NOTE: p.join_channel enqueues channelJoin, but
async def login(): headers = request.headers # request headers, used for things such as user ip and agent if 'User-Agent' not in headers or headers['User-Agent'] != 'osu!': # request isn't sent from osu client, return nothing return if 'osu-token' not in headers: # sometimes a login request will be a re-connect attempt, in which case they will already have a token, if not: login the user data = await request.data # request data, used to get info such as username to login the user info = data.decode().split( '\n')[:-1] # format data so we can use it easier username = info[0] pw = info[1].encode( ) # password in md5 form, we will use this to compare against db's stored bcrypt later user = await glob.db.fetch( 'SELECT id, pw, country, name FROM users WHERE name = %s', [username]) if not user: # ensure user actually exists before attempting to do anything else log(f'User {username} does not exist.', Ansi.LRED) resp = await make_response(packets.userID(-1)) resp.headers['cho-token'] = 'no' return resp bcache = glob.cache[ 'bcrypt'] # get our cached bcrypts to potentially enhance speed pw_bcrypt = user['pw'].encode() if pw_bcrypt in bcache: if pw != bcache[ pw_bcrypt]: # compare provided md5 with the stored (cached) bcrypt to ensure they have provided the correct password log( f"{username}'s login attempt failed: provided an incorrect password", Ansi.LRED) resp = await make_response(packets.userID(-1)) resp.headers['cho-token'] = 'no' return resp else: if not bcrypt.checkpw( pw, pw_bcrypt ): # compare provided md5 with the stored bcrypt to ensure they have provided the correct password log( f"{username}'s login attempt failed: provided an incorrect password", Ansi.LRED) resp = await make_response(packets.userID(-1)) resp.headers['cho-token'] = 'no' return resp bcache[pw_bcrypt] = pw # cache pw for future token = uuid.uuid4() # generate token for client to use as auth ucache = glob.cache['user'] if str(token) not in ucache: ucache[str(token)] = user[ 'id'] # cache token to use outside of this request data = bytearray(packets.userID( user['id'])) # initiate login by providing the user's id data += packets.protocolVersion(19) # no clue what this does data += packets.banchoPrivileges( 1 << 4) # force priv to developer for now data += ( packets.userPresence(user) + packets.userStats(user) ) # provide user & other user's presence/stats (for f9 + user stats) data += packets.notification( f'Welcome to Asahi v{glob.version}' ) # send notification as indicator they've logged in iguess data += packets.channelInfoEnd() # no clue what this does either resp = await make_response(bytes(data)) resp.headers['cho-token'] = token log(f'{username} successfully logged in.', Ansi.GREEN) return resp # if we have made it this far then it's a reconnect attempt with token already provided user_token = headers['osu-token'] # client-provided token tcache = glob.cache[ 'user'] # get token/userid cache to see if we need to relog the user or not if user_token not in tcache: # user is logged in but token is not found? most likely a restart so we force a reconnection return packets.restartServer(0) user = await glob.db.fetch( 'SELECT id, pw, country, name FROM users WHERE id = %s', [tcache[user_token]]) body = await request.body # handle any packets the client has sent | doesn't really work **for now** for packet in BanchoPacketReader(body, glob.packets): await packet.handle(user) log(f'Handled packet {packet}') resp = await make_response(b'') resp.headers['Content-Type'] = 'text/html; charset=UTF-8' # ? return resp