diff --git a/classquiz/oauth/custom.py b/classquiz/oauth/custom.py index b9c0520..5d09d6b 100644 --- a/classquiz/oauth/custom.py +++ b/classquiz/oauth/custom.py @@ -6,15 +6,15 @@ import uuid import asyncpg -from fastapi import APIRouter, Request, HTTPException, Response -from classquiz.config import settings +from fastapi import APIRouter, HTTPException, Request, Response +from pydantic import BaseModel, ValidationError -from classquiz.db.models import User, UserAuthTypes from classquiz.auth import check_token +from classquiz.config import settings +from classquiz.db.models import User, UserAuthTypes from classquiz.helpers.avatar import gzipped_user_avatar from classquiz.oauth.authenticate_user import log_user_in, rememberme_check from classquiz.oauth.init_oauth import init_oauth -from pydantic import BaseModel, ValidationError settings = settings() @@ -47,17 +47,29 @@ class OpenIDResponse(BaseModel): @router.get("/login") async def openid_login(req: Request): - if settings.custom_openid_provider.client_id is None or settings.custom_openid_provider.client_secret is None: - raise HTTPException(status_code=501, detail="Custom-OAuth-Login isn't available on this server") + if ( + settings.custom_openid_provider.client_id is None + or settings.custom_openid_provider.client_secret is None + ): + raise HTTPException( + status_code=501, detail="Custom-OAuth-Login isn't available on this server" + ) oauth = init_oauth() - return await oauth.custom.authorize_redirect(req, f"{settings.root_address}/api/v1/users/oauth/custom/auth") + return await oauth.custom.authorize_redirect( + req, f"{settings.root_address}/api/v1/users/oauth/custom/auth" + ) @router.get("/auth") async def auth(request: Request, response: Response): - if settings.custom_openid_provider.client_id is None or settings.custom_openid_provider.client_secret is None: - raise HTTPException(status_code=501, detail="Custom-OAuth-Login isn't available on this server") + if ( + settings.custom_openid_provider.client_id is None + or settings.custom_openid_provider.client_secret is None + ): + raise HTTPException( + status_code=501, detail="Custom-OAuth-Login isn't available on this server" + ) access_token = request.cookies.get("access_token") rememberme_token = request.cookies.get("rememberme_token") if access_token is not None: @@ -68,7 +80,9 @@ async def auth(request: Request, response: Response): except HTTPException: pass if rememberme_token is not None: - return await rememberme_check(rememberme_token=rememberme_token, response=response) + return await rememberme_check( + rememberme_token=rememberme_token, response=response + ) oauth = init_oauth() user_data = await oauth.custom.authorize_access_token(request) @@ -77,29 +91,29 @@ async def auth(request: Request, response: Response): except (TypeError, ValidationError): raise HTTPException(status_code=401, detail="Something went wrong.") - try: - await User.objects.create( - id=uuid.uuid4(), - email=user_data.email, - username=user_data.preferred_username, - verified=user_data.email_verified, - auth_type=UserAuthTypes.CUSTOM, - google_uid=user_data.sub.hex, - avatar=gzipped_user_avatar(), - ) - # skipcq: PYL-W0703 - except asyncpg.exceptions.UniqueViolationError: - # Most likely a duplicate email/username, not UUID. - raise HTTPException(status_code=400, detail="User already exists.") - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) user = await User.objects.get_or_none( email=user_data.email, google_uid=user_data.sub.hex, auth_type=UserAuthTypes.CUSTOM, verified=True, ) - print(user_data) + if user is None: + try: + user = await User.objects.create( + id=uuid.uuid4(), + email=user_data.email, + username=user_data.preferred_username, + verified=user_data.email_verified, + auth_type=UserAuthTypes.CUSTOM, + google_uid=user_data.sub.hex, + avatar=gzipped_user_avatar(), + ) + # skipcq: PYL-W0703 + except asyncpg.exceptions.UniqueViolationError: + # Most likely a duplicate email/username, not UUID. + raise HTTPException(status_code=400, detail="User already exists.") + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) await log_user_in(user=user, request=request, response=response) response.headers.append("Location", "/account/login") diff --git a/classquiz/oauth/github.py b/classquiz/oauth/github.py index 29b72e4..ac15cd1 100644 --- a/classquiz/oauth/github.py +++ b/classquiz/oauth/github.py @@ -4,19 +4,19 @@ import uuid +from datetime import datetime import asyncpg import authlib.integrations.base_client -from fastapi import APIRouter, Request, HTTPException, Response +from fastapi import APIRouter, HTTPException, Request, Response +from fastapi.responses import RedirectResponse +from pydantic import BaseModel from classquiz.auth import check_token from classquiz.config import settings -from fastapi.responses import RedirectResponse from classquiz.db.models import User, UserAuthTypes -from pydantic import BaseModel from classquiz.helpers.avatar import gzipped_user_avatar from classquiz.oauth.authenticate_user import log_user_in, rememberme_check -from datetime import datetime from classquiz.oauth.init_oauth import init_oauth settings = settings() @@ -76,15 +76,21 @@ class GitHubOauthResponse(BaseModel): @router.get("/login") async def github_login(req: Request): if settings.github_client_id is None or settings.github_client_secret is None: - raise HTTPException(status_code=501, detail="GitHub-Login isn't available on this server") + raise HTTPException( + status_code=501, detail="GitHub-Login isn't available on this server" + ) oauth = init_oauth() - return await oauth.github.authorize_redirect(req, f"{settings.root_address}/api/v1/users/oauth/github/auth") + return await oauth.github.authorize_redirect( + req, f"{settings.root_address}/api/v1/users/oauth/github/auth" + ) @router.get("/auth") async def auth(request: Request, response: Response): if settings.github_client_id is None or settings.github_client_secret is None: - raise HTTPException(status_code=501, detail="GitHub-Login isn't available on this server") + raise HTTPException( + status_code=501, detail="GitHub-Login isn't available on this server" + ) access_token = request.cookies.get("access_token") rememberme_token = request.cookies.get("rememberme_token") if access_token is not None: @@ -95,7 +101,9 @@ async def auth(request: Request, response: Response): except HTTPException: pass if rememberme_token is not None: - return await rememberme_check(rememberme_token=rememberme_token, response=response) + return await rememberme_check( + rememberme_token=rememberme_token, response=response + ) oauth = init_oauth() try: token = await oauth.github.authorize_access_token(request) @@ -107,25 +115,26 @@ async def auth(request: Request, response: Response): if user_data.email is None: return RedirectResponse("/account/oauth-error?error=email") # REGISTER USER - try: - await User.objects.create( - id=uuid.uuid4(), - email=user_data.email, - username=user_data.login, - verified=True, - auth_type=UserAuthTypes.GITHUB, - avatar=gzipped_user_avatar(), - ) - except asyncpg.exceptions.UniqueViolationError: - raise HTTPException(status_code=400, detail="User already exists.") - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) user = await User.objects.get_or_none( email=user_data.email, username=user_data.login, auth_type=UserAuthTypes.GITHUB, verified=True, ) + if user is None: + try: + user = await User.objects.create( + id=uuid.uuid4(), + email=user_data.email, + username=user_data.login, + verified=True, + auth_type=UserAuthTypes.GITHUB, + avatar=gzipped_user_avatar(), + ) + except asyncpg.exceptions.UniqueViolationError: + raise HTTPException(status_code=400, detail="User already exists.") + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) await log_user_in(user=user, request=request, response=response) response.headers.append("Location", "/account/login") diff --git a/classquiz/oauth/google.py b/classquiz/oauth/google.py index c663ff8..bd141e7 100644 --- a/classquiz/oauth/google.py +++ b/classquiz/oauth/google.py @@ -51,16 +51,22 @@ class OauthGoogleResponse(BaseModel): @router.get("/login") async def google_login(req: Request): if settings.google_client_secret is None or settings.google_client_id is None: - raise HTTPException(status_code=501, detail="Google-Login isn't available on this server") + raise HTTPException( + status_code=501, detail="Google-Login isn't available on this server" + ) oauth = init_oauth() - return await oauth.google.authorize_redirect(req, f"{settings.root_address}/api/v1/users/oauth/google/auth") + return await oauth.google.authorize_redirect( + req, f"{settings.root_address}/api/v1/users/oauth/google/auth" + ) @router.get("/auth") async def auth(request: Request, response: Response): if settings.google_client_secret is None or settings.google_client_id is None: - raise HTTPException(status_code=501, detail="Google-Login isn't available on this server") + raise HTTPException( + status_code=501, detail="Google-Login isn't available on this server" + ) access_token = request.cookies.get("access_token") rememberme_token = request.cookies.get("rememberme_token") if access_token is not None: @@ -71,7 +77,9 @@ async def auth(request: Request, response: Response): except HTTPException: pass if rememberme_token is not None: - return await rememberme_check(rememberme_token=rememberme_token, response=response) + return await rememberme_check( + rememberme_token=rememberme_token, response=response + ) oauth = init_oauth() user_data = await oauth.google.authorize_access_token(request) @@ -80,26 +88,29 @@ async def auth(request: Request, response: Response): except (TypeError, ValidationError): raise HTTPException(status_code=401, detail="Something went wrong.") # REGISTER USER - try: - await User.objects.create( - id=uuid.uuid4(), - email=user_data.email, - username=user_data.name, - verified=user_data.email_verified, - auth_type=UserAuthTypes.GOOGLE, - google_uid=user_data.sub, - avatar=gzipped_user_avatar(), - ) - except asyncpg.exceptions.UniqueViolationError: - raise HTTPException(status_code=400, detail="User already exists.") - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) user = await User.objects.get_or_none( email=user_data.email, google_uid=user_data.sub, auth_type=UserAuthTypes.GOOGLE, verified=True, ) + if user is None: + if user_data.email_verified is False: + raise HTTPException(status_code=401, detail="Email isn't verified") + try: + user = await User.objects.create( + id=uuid.uuid4(), + email=user_data.email, + username=user_data.name, + verified=True, + auth_type=UserAuthTypes.GOOGLE, + google_uid=user_data.sub, + avatar=gzipped_user_avatar(), + ) + except asyncpg.exceptions.UniqueViolationError: + raise HTTPException(status_code=400, detail="User already exists.") + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) await log_user_in(user=user, request=request, response=response) response.headers.append("Location", "/account/login")