Skip to content

Commit

Permalink
Auth webapp (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
bomzheg authored May 29, 2024
1 parent 8e71cfc commit 3e25ff6
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
7 changes: 7 additions & 0 deletions shvatka/api/dependencies/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import typing
from datetime import timedelta, datetime

from aiogram.utils.web_app import check_webapp_signature, parse_webapp_init_data, WebAppInitData
from dishka import Provider, provide, Scope, from_context
from fastapi import HTTPException, Request
from jose import jwt, JWTError
Expand Down Expand Up @@ -147,3 +148,9 @@ def check_tg_hash(user: UserTgAuth, bot_token: str):
hmac_string = hmac.new(secret_key, data_check, hashlib.sha256).hexdigest()
if hmac_string != user.hash:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="something wrong")


def check_webapp_hash(data: str, bot_token: str) -> WebAppInitData:
if not check_webapp_signature(bot_token, data):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="tg hash mismatch")
return parse_webapp_init_data(data)
26 changes: 26 additions & 0 deletions shvatka/api/models/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,32 @@
from shvatka.core.models import dto


class WebAppUser(BaseModel):
id: int
first_name: str
is_bot: bool | None = None
last_name: str | None = None
username: str | None = None
language_code: str | None = None
is_premium: bool | None = None
added_to_attachment_menu: bool | None = None
allows_write_to_pm: bool | None = None
photo_url: str | None = None


class WebAppInitData(BaseModel):
user: WebAppUser
auth_date: datetime
hash: str
start_param: str | None = None
query_id: str | None = None


class WebAppAuth(BaseModel):
init_data: str
init_data_unsafe: WebAppInitData


class UserTgAuth(BaseModel):
id: int
first_name: str
Expand Down
24 changes: 22 additions & 2 deletions shvatka/api/routes/auth.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import typing
from typing import Annotated

from aiogram.types import User
from dishka.integrations.fastapi import inject, FromDishka as Depends
from fastapi import Depends as fDepends, Body
from fastapi import APIRouter
from fastapi.security import OAuth2PasswordRequestForm
from starlette.responses import HTMLResponse, Response

from shvatka.api.config.models.auth import AuthConfig
from shvatka.api.models.auth import UserTgAuth
from shvatka.api.models.auth import UserTgAuth, WebAppAuth
from shvatka.api.utils.cookie_auth import set_auth_response
from shvatka.core.models import dto
from shvatka.core.services.user import upsert_user
from shvatka.infrastructure.db.dao.holder import HolderDao
from shvatka.api.dependencies.auth import AuthProperties, check_tg_hash
from shvatka.api.dependencies.auth import AuthProperties, check_tg_hash, check_webapp_hash

TG_WIDGET_HTML = """
<html>
Expand Down Expand Up @@ -90,6 +93,22 @@ async def tg_login_result_post(
return {"ok": True}


@inject
async def webapp_login_result_post(
response: Response,
web_auth: Annotated[WebAppAuth, Body()],
dao: Annotated[HolderDao, Depends()],
auth_properties: Annotated[AuthProperties, Depends()],
config: Annotated[AuthConfig, Depends()],
):
parsed = check_webapp_hash(web_auth.init_data, config.bot_token)
user = dto.User.from_aiogram(typing.cast(User, parsed.user))
saved = await upsert_user(user, dao.user)
token = auth_properties.create_user_token(saved)
set_auth_response(config, response, token)
return {"ok": True}


@inject
async def tg_login_page(config: Annotated[AuthConfig, Depends()]):
return TG_WIDGET_HTML.format(
Expand All @@ -105,4 +124,5 @@ def setup() -> APIRouter:
router.add_api_route("/logout", logout, methods=["POST"])
router.add_api_route("/login/data", tg_login_result, methods=["GET"])
router.add_api_route("/login/data", tg_login_result_post, methods=["POST"])
router.add_api_route("/login/webapp", webapp_login_result_post, methods=["POST"])
return router

0 comments on commit 3e25ff6

Please sign in to comment.