Skip to content

Commit 343e141

Browse files
authored
Merge pull request #79 from swimmwatch/release/v3.0.0
Release v3.0.0
2 parents 749a0be + 2cc8672 commit 343e141

16 files changed

Lines changed: 1435 additions & 563 deletions

File tree

.github/workflows/python-check.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ on:
55
- '**/*.py'
66
- 'poetry.lock'
77
- 'pyproject.toml'
8+
- '.github/workflows/python-check.yml'
89
branches:
910
- master
1011
- dev
12+
- release/*
1113

1214
jobs:
1315
lint:
1416
name: "Run linters"
1517
runs-on: ubuntu-latest
1618
strategy:
1719
matrix:
18-
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
20+
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
1921
poetry-version: [ "1.8.3" ]
2022
steps:
2123
- name: Checkout
@@ -39,11 +41,12 @@ jobs:
3941
run: make doc-lint
4042
test:
4143
name: "Run tests"
42-
runs-on: ubuntu-latest
44+
runs-on: ${{matrix.os}}
4345
strategy:
4446
matrix:
45-
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
47+
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
4648
poetry-version: [ "1.8.3" ]
49+
os: [ "ubuntu-latest", "windows-latest", "macos-latest" ]
4750
steps:
4851
- name: Checkout
4952
uses: actions/checkout@v4
@@ -58,3 +61,8 @@ jobs:
5861
run: make install
5962
- name: Run pytest
6063
run: make test
64+
- name: "Upload coverage reports to Codecov"
65+
if: matrix.python-version == '3.13' && matrix.os == 'ubuntu-latest' && github.actor != 'dependabot[bot]'
66+
uses: codecov/codecov-action@v5
67+
with:
68+
token: ${{ secrets.CODECOV_TOKEN }}

Makefile

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ format: black isort doc-lint
2525

2626
lint: flake mypy black-lint
2727

28-
cov:
29-
poetry run pytest --cov=$(PACKAGE_DIR) $(SRC_DIR)
30-
3128
lock:
3229
poetry lock --no-update
3330

@@ -41,4 +38,4 @@ mkdocs-deploy:
4138
poetry run mkdocs gh-deploy --force
4239

4340
test:
44-
poetry run pytest -n 2 $(TESTS_DIR)
41+
poetry run pytest --cov=$(PACKAGE_DIR) --cov-branch --cov-report=xml --numprocesses logical $(TESTS_DIR)

README.md

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,46 @@
55

66
<div align="center">
77
<p>
8-
<a href="https://pypi.org/project/telegram-webapp-auth"><img src="https://img.shields.io/pypi/v/telegram-webapp-auth.svg" alt="PyPI"></a>
9-
<a href="pyproject.toml"><img src="https://img.shields.io/pypi/pyversions/telegram-webapp-auth" alt="Supported Python Versions"></a>
8+
<a href="https://pypi.org/project/telegram-webapp-auth">
9+
<img src="https://img.shields.io/pypi/v/telegram-webapp-auth.svg" alt="PyPI">
10+
</a>
11+
<a href="pyproject.toml">
12+
<img src="https://img.shields.io/pypi/pyversions/telegram-webapp-auth" alt="Supported Python Versions">
13+
</a>
1014
<br/>
11-
<a href="LICENSE"><img src="https://img.shields.io/github/license/swimmwatch/telegram-webapp-auth" alt="License"></a>
12-
<a href="https://github.com/ambv/black"><img src="https://img.shields.io/badge/code%20style-black-black" alt="Code style"></a>
13-
<a href="https://github.com/pycqa/flake8"><img src="https://img.shields.io/badge/lint-flake8-black" alt="Linter"></a>
14-
<a href="https://github.com/python/mypy"><img src="https://img.shields.io/badge/type%20checker-mypy-black" alt="Type checker"></a>
15-
<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>
15+
<a href="LICENSE">
16+
<img src="https://img.shields.io/github/license/swimmwatch/telegram-webapp-auth" alt="License">
17+
</a>
18+
<a href="https://github.com/ambv/black">
19+
<img src="https://img.shields.io/badge/code%20style-black-black" alt="Code style">
20+
</a>
21+
<a href="https://github.com/pycqa/flake8">
22+
<img src="https://img.shields.io/badge/lint-flake8-black" alt="Linter">
23+
</a>
24+
<a href="https://github.com/python/mypy">
25+
<img src="https://img.shields.io/badge/type%20checker-mypy-black" alt="Type checker">
26+
</a>
27+
<a href="https://snyk.io/advisor/python/telegram-webapp-auth">
28+
<img src="https://snyk.io/advisor/python/telegram-webapp-auth/badge.svg" alt="Package health">
29+
</a>
1630
<br/>
17-
<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>
18-
<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>
19-
<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>
31+
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/python-check.yml">
32+
<img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/python-check.yml/badge.svg" alt="Tests">
33+
</a>
34+
<a href="https://codecov.io/github/swimmwatch/telegram-webapp-auth" target="_blank">
35+
<img src="https://codecov.io/github/swimmwatch/telegram-webapp-auth/graph/badge.svg?token=M638BMDY5V" alt="Coverage">
36+
</a>
37+
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/release.yml">
38+
<img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/release.yml/badge.svg" alt="Release">
39+
</a>
40+
<a href="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/docs.yml">
41+
<img src="https://github.com/swimmwatch/telegram-webapp-auth/actions/workflows/docs.yml/badge.svg" alt="Docs">
42+
</a>
2043
</p>
2144
</div>
2245
<!-- markdownlint-enable -->
2346

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

2649
## Installation
2750
```bash

docs/guide/examples/django.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,42 @@ TELEGRAM_SECRET_KEY = generate_secret_key(TELEGRAM_BOT_TOKEN)
1212
```
1313

1414
Then implement middleware:
15+
1516
```python
1617
from django.conf import settings
18+
from django.contrib.auth.models import User
19+
from django.http import HttpRequest
20+
from django.http import HttpResponse
1721
from telegram_webapp_auth.auth import TelegramAuthenticator
1822
from telegram_webapp_auth.errors import InvalidInitDataError
1923

24+
2025
class TWAAuthorizationMiddleware:
21-
def __init__(self, get_response):
26+
def __init__(self, get_response) -> None:
2227
self.get_response = get_response
2328
self._telegram_authenticator = TelegramAuthenticator(settings.TELEGRAM_SECRET_KEY)
2429

25-
def __call__(self, request):
30+
def __call__(self, request: HttpRequest) -> HttpResponse:
2631
# Code to be executed for each request before
2732
# the view (and later middleware) are called.
2833
auth_cred = request.headers.get('Authorization')
29-
34+
3035
try:
31-
user = self._telegram_authenticator.verify_token(auth_cred)
36+
init_data = self._telegram_authenticator.validate(auth_cred)
3237
except InvalidInitDataError:
3338
# TODO: handle error
3439
pass
3540

36-
current_user = User.objects.filter(tg_id=user.id).first()
41+
if not init_data.user:
42+
# TODO: handle error
43+
pass
44+
45+
current_user = User.objects.filter(tg_id=init_data.user.id).first()
3746
if not current_user:
3847
# TODO: handle error
3948
pass
40-
41-
request.user = current_user # Associate current user with requests object
49+
50+
request.user = current_user # Associate current user with the request object
4251

4352
response = self.get_response(request)
4453

docs/guide/examples/fastapi.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ from fastapi.security.http import HTTPAuthorizationCredentials
1212
from fastapi.security.http import HTTPBase
1313

1414
from telegram_webapp_auth.auth import TelegramAuthenticator
15-
from telegram_webapp_auth.auth import TelegramUser
15+
from telegram_webapp_auth.auth import WebAppUser
1616
from telegram_webapp_auth.auth import generate_secret_key
1717
from telegram_webapp_auth.errors import InvalidInitDataError
1818

@@ -30,9 +30,9 @@ def get_telegram_authenticator() -> TelegramAuthenticator:
3030
def get_current_user(
3131
auth_cred: HTTPAuthorizationCredentials = Depends(telegram_authentication_schema),
3232
telegram_authenticator: TelegramAuthenticator = Depends(get_telegram_authenticator),
33-
) -> TelegramUser:
33+
) -> WebAppUser:
3434
try:
35-
user = telegram_authenticator.verify_token(auth_cred.credentials)
35+
init_data = telegram_authenticator.validate(auth_cred.credentials)
3636
except InvalidInitDataError:
3737
raise HTTPException(
3838
status_code=http.HTTPStatus.FORBIDDEN,
@@ -43,19 +43,26 @@ def get_current_user(
4343
status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR,
4444
detail="Internal error.",
4545
)
46+
47+
if init_data.user is None:
48+
raise HTTPException(
49+
status_code=http.HTTPStatus.FORBIDDEN,
50+
detail="Forbidden access.",
51+
)
4652

47-
return user
53+
return init_data.user
4854
```
4955

5056
Finally, we can use it as usual.
5157

5258
File `app.py`:
59+
5360
```python
5461
from fastapi import Depends
5562
from fastapi import FastAPI
5663
from pydantic import BaseModel
5764

58-
from telegram_webapp_auth.auth import TelegramUser
65+
from telegram_webapp_auth.auth import WebAppUser
5966

6067
from .auth import get_current_user
6168

@@ -69,7 +76,7 @@ class Message(BaseModel):
6976
@app.post("/message")
7077
async def send_message(
7178
message: Message,
72-
user: TelegramUser = Depends(get_current_user),
79+
user: WebAppUser = Depends(get_current_user),
7380
):
7481
"""
7582
Some logic...

docs/references/data.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<!-- markdownlint-disable -->
2+
3+
<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>
4+
5+
# <kbd>module</kbd> `data`
6+
7+
8+
9+
10+
**Global Variables**
11+
---------------
12+
- **dataclasses**
13+
- **TEST_PUBLIC_KEY_STR**
14+
- **PROD_PUBLIC_KEY_STR**
15+
- **TEST_PUBLIC_KEY_BYTES**
16+
- **PROD_PUBLIC_KEY_BYTES**
17+
18+
19+
---
20+
21+
<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>
22+
23+
## <kbd>class</kbd> `WebAppUser`
24+
Represents a Telegram user.
25+
26+
Links: https://core.telegram.org/bots/webapps#webappuser
27+
28+
<a href="../../<string>"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
29+
30+
### <kbd>method</kbd> `__init__`
31+
32+
```python
33+
__init__(
34+
id: int,
35+
first_name: str,
36+
is_bot: Optional[bool] = None,
37+
last_name: Optional[str] = None,
38+
username: Optional[str] = None,
39+
language_code: Optional[str] = None,
40+
is_premium: Optional[bool] = None,
41+
added_to_attachment_menu: Optional[bool] = None,
42+
allows_write_to_pm: Optional[bool] = None,
43+
photo_url: Optional[str] = None
44+
) → None
45+
```
46+
47+
48+
49+
50+
51+
52+
53+
54+
55+
---
56+
57+
<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>
58+
59+
## <kbd>class</kbd> `ChatType`
60+
61+
62+
63+
64+
65+
66+
67+
68+
---
69+
70+
<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>
71+
72+
## <kbd>class</kbd> `WebAppChat`
73+
Represents a Telegram chat.
74+
75+
Links: https://core.telegram.org/bots/webapps#webappchat
76+
77+
<a href="../../<string>"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
78+
79+
### <kbd>method</kbd> `__init__`
80+
81+
```python
82+
__init__(
83+
id: int,
84+
type: ChatType,
85+
title: str,
86+
username: Optional[str] = None,
87+
photo_url: Optional[str] = None
88+
) → None
89+
```
90+
91+
92+
93+
94+
95+
96+
97+
98+
99+
---
100+
101+
<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>
102+
103+
## <kbd>class</kbd> `WebAppInitData`
104+
Represents the data that the webapp receives from Telegram.
105+
106+
Links: https://core.telegram.org/bots/webapps#webappinitdata
107+
108+
<a href="../../<string>"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
109+
110+
### <kbd>method</kbd> `__init__`
111+
112+
```python
113+
__init__(
114+
query_id: str,
115+
auth_date: int,
116+
hash: str,
117+
signature: str,
118+
user: Optional[WebAppUser] = None,
119+
receiver: Optional[WebAppUser] = None,
120+
chat: Optional[WebAppChat] = None,
121+
chat_type: Optional[ChatType] = None,
122+
chat_instance: Optional[str] = None,
123+
start_param: Optional[str] = None,
124+
can_send_after: Optional[int] = None
125+
) → None
126+
```
127+
128+
129+
130+
131+
132+
133+
134+
135+
136+
137+
138+
---
139+
140+
_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._

docs/references/errors.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@
3535

3636

3737

38+
---
39+
40+
<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>
41+
42+
## <kbd>class</kbd> `ExpiredInitDataError`
43+
44+
45+
46+
47+
48+
49+
50+
3851

3952

4053
---

0 commit comments

Comments
 (0)