test_captcha_verification.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. from __future__ import annotations
  2. import asyncio
  3. import sys
  4. from types import ModuleType, SimpleNamespace
  5. from unittest.mock import AsyncMock
  6. import pytest
  7. from pyrogram.enums import ChatMemberStatus
  8. @pytest.fixture
  9. async def greetings(app_modules, monkeypatch):
  10. app_modules.wbb.WELCOME_DELAY_KICK_SEC = 300
  11. permissions = ModuleType("wbb.core.decorators.permissions")
  12. permissions.adminsOnly = lambda _permission: lambda function: function
  13. notes = ModuleType("wbb.modules.notes")
  14. notes.extract_urls = lambda _markup: []
  15. monkeypatch.setitem(sys.modules, permissions.__name__, permissions)
  16. monkeypatch.setitem(sys.modules, notes.__name__, notes)
  17. module = app_modules.load("wbb.modules.greetings")
  18. await asyncio.sleep(0)
  19. return module
  20. async def test_captcha_defaults_off_and_admin_toggle_matches_bot(app_modules, monkeypatch):
  21. dbfunctions = app_modules.load("wbb.utils.dbfunctions")
  22. service = app_modules.load("wbb.services.chat_management")
  23. monkeypatch.setattr(service, "ensure_permission", AsyncMock())
  24. assert await dbfunctions.is_captcha_on(-100) is False
  25. assert (await service.get_automation_settings(-100))["captcha_enabled"] is False
  26. await app_modules.wbb.db.managed_chat_settings.insert_one(
  27. {"bot_id": "primary", "chat_id": -200, "welcome": {"enabled": True}}
  28. )
  29. assert await dbfunctions.is_captcha_on(-200) is False
  30. assert (await service.get_automation_settings(-200))["captcha_enabled"] is False
  31. await service.apply_automation_settings(-100, {"captcha_enabled": True})
  32. assert await dbfunctions.is_captcha_on(-100) is True
  33. await dbfunctions.captcha_off(-100) # The /captcha command uses the same helper.
  34. assert await dbfunctions.is_captcha_on(-100) is False
  35. assert (await service.get_automation_settings(-100))["captcha_enabled"] is False
  36. await dbfunctions.captcha_on(-100)
  37. assert (await service.get_automation_settings(-100))["captcha_enabled"] is True
  38. async def test_solved_captcha_is_saved_for_each_member(app_modules):
  39. dbfunctions = app_modules.load("wbb.utils.dbfunctions")
  40. await dbfunctions.save_captcha_solved(-100, 11)
  41. await dbfunctions.save_captcha_solved(-100, 12)
  42. assert await dbfunctions.has_solved_captcha_once(-100, 11)
  43. assert await dbfunctions.has_solved_captcha_once(-100, 12)
  44. async def test_captcha_command_updates_admin_setting(greetings):
  45. reply_text = AsyncMock()
  46. message = SimpleNamespace(
  47. chat=SimpleNamespace(id=-100),
  48. command=["captcha", "开启"],
  49. text="/captcha 开启",
  50. reply_text=reply_text,
  51. )
  52. await greetings.captcha_state(None, message)
  53. assert await greetings.is_captcha_on(-100)
  54. message.command = ["captcha", "关闭"]
  55. message.text = "/captcha 关闭"
  56. await greetings.captcha_state(None, message)
  57. assert not await greetings.is_captcha_on(-100)
  58. async def test_passed_verification_timer_does_not_ban_later_manual_mute(
  59. greetings, monkeypatch
  60. ):
  61. monkeypatch.setattr(greetings.asyncio, "sleep", AsyncMock())
  62. chat = SimpleNamespace(
  63. id=-100,
  64. get_member=AsyncMock(
  65. return_value=SimpleNamespace(status=ChatMemberStatus.RESTRICTED)
  66. ),
  67. ban_member=AsyncMock(),
  68. )
  69. message = SimpleNamespace(chat=chat, delete=AsyncMock())
  70. user = SimpleNamespace(id=11)
  71. await greetings.update_captcha_cache(
  72. [{"chat_id": -100, "user_id": 11, "attempt_id": "old"}]
  73. )
  74. await greetings.save_captcha_solved(-100, 11)
  75. await greetings.kick_restricted_after_delay(300, message, user, "old")
  76. chat.ban_member.assert_not_awaited()
  77. message.delete.assert_not_awaited()
  78. assert await greetings.get_captcha_cache() == []
  79. async def test_success_callback_invalidates_timer_before_manual_mute(
  80. greetings, monkeypatch
  81. ):
  82. monkeypatch.setattr(greetings.asyncio, "sleep", AsyncMock())
  83. monkeypatch.setattr(greetings, "send_welcome_message", AsyncMock())
  84. chat = SimpleNamespace(
  85. id=-100,
  86. unban_member=AsyncMock(),
  87. get_member=AsyncMock(
  88. return_value=SimpleNamespace(status=ChatMemberStatus.RESTRICTED)
  89. ),
  90. ban_member=AsyncMock(),
  91. )
  92. button_message = SimpleNamespace(chat=chat, delete=AsyncMock())
  93. callback = SimpleNamespace(
  94. data="pressed_button ABCD 11",
  95. from_user=SimpleNamespace(id=11),
  96. message=button_message,
  97. answer=AsyncMock(),
  98. )
  99. pending = {
  100. "chat_id": -100,
  101. "user_id": 11,
  102. "attempt_id": "attempt",
  103. "answer": "ABCD",
  104. "keyboard": [["answer"]],
  105. "attempts": 0,
  106. }
  107. greetings.answers_dicc = [pending]
  108. await greetings.update_captcha_cache([pending])
  109. await greetings.callback_query_welcome_button(None, callback)
  110. await greetings.kick_restricted_after_delay(
  111. 300, button_message, SimpleNamespace(id=11), "attempt"
  112. )
  113. chat.unban_member.assert_awaited_once_with(11)
  114. chat.ban_member.assert_not_awaited()
  115. assert await greetings.get_captcha_cache() == []
  116. async def test_timeout_only_bans_matching_pending_verification(greetings, monkeypatch):
  117. monkeypatch.setattr(greetings.asyncio, "sleep", AsyncMock())
  118. first_chat = SimpleNamespace(
  119. id=-100,
  120. get_member=AsyncMock(
  121. return_value=SimpleNamespace(status=ChatMemberStatus.RESTRICTED)
  122. ),
  123. ban_member=AsyncMock(),
  124. )
  125. second_chat = SimpleNamespace(id=-200, ban_member=AsyncMock())
  126. message = SimpleNamespace(chat=first_chat, delete=AsyncMock())
  127. await greetings.update_captcha_cache(
  128. [
  129. {"chat_id": -100, "user_id": 11, "attempt_id": "new"},
  130. {"chat_id": -200, "user_id": 11, "attempt_id": "other"},
  131. ]
  132. )
  133. await greetings.kick_restricted_after_delay(
  134. 300, message, SimpleNamespace(id=11), "old"
  135. )
  136. first_chat.ban_member.assert_not_awaited()
  137. await greetings.kick_restricted_after_delay(
  138. 300, message, SimpleNamespace(id=11), "new"
  139. )
  140. first_chat.ban_member.assert_awaited_once()
  141. second_chat.ban_member.assert_not_awaited()
  142. assert await greetings.get_captcha_cache() == [
  143. {"chat_id": -200, "user_id": 11, "attempt_id": "other"}
  144. ]