130 lines
6.2 KiB
Python
130 lines
6.2 KiB
Python
import unittest
|
|
from types import SimpleNamespace
|
|
from unittest.mock import Mock, patch
|
|
|
|
|
|
class FakeResponse:
|
|
def __init__(self, *, status_code=200, text="", json_data=None, headers=None):
|
|
self.status_code = status_code
|
|
self.text = text
|
|
self._json_data = json_data
|
|
self.headers = headers or {"content-type": "application/json"}
|
|
|
|
def json(self):
|
|
return self._json_data
|
|
|
|
|
|
class RegisterLiveSentinelTests(unittest.TestCase):
|
|
def test_register_authorize_continue_and_so_token_are_used(self):
|
|
from src.chatgpt_register_http_reverse import ChatGPTRegisterHTTPReverse
|
|
|
|
flow_history: list[str] = []
|
|
def build_token(flow: str) -> str:
|
|
flow_history.append(flow)
|
|
return f"{flow}-token"
|
|
|
|
def build_session_observer_token(flow: str) -> str:
|
|
flow_history.append("session_observer")
|
|
return "session-observer-token"
|
|
|
|
fake_http = SimpleNamespace(
|
|
request=Mock(return_value=FakeResponse(json_data={"accessToken": "at", "user": {"id": "uid"}})),
|
|
session=SimpleNamespace(cookies=SimpleNamespace(jar=[])),
|
|
)
|
|
fake_mail = SimpleNamespace(
|
|
create_mailbox=Mock(return_value={"address": "user@example.com", "id": "box-1", "password": ""}),
|
|
wait_for_otp=Mock(return_value="123456"),
|
|
)
|
|
solver = SimpleNamespace(
|
|
build_token=Mock(side_effect=build_token),
|
|
build_session_observer_token=Mock(side_effect=build_session_observer_token),
|
|
)
|
|
|
|
register = ChatGPTRegisterHTTPReverse(fake_http, fake_mail, sentinel_solver=solver)
|
|
|
|
order: list[str] = []
|
|
create_call_args: dict[str, str | None] = {}
|
|
|
|
def fake_authorize_continue(*args, **kwargs):
|
|
order.append("authorize_continue")
|
|
return "https://auth.openai.com/create-account/password"
|
|
|
|
def fake_attempt_register(*args, **kwargs):
|
|
order.append("attempt_register")
|
|
return FakeResponse(status_code=200), {"continue_url": "continue-1"}
|
|
|
|
def fake_attempt_create_account(*args, sentinel=None, sentinel_so=None, **kwargs):
|
|
order.append("attempt_create")
|
|
create_call_args["sentinel"] = sentinel
|
|
create_call_args["sentinel_so"] = sentinel_so
|
|
return FakeResponse(status_code=200), {"continue_url": "continue-3"}
|
|
|
|
with patch.object(register, "_bootstrap_chatgpt", return_value="csrf"), \
|
|
patch.object(register, "_signin_auth0", return_value="auth-url"), \
|
|
patch.object(register, "_follow_auth_redirects", return_value="https://auth.openai.com/create-account/password"), \
|
|
patch.object(register, "_accounts_api_base", return_value="https://auth.openai.com/api/accounts"), \
|
|
patch.object(register, "_register_endpoint", return_value="https://auth.openai.com/api/accounts/user/register"), \
|
|
patch.object(register, "_authorize_continue", side_effect=fake_authorize_continue, create=True) as authorize_continue, \
|
|
patch.object(register, "_open_continue_url", side_effect=["email-url", "about-you-url"]), \
|
|
patch.object(register, "_validate_otp", return_value="continue-2"), \
|
|
patch.object(register, "_finalize_auth_callback"), \
|
|
patch.object(register, "_attempt_register", side_effect=fake_attempt_register) as attempt_register, \
|
|
patch.object(register, "_attempt_create_account", side_effect=fake_attempt_create_account) as attempt_create:
|
|
result = register.register("Passw0rd!", "Jane Doe")
|
|
|
|
self.assertEqual(result["email"], "user@example.com")
|
|
self.assertEqual(
|
|
flow_history,
|
|
[
|
|
"authorize_continue",
|
|
"username_password_create",
|
|
"oauth_create_account",
|
|
"session_observer",
|
|
],
|
|
)
|
|
self.assertTrue(authorize_continue.called)
|
|
self.assertEqual(authorize_continue.call_args.args[1], "https://auth.openai.com/log-in-or-create-account?usernameKind=email")
|
|
self.assertLess(order.index("authorize_continue"), order.index("attempt_register"))
|
|
self.assertEqual(attempt_register.call_args.args[1], "https://auth.openai.com/create-account/password")
|
|
self.assertEqual(attempt_register.call_args.kwargs["sentinel"], "username_password_create-token")
|
|
self.assertEqual(create_call_args["sentinel"], "oauth_create_account-token")
|
|
self.assertEqual(create_call_args["sentinel_so"], "session-observer-token")
|
|
solver.build_session_observer_token.assert_called_once_with("oauth_create_account")
|
|
|
|
|
|
def test_authorize_continue_posts_screen_hint_and_json_headers(self):
|
|
from src.chatgpt_register_http_reverse import ChatGPTRegisterHTTPReverse
|
|
|
|
captured = {}
|
|
|
|
def fake_request(method, url, **kwargs):
|
|
captured['method'] = method
|
|
captured['url'] = url
|
|
captured['kwargs'] = kwargs
|
|
return FakeResponse(status_code=200, json_data={"continue_url": "https://auth.openai.com/create-account/password"})
|
|
|
|
fake_http = SimpleNamespace(
|
|
request=fake_request,
|
|
session=SimpleNamespace(cookies=SimpleNamespace(jar=[])),
|
|
)
|
|
fake_mail = SimpleNamespace()
|
|
register = ChatGPTRegisterHTTPReverse(fake_http, fake_mail, sentinel_solver=SimpleNamespace())
|
|
|
|
with patch.object(register, '_open_continue_url', return_value='https://auth.openai.com/create-account/password'):
|
|
result = register._authorize_continue(
|
|
'https://auth.openai.com/api/accounts',
|
|
'https://auth.openai.com/log-in-or-create-account?usernameKind=email',
|
|
'user@example.com',
|
|
sentinel='authorize-token',
|
|
)
|
|
|
|
self.assertEqual(result, 'https://auth.openai.com/create-account/password')
|
|
self.assertEqual(captured['method'], 'POST')
|
|
self.assertEqual(captured['kwargs']['json']['screen_hint'], 'login_or_signup')
|
|
self.assertEqual(captured['kwargs']['headers']['Accept'], 'application/json')
|
|
self.assertEqual(captured['kwargs']['headers']['openai-sentinel-token'], 'authorize-token')
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|