Initial commit: grok-free-register-oss
Open-source Grok free registration CLI, xai_enroller auth pipeline, local auth service, tests and docs.
This commit is contained in:
commit
d10009d639
72 files changed
+18752
No files matched your search
@@ -0,0 +1,188 @@
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
import httpx
|
||||
|
||||
from xai_enroller.coordinator import EnrollmentCoordinator
|
||||
from xai_enroller.executors import PlaywrightExecutor
|
||||
from xai_enroller.models import SourceRecord
|
||||
from xai_enroller.protocol import XAIProfile, XAIProtocol
|
||||
from xai_enroller.sinks import CPAAuthFileSink
|
||||
|
||||
|
||||
class SingleSource:
|
||||
async def records(self):
|
||||
yield SourceRecord("source-1", "sso-secret")
|
||||
|
||||
|
||||
class FakeButton:
|
||||
async def count(self):
|
||||
return 1
|
||||
|
||||
@property
|
||||
def first(self):
|
||||
return self
|
||||
|
||||
async def click(self):
|
||||
return None
|
||||
|
||||
|
||||
class FakePage:
|
||||
async def goto(self, url, wait_until):
|
||||
self.url = url
|
||||
|
||||
def locator(self, selector):
|
||||
return self
|
||||
|
||||
async def inner_text(self):
|
||||
return "Authorize access"
|
||||
|
||||
def get_by_role(self, role, name):
|
||||
return FakeButton() if name == "Authorize" else type(
|
||||
"NoButton",
|
||||
(),
|
||||
{"count": staticmethod(lambda: asyncio.sleep(0, result=0))},
|
||||
)()
|
||||
|
||||
async def close(self):
|
||||
return None
|
||||
|
||||
|
||||
class FakeContext:
|
||||
def __init__(self, browser):
|
||||
self.browser = browser
|
||||
self.cookies = []
|
||||
|
||||
async def add_cookies(self, cookies):
|
||||
self.cookies.extend(cookies)
|
||||
|
||||
async def new_page(self):
|
||||
return FakePage()
|
||||
|
||||
async def close(self):
|
||||
self.browser.live_contexts -= 1
|
||||
|
||||
|
||||
class FakeBrowser:
|
||||
def __init__(self):
|
||||
self.launches = 0
|
||||
self.live_contexts = 0
|
||||
self.max_live_contexts = 0
|
||||
|
||||
async def new_context(self):
|
||||
self.live_contexts += 1
|
||||
self.max_live_contexts = max(self.max_live_contexts, self.live_contexts)
|
||||
return FakeContext(self)
|
||||
|
||||
async def close(self):
|
||||
return None
|
||||
|
||||
|
||||
class FakeChromium:
|
||||
def __init__(self, browser):
|
||||
self.browser = browser
|
||||
|
||||
async def launch(self, **options):
|
||||
self.browser.launches += 1
|
||||
return self.browser
|
||||
|
||||
|
||||
class FakePlaywright:
|
||||
def __init__(self, browser):
|
||||
self.chromium = FakeChromium(browser)
|
||||
|
||||
async def stop(self):
|
||||
return None
|
||||
|
||||
|
||||
class FakePlaywrightFactory:
|
||||
def __init__(self):
|
||||
self.browser = FakeBrowser()
|
||||
self.playwright = FakePlaywright(self.browser)
|
||||
|
||||
def __call__(self):
|
||||
factory = self
|
||||
|
||||
class Runner:
|
||||
async def start(self):
|
||||
return factory.playwright
|
||||
|
||||
return Runner()
|
||||
|
||||
|
||||
def test_adapter_boundary_hands_xai_credential_to_cpa_without_ledger_secrets(tmp_path):
|
||||
def xai_handler(request):
|
||||
if request.url.path == "/.well-known/openid-configuration":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"device_authorization_endpoint": "https://auth.x.ai/oauth2/device/code",
|
||||
"token_endpoint": "https://auth.x.ai/oauth2/token",
|
||||
},
|
||||
)
|
||||
if request.url.path == "/oauth2/device/code":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"device_code": "device-secret",
|
||||
"user_code": "ABCD",
|
||||
"verification_uri": "https://accounts.x.ai/oauth2/device",
|
||||
"verification_uri_complete": (
|
||||
"https://accounts.x.ai/oauth2/device?user_code=ABCD"
|
||||
),
|
||||
"expires_in": 60,
|
||||
"interval": 0,
|
||||
},
|
||||
)
|
||||
if request.url.path == "/oauth2/token":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"access_token": "access-secret",
|
||||
"refresh_token": "refresh-secret",
|
||||
"id_token": "id-secret",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 3600,
|
||||
"sub": "subject-1",
|
||||
},
|
||||
)
|
||||
raise AssertionError(f"unexpected xAI request: {request.url}")
|
||||
|
||||
cpa_requests = []
|
||||
|
||||
def cpa_handler(request):
|
||||
cpa_requests.append(request)
|
||||
return httpx.Response(201)
|
||||
|
||||
xai_client = httpx.AsyncClient(transport=httpx.MockTransport(xai_handler))
|
||||
cpa_client = httpx.AsyncClient(transport=httpx.MockTransport(cpa_handler))
|
||||
factory = FakePlaywrightFactory()
|
||||
coordinator = EnrollmentCoordinator(
|
||||
source=SingleSource(),
|
||||
protocol=XAIProtocol(xai_client, XAIProfile.default()),
|
||||
executor=PlaywrightExecutor(playwright_factory=factory),
|
||||
sink=CPAAuthFileSink(
|
||||
"https://cpa.example",
|
||||
"management-secret",
|
||||
cpa_client,
|
||||
name_secret=b"name-secret",
|
||||
),
|
||||
ledger_path=tmp_path / "ledger.db",
|
||||
ledger_salt=b"ledger-salt",
|
||||
)
|
||||
|
||||
try:
|
||||
results = asyncio.run(coordinator.run(target=1))
|
||||
finally:
|
||||
asyncio.run(xai_client.aclose())
|
||||
asyncio.run(cpa_client.aclose())
|
||||
|
||||
assert results[0].status.value == "imported"
|
||||
assert factory.browser.launches == 1
|
||||
assert factory.browser.max_live_contexts == 1
|
||||
assert cpa_requests[0].url.path == "/v0/management/auth-files"
|
||||
assert cpa_requests[0].url.params["name"].startswith("xai-")
|
||||
assert json.loads(cpa_requests[0].content)["refresh_token"] == "refresh-secret"
|
||||
ledger_bytes = (tmp_path / "ledger.db").read_bytes()
|
||||
for secret in ("sso-secret", "device-secret", "access-secret", "refresh-secret", "id-secret"):
|
||||
assert secret.encode() not in ledger_bytes
|
||||
Reference in new issue
Block a user