mirror of
https://github.com/zc-zhangchen/any-auto-register.git
synced 2026-05-18 11:26:45 +08:00
204 lines
7.9 KiB
Python
204 lines
7.9 KiB
Python
import base64
|
|
import json
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
from platforms.chatgpt.oauth_client import OAuthClient
|
|
from platforms.chatgpt.phone_service import SMSToMePhoneService
|
|
from platforms.chatgpt.utils import FlowState
|
|
from smstome_tool import PhoneEntry, parse_country_slugs
|
|
|
|
|
|
class OAuthCookieDecodeTests(unittest.TestCase):
|
|
def test_decode_signed_cookie_payload(self):
|
|
payload = {
|
|
"email": "demo@example.com",
|
|
"phone_number": "+447456344799",
|
|
"phone_verification_channel": "whatsapp",
|
|
}
|
|
encoded = base64.urlsafe_b64encode(json.dumps(payload).encode("utf-8")).decode("utf-8").rstrip("=")
|
|
cookie_value = f"{encoded}.sig-a.sig-b"
|
|
|
|
self.assertEqual(OAuthClient._decode_cookie_json_value(cookie_value), payload)
|
|
|
|
def test_decode_invalid_cookie_payload(self):
|
|
self.assertIsNone(OAuthClient._decode_cookie_json_value("not-a-valid-cookie"))
|
|
|
|
|
|
class SMSToMeConfigTests(unittest.TestCase):
|
|
def test_parse_country_slugs_accepts_csv_and_iterables(self):
|
|
self.assertEqual(
|
|
parse_country_slugs("united-kingdom, poland;finland"),
|
|
["united-kingdom", "poland", "finland"],
|
|
)
|
|
self.assertEqual(
|
|
parse_country_slugs(["united-kingdom", "poland", "united_kingdom"]),
|
|
["united-kingdom", "poland"],
|
|
)
|
|
|
|
def test_phone_service_enabled_when_pool_file_exists(self):
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
pool_path = Path(tmp_dir) / "phones.txt"
|
|
pool_path.write_text("+447456344799\tunited-kingdom\thttps://example.com\n", encoding="utf-8")
|
|
|
|
service = SMSToMePhoneService({"smstome_global_file": str(pool_path)})
|
|
self.assertTrue(service.enabled)
|
|
|
|
def test_phone_service_disabled_for_empty_pool_without_cookie(self):
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
pool_path = Path(tmp_dir) / "phones.txt"
|
|
pool_path.write_text("", encoding="utf-8")
|
|
|
|
service = SMSToMePhoneService({"smstome_global_file": str(pool_path)})
|
|
self.assertFalse(service.enabled)
|
|
|
|
def test_wait_for_code_forwards_cookie_timeout_and_poll_interval(self):
|
|
entry = PhoneEntry(
|
|
country_slug="united-kingdom",
|
|
phone="+447456344799",
|
|
detail_url="https://example.com/phone/1",
|
|
)
|
|
service = SMSToMePhoneService(
|
|
{
|
|
"smstome_cookie": "cf_clearance=demo",
|
|
"smstome_otp_timeout_seconds": "66",
|
|
"smstome_poll_interval_seconds": "7",
|
|
}
|
|
)
|
|
|
|
with mock.patch("platforms.chatgpt.phone_service.wait_for_otp", return_value="123456") as mocked:
|
|
code = service.wait_for_code(entry)
|
|
|
|
self.assertEqual(code, "123456")
|
|
mocked.assert_called_once()
|
|
kwargs = mocked.call_args.kwargs
|
|
self.assertEqual(kwargs["cookie_header"], "cf_clearance=demo")
|
|
self.assertEqual(kwargs["timeout"], 66)
|
|
self.assertEqual(kwargs["poll_interval"], 7)
|
|
self.assertFalse(kwargs["raise_on_timeout"])
|
|
|
|
def test_ensure_pool_ready_syncs_with_configured_page_limit(self):
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
pool_path = Path(tmp_dir) / "phones.txt"
|
|
service = SMSToMePhoneService(
|
|
{
|
|
"smstome_cookie": "cf_clearance=demo",
|
|
"smstome_country_slugs": "united-kingdom",
|
|
"smstome_global_file": str(pool_path),
|
|
"smstome_sync_max_pages_per_country": "9",
|
|
}
|
|
)
|
|
|
|
with mock.patch("platforms.chatgpt.phone_service.update_global_phone_list", return_value=3) as mocked:
|
|
service.ensure_pool_ready()
|
|
|
|
mocked.assert_called_once()
|
|
kwargs = mocked.call_args.kwargs
|
|
self.assertEqual(kwargs["cookie_header"], "cf_clearance=demo")
|
|
self.assertEqual(kwargs["countries"], ["united-kingdom"])
|
|
self.assertEqual(kwargs["output_path"], pool_path)
|
|
self.assertEqual(kwargs["max_pages_per_country"], 9)
|
|
|
|
|
|
class OAuthPhoneBlacklistTests(unittest.TestCase):
|
|
def test_should_blacklist_explicit_phone_rejection(self):
|
|
state = FlowState(
|
|
page_type="add_phone",
|
|
payload={"error": {"message": "phone number is invalid"}},
|
|
)
|
|
self.assertTrue(
|
|
OAuthClient._should_blacklist_phone_failure(
|
|
"add-phone/send 失败: 400 - phone number is invalid",
|
|
state,
|
|
)
|
|
)
|
|
|
|
def test_should_not_blacklist_whatsapp_or_delivery_failures(self):
|
|
self.assertFalse(
|
|
OAuthClient._should_blacklist_phone_failure(
|
|
"add_phone 已切到 whatsapp 通道,当前 SMSToMe 仅支持短信接码"
|
|
)
|
|
)
|
|
self.assertFalse(
|
|
OAuthClient._should_blacklist_phone_failure("手机号 +447000000001 未收到短信验证码")
|
|
)
|
|
|
|
def test_handle_add_phone_blacklists_explicitly_rejected_number(self):
|
|
client = OAuthClient(config={}, verbose=False)
|
|
client._log = lambda _msg: None
|
|
entry = PhoneEntry(
|
|
country_slug="united-kingdom",
|
|
phone="+447000000001",
|
|
detail_url="https://example.com/phone/1",
|
|
)
|
|
phone_service = mock.Mock()
|
|
phone_service.enabled = True
|
|
phone_service.max_attempts = 1
|
|
phone_service.acquire_phone.return_value = entry
|
|
phone_service.prefix_hint.return_value = "+447000"
|
|
|
|
with mock.patch("platforms.chatgpt.oauth_client.SMSToMePhoneService", return_value=phone_service):
|
|
with mock.patch.object(
|
|
client,
|
|
"_send_phone_number",
|
|
return_value=(False, None, "add-phone/send 失败: 400 - phone number is invalid"),
|
|
):
|
|
state = client._handle_add_phone_verification(
|
|
"device-id",
|
|
"Mozilla/5.0",
|
|
None,
|
|
None,
|
|
FlowState(page_type="add_phone"),
|
|
)
|
|
|
|
self.assertIsNone(state)
|
|
phone_service.mark_blacklisted.assert_called_once_with(entry.phone)
|
|
self.assertIn("add_phone 阶段失败", client.last_error)
|
|
|
|
def test_handle_add_phone_does_not_blacklist_whatsapp_channel(self):
|
|
client = OAuthClient(config={}, verbose=False)
|
|
client._log = lambda _msg: None
|
|
entry = PhoneEntry(
|
|
country_slug="united-kingdom",
|
|
phone="+447000000002",
|
|
detail_url="https://example.com/phone/2",
|
|
)
|
|
phone_service = mock.Mock()
|
|
phone_service.enabled = True
|
|
phone_service.max_attempts = 1
|
|
phone_service.acquire_phone.return_value = entry
|
|
phone_service.prefix_hint.return_value = "+447000"
|
|
|
|
next_state = FlowState(
|
|
page_type="phone_otp_verification",
|
|
continue_url="https://auth.openai.com/phone-verification",
|
|
)
|
|
|
|
with mock.patch("platforms.chatgpt.oauth_client.SMSToMePhoneService", return_value=phone_service):
|
|
with mock.patch.object(client, "_send_phone_number", return_value=(True, next_state, "")):
|
|
with mock.patch.object(
|
|
client,
|
|
"_decode_oauth_session_cookie",
|
|
return_value={
|
|
"phone_verification_channel": "whatsapp",
|
|
"phone_number": entry.phone,
|
|
},
|
|
):
|
|
state = client._handle_add_phone_verification(
|
|
"device-id",
|
|
"Mozilla/5.0",
|
|
None,
|
|
None,
|
|
FlowState(page_type="add_phone"),
|
|
)
|
|
|
|
self.assertIsNone(state)
|
|
phone_service.mark_blacklisted.assert_not_called()
|
|
self.assertIn("whatsapp", client.last_error)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|