async def handle(self, p: Player) -> None: # XXX: this only sends when the client can see > 256 players, # so this probably won't have much use for private servers. # NOTE: i'm not exactly sure how bancho implements this and whether # i'm supposed to filter the users presences to send back with the # player's presence filter; i can add it in the future perhaps. for t in glob.players: if p is not t: p.enqueue(packets.userPresence(t))
data += packets.channelInfo(*c.basic_info) # fetch some of the player's # information from sql to be cached. await p.achievements_from_sql() await p.stats_from_sql_full() await p.friends_from_sql() if glob.config.server_build: # update their country data with # the IP from the login request. await p.fetch_geoloc(ip) # update our new player's stats, and broadcast them. user_data = (packets.userPresence(p) + packets.userStats(p)) data += user_data # o for online, or other for o in glob.players: # enqueue us to them o.enqueue(user_data) # enqueue them to us. data += packets.userPresence(o) data += packets.userStats(o) data += packets.mainMenuIcon() data += packets.friendsList(*p.friends) data += packets.silenceEnd(p.remaining_silence)
async def handle(self, p: Player) -> None: for pid in self.user_ids: if t := await glob.players.get(id=pid): p.enqueue(packets.userPresence(t))
data.extend(packets.channelJoin(c.name)) data.extend(packets.channelInfo(*c.basic_info)) # fetch some of the player's # information from sql to be cached. await p.stats_from_sql_full() await p.friends_from_sql() if glob.config.server_build: # update their country data with # the IP from the login request. await p.fetch_geoloc(ip) # update our new player's stats, and broadcast them. user_data = (packets.userPresence(p) + packets.userStats(p)) data.extend(user_data) # o for online, or other for o in glob.players: # enqueue us to them o.enqueue(user_data) # enqueue them to us. data.extend(packets.userPresence(o) + packets.userStats(o)) data.extend(packets.mainMenuIcon() + packets.friendsList(*p.friends) + packets.silenceEnd(p.remaining_silence)) # thank u osu for doing this by username rather than id
data += packets.channelInfo(*c.basic_info) # fetch some of the player's # information from sql to be cached. await p.stats_from_sql_full() await p.friends_from_sql() if glob.config.server_build: # update their country data with # the IP from the login request. await p.fetch_geoloc(ip) # update our new player's stats, and broadcast them. user_data = ( packets.userPresence(p) + packets.userStats(p) ) data += user_data # o for online, or other for o in glob.players: # enqueue us to them o.enqueue(user_data) # enqueue them to us. data += packets.userPresence(o) data += packets.userStats(o) data += packets.mainMenuIcon()
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)) resp = await make_response(bytes(data)) resp.headers['cho-token'] = token
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
def userPresenceRequest(p: Player, pr: PacketReader) -> None: for pid in pr.read(osuTypes.i32_list): if t := glob.players.get_by_id(pid): p.enqueue(packets.userPresence(t))