add password authentication for bot users
This commit is contained in:
75
tests/test_auth.py
Normal file
75
tests/test_auth.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from telegram.constants import ChatType
|
||||
from telegram.ext import ApplicationHandlerStop
|
||||
|
||||
from assistant_bot.auth import authentication_guard
|
||||
from assistant_bot.storage import AssistantStorage
|
||||
|
||||
|
||||
class AuthenticationGuardTests(unittest.IsolatedAsyncioTestCase):
|
||||
def setUp(self) -> None:
|
||||
self.temporary_directory = tempfile.TemporaryDirectory()
|
||||
self.storage = AssistantStorage(
|
||||
Path(self.temporary_directory.name) / "assistant.sqlite3"
|
||||
)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.temporary_directory.cleanup()
|
||||
|
||||
def make_update_and_context(self, text: str) -> tuple[Any, Any]:
|
||||
message = SimpleNamespace(text=text, reply_text=AsyncMock())
|
||||
update = SimpleNamespace(
|
||||
effective_user=SimpleNamespace(id=42),
|
||||
effective_chat=SimpleNamespace(type=ChatType.PRIVATE),
|
||||
effective_message=message,
|
||||
inline_query=None,
|
||||
)
|
||||
context = SimpleNamespace(
|
||||
application=SimpleNamespace(
|
||||
bot_data={
|
||||
"storage": self.storage,
|
||||
"assistant_password": "секрет",
|
||||
}
|
||||
)
|
||||
)
|
||||
return update, context
|
||||
|
||||
async def test_correct_password_authorizes_user(self) -> None:
|
||||
update, context = self.make_update_and_context("секрет")
|
||||
|
||||
with self.assertRaises(ApplicationHandlerStop):
|
||||
await authentication_guard(update, context)
|
||||
|
||||
self.assertTrue(self.storage.is_user_authorized(42))
|
||||
update.effective_message.reply_text.assert_awaited_once_with(
|
||||
"Пароль принят. Доступ открыт — повторно вводить его не нужно."
|
||||
)
|
||||
|
||||
async def test_wrong_password_does_not_authorize_user(self) -> None:
|
||||
update, context = self.make_update_and_context("неверно")
|
||||
|
||||
with self.assertRaises(ApplicationHandlerStop):
|
||||
await authentication_guard(update, context)
|
||||
|
||||
self.assertFalse(self.storage.is_user_authorized(42))
|
||||
update.effective_message.reply_text.assert_awaited_once_with(
|
||||
"Неверный пароль. Попробуй еще раз."
|
||||
)
|
||||
|
||||
async def test_authorized_user_passes_guard(self) -> None:
|
||||
self.storage.authorize_user(42)
|
||||
update, context = self.make_update_and_context("обычное сообщение")
|
||||
|
||||
await authentication_guard(update, context)
|
||||
|
||||
update.effective_message.reply_text.assert_not_awaited()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -67,5 +67,25 @@ class AssistantModeConfigTests(unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class PasswordConfigTests(unittest.TestCase):
|
||||
def test_password_is_required(self) -> None:
|
||||
with patch("assistant_bot.config.load_env_file"), patch.dict(
|
||||
os.environ,
|
||||
{},
|
||||
clear=False,
|
||||
):
|
||||
os.environ.pop(config.PASSWORD_ENV_NAME, None)
|
||||
with self.assertRaises(RuntimeError):
|
||||
config.get_assistant_password()
|
||||
|
||||
def test_password_is_read_from_environment(self) -> None:
|
||||
with patch("assistant_bot.config.load_env_file"), patch.dict(
|
||||
os.environ,
|
||||
{config.PASSWORD_ENV_NAME: " test-password "},
|
||||
clear=False,
|
||||
):
|
||||
self.assertEqual(config.get_assistant_password(), "test-password")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -53,6 +53,18 @@ class AgentDecisionTests(unittest.TestCase):
|
||||
|
||||
|
||||
class StorageTests(unittest.TestCase):
|
||||
def test_user_authorization_is_persisted(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
database_path = Path(directory) / "assistant.sqlite3"
|
||||
storage = AssistantStorage(database_path)
|
||||
|
||||
self.assertFalse(storage.is_user_authorized(42))
|
||||
storage.authorize_user(42)
|
||||
|
||||
reopened_storage = AssistantStorage(database_path)
|
||||
self.assertTrue(reopened_storage.is_user_authorized(42))
|
||||
self.assertFalse(reopened_storage.is_user_authorized(43))
|
||||
|
||||
def test_legacy_user_settings_gets_yandex_model_column(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
database_path = Path(directory) / "assistant.sqlite3"
|
||||
|
||||
Reference in New Issue
Block a user