async def get_login(self, name: str, phash: str) -> Optional[Player]: # Only used cached results - the user should have # logged into bancho at least once. (This does not # mean they're logged in now). # Let them pass as a string for ease of access phash = phash.encode() bcrypt_cache = glob.cache['bcrypt'] if phash not in bcrypt_cache: # User has not logged in through bancho. return res = await glob.db.fetch( 'SELECT pw_hash FROM users ' 'WHERE name_safe = %s', [Player.make_safe(name)]) if not res: # Could not find user in the DB. return if bcrypt_cache[phash] != res['pw_hash']: # Password bcrypts do not match. return return await self.get_by_name(name)
async def get_by_name(self, name: str, sql: bool = False) -> Player: name_safe = Player.make_safe(name) for p in self.players: if p.safe_name == name_safe: return p if not sql: # don't fetch from sql # if not specified. return # try to get from sql. res = await glob.db.fetch( 'SELECT id, priv, silence_end ' 'FROM users WHERE name_safe = %s', [name_safe]) return Player(**res, name=name) if res else None
for p in self.players: if p not in immune: p.enqueue(data) async def get(self, sql: bool = False, **kwargs) -> Optional[Player]: for attr in ('token', 'id', 'name'): if val := kwargs.pop(attr, None): break else: raise ValueError( 'must provide valid kwarg (token, id, name) to get()') if attr == 'name': # name -> safe_name attr = 'safe_name' val = Player.make_safe(val) for p in self.players: if getattr(p, attr) == val: return p if not sql: # don't fetch from sql # if not specified return # try to get from sql. res = await glob.db.fetch( 'SELECT id, name, priv, pw_bcrypt, silence_end ' f'FROM users WHERE {attr} = %s', [val])
display_city = s[2] == '1' # Client hashes contain a few values useful to us. # [0]: md5(osu path) # [1]: adapters (network physical addresses delimited by '.') # [2]: md5(adapters) # [3]: md5(uniqueid) (osu! uninstall id) # [4]: md5(uniqueid2) (disk signature/serial num) client_hashes = s[3].split(':')[:-1] client_hashes.pop(1) # no need for non-md5 adapters pm_private = s[4] == '1' p_row = await glob.db.fetch( 'SELECT id, name, priv, pw_hash, silence_end ' 'FROM users WHERE name_safe = %s', [Player.make_safe(username)]) if not p_row: # no account by this name exists. return packets.userID(-1), 'no' # get our bcrypt cache. bcrypt_cache = glob.cache['bcrypt'] # their account exists in sql. # check their account status & credentials against db. if pw_hash in bcrypt_cache: # ~0.01 ms # cache hit - this saves ~200ms on subsequent logins. if bcrypt_cache[pw_hash] != p_row['pw_hash']: # password wrong
# Client hashes contain a few values useful to us. # [0]: md5(osu path) # [1]: adapters (network physical addresses delimited by '.') # [2]: md5(adapters) # [3]: md5(uniqueid) (osu! uninstall id) # [4]: md5(uniqueid2) (disk signature/serial num) client_hashes = s[3].split(':')[:-1] client_hashes.pop(1) # no need for non-md5 adapters pm_private = s[4] == '1' res = await glob.db.fetch( 'SELECT id, name, priv, pw_hash, ' 'silence_end FROM users ' 'WHERE name_safe = %s', [Player.make_safe(username)]) # get our bcrypt cache. bcrypt_cache = glob.cache['bcrypt'] if res: # account exists. # check their account status & credentials against db. if not res['priv'] & Privileges.Normal: return await packets.userID(-3), 'no' # password is incorrect. if pw_hash in bcrypt_cache: # ~0.01 ms # cache hit - this saves ~200ms on subsequent logins. if bcrypt_cache[pw_hash] != res['pw_hash']: return await packets.userID(-1), 'no'
# Client hashes contain a few values useful to us. # [0]: md5(osu path) # [1]: adapters (network physical addresses delimited by '.') # [2]: md5(adapters) # [3]: md5(uniqueid) (osu! uninstall id) # [4]: md5(uniqueid2) (disk signature/serial num) client_hashes = s[3].split(':')[:-1] client_hashes.pop(1) # no need for non-md5 adapters pm_private = s[4] == '1' user_info = await glob.db.fetch( 'SELECT id, name, priv, pw_bcrypt, silence_end ' 'FROM users WHERE safe_name = %s', [Player.make_safe(username)] ) if not user_info: # no account by this name exists. return packets.userID(-1), 'no' # get our bcrypt cache. bcrypt_cache = glob.cache['bcrypt'] pw_bcrypt = user_info['pw_bcrypt'].encode() user_info['pw_bcrypt'] = pw_bcrypt # check credentials against db. # algorithms like these are intentionally # designed to be slow; we'll cache the # results to speed up subsequent logins.