DispelEvilBot/tests/test_auth.py

109 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Тесты входа в админку через Telegram: подпись, сессия и CSRF."""
from __future__ import annotations
import time
from fastapi.testclient import TestClient
from admin.security import verify_telegram_auth
def test_healthz_is_public(client_factory) -> None:
assert client_factory(authenticated=False).get("/healthz").status_code == 200
def test_protected_page_redirects_to_login(client_factory) -> None:
response = client_factory(authenticated=False, follow_redirects=False).get("/")
assert response.status_code == 303
assert response.headers["location"].startswith("/login")
def test_login_page_has_widget(client_factory) -> None:
response = client_factory(authenticated=False).get("/login")
assert response.status_code == 200
assert "telegram-widget.js" in response.text
assert "debot_test_bot" in response.text
assert "https://debot-test.mpakosrv.ru/auth/telegram" in response.text
def test_login_page_without_config(client_factory, settings_factory) -> None:
client = client_factory(
authenticated=False,
settings=settings_factory(bot_token="", bot_username=""),
)
response = client.get("/login")
assert response.status_code == 200
assert "Вход не настроен" in response.text
def test_login_with_valid_signature(client_factory, telegram_query) -> None:
client: TestClient = client_factory(authenticated=False, follow_redirects=False)
response = client.get("/auth/telegram", params=telegram_query())
assert response.status_code == 303
assert response.headers["location"] == "/"
assert client.get("/").status_code == 200
def test_login_rejects_bad_hash(client_factory, telegram_query) -> None:
params = telegram_query()
params["hash"] = "0" * 64
response = client_factory(authenticated=False).get("/auth/telegram", params=params)
assert response.status_code == 403
assert "Не удалось проверить вход" in response.text
def test_login_rejects_stale_auth_date(client_factory, telegram_query) -> None:
params = telegram_query(auth_date=int(time.time()) - 90_000)
response = client_factory(authenticated=False).get("/auth/telegram", params=params)
assert response.status_code == 403
def test_login_rejects_non_admin(client_factory, telegram_query) -> None:
response = client_factory(authenticated=False).get("/auth/telegram", params=telegram_query(telegram_id=2))
assert response.status_code == 403
assert "нет доступа" in response.text
def test_logout_requires_csrf(client_factory) -> None:
response = client_factory().post("/logout")
assert response.status_code == 400
def test_logout_clears_session(client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = csrf_token(client.get("/").text)
response = client.post("/logout", data={"csrf_token": token})
assert response.status_code == 200
assert client.get("/", follow_redirects=False).status_code == 303
def test_verify_signature(bot_token: str) -> None:
"""Юнит-проверка подписи без HTTP (данные собираем тем же алгоритмом)."""
import hashlib
import hmac
data = {"id": "1", "first_name": "Admin", "auth_date": str(int(time.time()))}
check = "\n".join(f"{key}={value}" for key, value in sorted(data.items()))
secret = hashlib.sha256(bot_token.encode()).digest()
data["hash"] = hmac.new(secret, check.encode(), hashlib.sha256).hexdigest()
assert verify_telegram_auth(data, bot_token)
assert not verify_telegram_auth({**data, "id": "2"}, bot_token)
assert not verify_telegram_auth(data, "999:OTHER")
assert not verify_telegram_auth(data, bot_token, now=time.time() + 90_000)