Exemple #1
0
async def handle_spotify_callback(query_params: Dict, config: Config):
    if query_params.get("error"):
        raise err.failed_dependency(
            "Please allow access to your Spotify account to proceed")
    token = query_params.get("state")
    if not token:
        raise err.bad_request(
            "'state' query parameter required but not provided")
    try:
        claims = jwt.get_claims_from_jwt(token, config.jwt_key(), jwt.Aud.API)
        user_id = int(claims["sub"])
    except Exception as e:
        logger.debug("Failed to decode state as JWT: %s", e)
        raise err.bad_request("Invalid state from Spotify callback")

    code = query_params.get("code")
    if not code:
        raise err.failed_dependency(
            "Spotify authorization failed; no valid code returned")

    request = {
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": config.spotify_redirect(),
        "client_id": config.spotify_client_id(),
        "client_secret": config.spotify_secret()
    }

    try:
        session = config.get_session()
        tokens_response = await config.get_spotify_api().request_tokens(request
                                                                        )

        access_token = tokens_response["access_token"]
        refresh_token = tokens_response["refresh_token"]
        created_at = datetime.utcnow()
        expires_in = tokens_response["expires_in"]

        spotify_user_data = await config.get_spotify_api().spotify_user_data(
            access_token)
        spotify_user_id = spotify_user_data["id"]
    except Exception as e:
        logger.exception("Failed to authorize user(id=%s): %s", user_id, e)
        raise err.internal_server_error(
            "Something went wrong logging in with Spotify")

    try:
        async with config.get_database_connection() as db:
            await spotify_token.SpotifyTokenPersistence(db).upsert_token(
                user_id, spotify_user_id, access_token, refresh_token,
                created_at, expires_in)
    except Exception as e:
        logger.exception("Failed to upsert Spotify token for user(id=%s): %s",
                         user_id, e)
        raise err.internal_server_error()

    return {"success": True}
Exemple #2
0
def _handle_token_result(token_result: Union[str, GetTokenError]) -> str:
    if isinstance(token_result, GetTokenError):
        if token_result == GetTokenError.EXPIRED:
            raise err.failed_dependency("Spotify token has expired")
        elif token_result == GetTokenError.NOT_AUTHED:
            raise err.failed_dependency(
                "User must be authorized with Spotify to perform this operation"
            )
        elif token_result == GetTokenError.API_ERROR:
            raise err.internal_server_error(token_result.value)
        else:
            raise err.internal_server_error()
    return token_result
Exemple #3
0
async def register_user(first_name: str, last_name: str, email: str,
                        password: str, config: Config):
    if not check_password(password):
        raise err.bad_request(
            "Please provide a password at least 8 characters long, containing letters and symbols"
        )

    password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
    try:
        async with config.get_database_connection() as db:
            user_persistence = users.UsersPersistence(db)
            created_user_id = await user_persistence.create_user(
                first_name, last_name, email, password_hash)
            user = await user_persistence.get_user_by_id(created_user_id)
    except IntegrityError as e:
        logger.debug("IntegrityError registering user with email %s: %s",
                     email, e)
        raise err.bad_request("Email address is already in use")
    except Exception as e:
        logger.exception("Failed to get user with email %s from db: %s", email,
                         e)
        raise err.internal_server_error()

    return {
        "token": jwt.generate_jwt(user["user_id"], jwt.Aud.AUTH,
                                  config.jwt_key())
    }
Exemple #4
0
async def login(email: str, password: str, config: Config) -> Dict:
    """
    Get user from DB, check password hash matches and return a JWT token if so
    """
    try:
        async with config.get_database_connection() as db:
            user = await users.UsersPersistence(db).get_user_by_email(email)
    except Exception as e:
        logger.exception("Failed to get user with email %s from db: %s", email,
                         e)
        raise err.internal_server_error()

    auth_failed = err.unauthorized(
        "Failed to log you in with the provided credentials; please try again")
    if not user:
        logger.debug("User not found with email %s", email)
        raise auth_failed

    if not bcrypt.checkpw(password.encode(), user["password_hash"]):
        logger.debug("Incorrect password for user(id=%s)", user["user_id"])
        raise auth_failed

    return {
        "token": jwt.generate_jwt(user["user_id"], jwt.Aud.AUTH,
                                  config.jwt_key())
    }
Exemple #5
0
async def me(user_id: int, config: Config) -> Dict:
    try:
        async with config.get_database_connection() as db:
            get_user = users.UsersPersistence(db).get_user_by_id(user_id)
            get_joined_rooms = rooms.RoomPersistence(
                db).get_joined_rooms_by_user(user_id)
            get_token = spotify.get_valid_token_for_user(user_id, config)
            (user, joined_rooms,
             token) = await asyncio.gather(get_user,
                                           get_joined_rooms,
                                           get_token,
                                           return_exceptions=False)
    except Exception as e:
        logger.exception("Failed to get user(id=%s) from db: %s", user_id, e)
        raise err.internal_server_error()
    del user["password_hash"]
    user["rooms"] = joined_rooms
    user["authed_with_spotify"] = isinstance(token, str)
    return user