def login(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'username must be a string', 400 if not object_check(body, 'password', 'str'): return 'password must be a string', 400 # If username has an @-sign, then it's an email if '@' in body['username']: user = db_get('users', {'email': body['username'].strip().lower()}, True) else: user = db_get('users', {'username': body['username'].strip().lower()}) if not user: return 'invalid username/password', 403 if not check_password(body['password'], user['password']): return 'invalid username/password', 403 # If the number of bcrypt rounds has changed, create a new hash. new_hash = None if config['bcrypt_rounds'] != extract_bcrypt_rounds(user['password']): new_hash = hash(body['password'], make_salt()) cookie = make_salt() db_set( 'tokens', { 'id': cookie, 'username': user['username'], 'ttl': times() + session_length }) if new_hash: db_set( 'users', { 'username': user['username'], 'password': new_hash, 'last_login': timems() }) else: db_set('users', { 'username': user['username'], 'last_login': timems() }) resp = make_response({}) # We set the cookie to expire in a year, just so that the browser won't invalidate it if the same cookie gets renewed by constant use. # The server will decide whether the cookie expires. resp.set_cookie(cookie_name, value=cookie, httponly=True, secure=True, samesite='Lax', path='/', max_age=365 * 24 * 60 * 60) return resp
def login(): body = request.json # Validations if not isinstance(body, dict): return 'body must be an object', 400 if not isinstance(body.get('username'), str): return 'username must be a string', 400 if not isinstance(body.get('password'), str): return 'password must be a string', 400 # If username has an @-sign, then it's an email if '@' in body['username']: user = DATABASE.user_by_email(body['username']) else: user = DATABASE.user_by_username(body['username']) if not user: return 'invalid username/password', 403 if not check_password(body['password'], user['password']): return 'invalid username/password', 403 # If the number of bcrypt rounds has changed, create a new hash. new_hash = None if config['bcrypt_rounds'] != extract_bcrypt_rounds(user['password']): new_hash = hash(body['password'], make_salt()) cookie = make_salt() DATABASE.store_token({ 'id': cookie, 'username': user['username'], 'ttl': times() + session_length }) if new_hash: DATABASE.record_login(user['username'], new_hash) else: DATABASE.record_login(user['username']) resp = make_response({}) # We set the cookie to expire in a year, just so that the browser won't invalidate it if the same cookie gets renewed by constant use. # The server will decide whether the cookie expires. resp.set_cookie(TOKEN_COOKIE_NAME, value=cookie, httponly=True, secure=is_heroku(), samesite='Lax', path='/', max_age=365 * 24 * 60 * 60) # Remember the current user on the session. This is "new style" logins, which should ultimately # replace "old style" logins (with the cookie above), as it requires fewer database calls. remember_current_user(user) return resp
def test_extract_default_rounds(self): salt = bcrypt.gensalt().decode('utf-8') self.assertEqual(12, utils.extract_bcrypt_rounds(salt)) # def test_load_yaml_speed(self): # # n = 50 # # file = 'coursedata/adventures/hu.yaml' # # # # start = time.time() # # for _ in range(n): # # original_data = utils.load_yaml_uncached(file) # # original_seconds = time.time() - start # # # # start = time.time() # # for _ in range(n): # # cached_data = utils.load_yaml_pickled(file) # # cached_seconds = time.time() - start # # # # self.assertEqual(original_data, cached_data) # # print(f'YAML loading takes {original_seconds / n} seconds, unpickling takes {cached_seconds / n} ({original_seconds / cached_seconds}x faster)')
def test_extract_rounds(self): salt = bcrypt.gensalt(rounds=7).decode('utf-8') self.assertEqual(7, utils.extract_bcrypt_rounds(salt))