Skip to content

Commit

Permalink
Merge pull request #79 from swimmwatch/release/v3.0.0
Browse files Browse the repository at this point in the history
Release v3.0.0
  • Loading branch information
swimmwatch authored Jan 8, 2025
2 parents 749a0be + 2cc8672 commit 343e141
Show file tree
Hide file tree
Showing 16 changed files with 1,435 additions and 563 deletions.
14 changes: 11 additions & 3 deletions .github/workflows/python-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ on:
- '**/*.py'
- 'poetry.lock'
- 'pyproject.toml'
- '.github/workflows/python-check.yml'
branches:
- master
- dev
- release/*

jobs:
lint:
name: "Run linters"
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
poetry-version: [ "1.8.3" ]
steps:
- name: Checkout
Expand All @@ -39,11 +41,12 @@ jobs:
run: make doc-lint
test:
name: "Run tests"
runs-on: ubuntu-latest
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
poetry-version: [ "1.8.3" ]
os: [ "ubuntu-latest", "windows-latest", "macos-latest" ]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -58,3 +61,8 @@ jobs:
run: make install
- name: Run pytest
run: make test
- name: "Upload coverage reports to Codecov"
if: matrix.python-version == '3.13' && matrix.os == 'ubuntu-latest' && github.actor != 'dependabot[bot]'
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
5 changes: 1 addition & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ format: black isort doc-lint

lint: flake mypy black-lint

cov:
poetry run pytest --cov=$(PACKAGE_DIR) $(SRC_DIR)

lock:
poetry lock --no-update

Expand All @@ -41,4 +38,4 @@ mkdocs-deploy:
poetry run mkdocs gh-deploy --force

test:
poetry run pytest -n 2 $(TESTS_DIR)
poetry run pytest --cov=$(PACKAGE_DIR) --cov-branch --cov-report=xml --numprocesses logical $(TESTS_DIR)
45 changes: 34 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,46 @@

<div align="center">
<p>
<a href="https://pypi.org/project/telegram-webapp-auth"><img src="https://img.shields.io/pypi/v/telegram-webapp-auth.svg" alt="PyPI"></a>
<a href="pyproject.toml"><img src="https://img.shields.io/pypi/pyversions/telegram-webapp-auth" alt="Supported Python Versions"></a>
<a href="https://pypi.org/project/telegram-webapp-auth">
<img src="https://img.shields.io/pypi/v/telegram-webapp-auth.svg" alt="PyPI">
</a>
<a href="pyproject.toml">
<img src="https://img.shields.io/pypi/pyversions/telegram-webapp-auth" alt="Supported Python Versions">
</a>
<br/>
<a href="LICENSE"><img src="https://img.shields.io/github/license/swimmwatch/telegram-webapp-auth" alt="License"></a>
<a href="https://github.com/ambv/black"><img src="https://img.shields.io/badge/code%20style-black-black" alt="Code style"></a>
<a href="https://github.com/pycqa/flake8"><img src="https://img.shields.io/badge/lint-flake8-black" alt="Linter"></a>
<a href="https://github.com/python/mypy"><img src="https://img.shields.io/badge/type%20checker-mypy-black" alt="Type checker"></a>
<a href="https://snyk.io/advisor/python/telegram-webapp-auth"><img src="https://snyk.io/advisor/python/telegram-webapp-auth/badge.svg" alt="Package health"></a>
<a href="LICENSE">
<img src="https://img.shields.io/github/license/swimmwatch/telegram-webapp-auth" alt="License">
</a>
<a href="https://github.com/ambv/black">
<img src="https://img.shields.io/badge/code%20style-black-black" alt="Code style">
</a>
<a href="https://github.com/pycqa/flake8">
<img src="https://img.shields.io/badge/lint-flake8-black" alt="Linter">
</a>
<a href="https://github.com/python/mypy">
<img src="https://img.shields.io/badge/type%20checker-mypy-black" alt="Type checker">
</a>
<a href="https://snyk.io/advisor/python/telegram-webapp-auth">
<img src="https://snyk.io/advisor/python/telegram-webapp-auth/badge.svg" alt="Package health">
</a>
<br/>
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/python-check.yml"><img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/python-check.yml/badge.svg" alt="Tests"></a>
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/release.yml"><img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/release.yml/badge.svg" alt="Release"></a>
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/docs.yml"><img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/docs.yml/badge.svg" alt="Docs"></a>
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/python-check.yml">
<img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/python-check.yml/badge.svg" alt="Tests">
</a>
<a href="https://codecov.io/github/swimmwatch/telegram-webapp-auth" target="_blank">
<img src="https://codecov.io/github/swimmwatch/telegram-webapp-auth/graph/badge.svg?token=M638BMDY5V" alt="Coverage">
</a>
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/release.yml">
<img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/release.yml/badge.svg" alt="Release">
</a>
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/docs.yml">
<img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/docs.yml/badge.svg" alt="Docs">
</a>
</p>
</div>
<!-- markdownlint-enable -->

This Python package implements [Telegram Web authentication algorithm](https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app).
This Python package implements [Telegram Mini Apps authentication algorithms](https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app).

## Installation
```bash
Expand Down
23 changes: 16 additions & 7 deletions docs/guide/examples/django.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,42 @@ TELEGRAM_SECRET_KEY = generate_secret_key(TELEGRAM_BOT_TOKEN)
```

Then implement middleware:

```python
from django.conf import settings
from django.contrib.auth.models import User
from django.http import HttpRequest
from django.http import HttpResponse
from telegram_webapp_auth.auth import TelegramAuthenticator
from telegram_webapp_auth.errors import InvalidInitDataError


class TWAAuthorizationMiddleware:
def __init__(self, get_response):
def __init__(self, get_response) -> None:
self.get_response = get_response
self._telegram_authenticator = TelegramAuthenticator(settings.TELEGRAM_SECRET_KEY)

def __call__(self, request):
def __call__(self, request: HttpRequest) -> HttpResponse:
# Code to be executed for each request before
# the view (and later middleware) are called.
auth_cred = request.headers.get('Authorization')

try:
user = self._telegram_authenticator.verify_token(auth_cred)
init_data = self._telegram_authenticator.validate(auth_cred)
except InvalidInitDataError:
# TODO: handle error
pass

current_user = User.objects.filter(tg_id=user.id).first()
if not init_data.user:
# TODO: handle error
pass

current_user = User.objects.filter(tg_id=init_data.user.id).first()
if not current_user:
# TODO: handle error
pass
request.user = current_user # Associate current user with requests object

request.user = current_user # Associate current user with the request object

response = self.get_response(request)

Expand Down
19 changes: 13 additions & 6 deletions docs/guide/examples/fastapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ from fastapi.security.http import HTTPAuthorizationCredentials
from fastapi.security.http import HTTPBase

from telegram_webapp_auth.auth import TelegramAuthenticator
from telegram_webapp_auth.auth import TelegramUser
from telegram_webapp_auth.auth import WebAppUser
from telegram_webapp_auth.auth import generate_secret_key
from telegram_webapp_auth.errors import InvalidInitDataError

Expand All @@ -30,9 +30,9 @@ def get_telegram_authenticator() -> TelegramAuthenticator:
def get_current_user(
auth_cred: HTTPAuthorizationCredentials = Depends(telegram_authentication_schema),
telegram_authenticator: TelegramAuthenticator = Depends(get_telegram_authenticator),
) -> TelegramUser:
) -> WebAppUser:
try:
user = telegram_authenticator.verify_token(auth_cred.credentials)
init_data = telegram_authenticator.validate(auth_cred.credentials)
except InvalidInitDataError:
raise HTTPException(
status_code=http.HTTPStatus.FORBIDDEN,
Expand All @@ -43,19 +43,26 @@ def get_current_user(
status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Internal error.",
)

if init_data.user is None:
raise HTTPException(
status_code=http.HTTPStatus.FORBIDDEN,
detail="Forbidden access.",
)

return user
return init_data.user
```

Finally, we can use it as usual.

File `app.py`:

```python
from fastapi import Depends
from fastapi import FastAPI
from pydantic import BaseModel

from telegram_webapp_auth.auth import TelegramUser
from telegram_webapp_auth.auth import WebAppUser

from .auth import get_current_user

Expand All @@ -69,7 +76,7 @@ class Message(BaseModel):
@app.post("/message")
async def send_message(
message: Message,
user: TelegramUser = Depends(get_current_user),
user: WebAppUser = Depends(get_current_user),
):
"""
Some logic...
Expand Down
140 changes: 140 additions & 0 deletions docs/references/data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!-- markdownlint-disable -->

<a href="../../telegram_webapp_auth/data.py#L0"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

# <kbd>module</kbd> `data`




**Global Variables**
---------------
- **dataclasses**
- **TEST_PUBLIC_KEY_STR**
- **PROD_PUBLIC_KEY_STR**
- **TEST_PUBLIC_KEY_BYTES**
- **PROD_PUBLIC_KEY_BYTES**


---

<a href="../../telegram_webapp_auth/data.py#L17"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>class</kbd> `WebAppUser`
Represents a Telegram user.

Links: https://core.telegram.org/bots/webapps#webappuser

<a href="../../<string>"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `__init__`

```python
__init__(
id: int,
first_name: str,
is_bot: Optional[bool] = None,
last_name: Optional[str] = None,
username: Optional[str] = None,
language_code: Optional[str] = None,
is_premium: Optional[bool] = None,
added_to_attachment_menu: Optional[bool] = None,
allows_write_to_pm: Optional[bool] = None,
photo_url: Optional[str] = None
) → None
```









---

<a href="../../telegram_webapp_auth/data.py#L37"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>class</kbd> `ChatType`








---

<a href="../../telegram_webapp_auth/data.py#L44"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>class</kbd> `WebAppChat`
Represents a Telegram chat.

Links: https://core.telegram.org/bots/webapps#webappchat

<a href="../../<string>"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `__init__`

```python
__init__(
id: int,
type: ChatType,
title: str,
username: Optional[str] = None,
photo_url: Optional[str] = None
) → None
```









---

<a href="../../telegram_webapp_auth/data.py#L59"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>class</kbd> `WebAppInitData`
Represents the data that the webapp receives from Telegram.

Links: https://core.telegram.org/bots/webapps#webappinitdata

<a href="../../<string>"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `__init__`

```python
__init__(
query_id: str,
auth_date: int,
hash: str,
signature: str,
user: Optional[WebAppUser] = None,
receiver: Optional[WebAppUser] = None,
chat: Optional[WebAppChat] = None,
chat_type: Optional[ChatType] = None,
chat_instance: Optional[str] = None,
start_param: Optional[str] = None,
can_send_after: Optional[int] = None
) → None
```











---

_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._
13 changes: 13 additions & 0 deletions docs/references/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@



---

<a href="../../telegram_webapp_auth/errors.py#L9"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>class</kbd> `ExpiredInitDataError`










---
Expand Down
Loading

0 comments on commit 343e141

Please sign in to comment.