fix: complete remaining registration hardening
This commit is contained in:
+15
-20
@@ -193,6 +193,7 @@ def create_standalone_page(proxy: Optional[str] = None, headless: bool = False,
|
||||
|
||||
resolved = resolve_proxy(proxy)
|
||||
proxy_bridge = None
|
||||
browser = None
|
||||
chrome_proxy, proxy_bridge = prepare_chromium_proxy(resolved, log=logger)
|
||||
try:
|
||||
if chrome_proxy:
|
||||
@@ -200,19 +201,17 @@ def create_standalone_page(proxy: Optional[str] = None, headless: bool = False,
|
||||
logger("browser proxy=%s (chromium %s)" % (proxy_log_label(resolved), chrome_proxy))
|
||||
else:
|
||||
logger("browser proxy=(none)")
|
||||
|
||||
browser = Chromium(options)
|
||||
if proxy_bridge is not None:
|
||||
try:
|
||||
setattr(browser, "_cpa_proxy_bridge", proxy_bridge)
|
||||
except Exception:
|
||||
pass
|
||||
_register_mint_browser(browser)
|
||||
setattr(browser, "_cpa_proxy_bridge", proxy_bridge)
|
||||
page = browser.latest_tab
|
||||
_register_mint_browser(browser)
|
||||
logger("standalone chromium started")
|
||||
return browser, page
|
||||
except Exception:
|
||||
if proxy_bridge is not None:
|
||||
if browser is not None:
|
||||
close_standalone(browser)
|
||||
elif proxy_bridge is not None:
|
||||
try:
|
||||
proxy_bridge.stop()
|
||||
except Exception:
|
||||
@@ -846,6 +845,8 @@ def mint_with_browser(
|
||||
cookies: Any = None,
|
||||
reuse_browser: bool = True,
|
||||
recycle_every: int = 15,
|
||||
request_timeout_sec: float = 15.0,
|
||||
poll_timeout_sec: float = 15.0,
|
||||
):
|
||||
from .oauth_device import OAuthDeviceError, poll_device_token, request_device_code
|
||||
from .proxyutil import proxy_log_label, resolve_proxy, set_runtime_proxy
|
||||
@@ -858,19 +859,12 @@ def mint_with_browser(
|
||||
set_runtime_proxy(resolved or None)
|
||||
success = False
|
||||
try:
|
||||
last_error = None
|
||||
session = None
|
||||
for attempt in range(1, 4):
|
||||
try:
|
||||
session = request_device_code(proxy=resolved or None)
|
||||
last_error = None
|
||||
break
|
||||
except Exception as exc:
|
||||
last_error = exc
|
||||
logger("request_device_code attempt %s/3 failed: %s" % (attempt, exc))
|
||||
_sleep(1.5 * attempt)
|
||||
if session is None:
|
||||
raise last_error or RuntimeError("request_device_code failed")
|
||||
session = request_device_code(
|
||||
proxy=resolved or None,
|
||||
timeout=float(request_timeout_sec),
|
||||
cancel=cancel,
|
||||
retries=2,
|
||||
)
|
||||
logger("device user_code=%s expires_in=%s proxy=%s" % (session.user_code, session.expires_in, proxy_log_label(resolved) or "(none)"))
|
||||
if work_page is None:
|
||||
own_browser, work_page, owned = acquire_mint_browser(
|
||||
@@ -910,6 +904,7 @@ def mint_with_browser(
|
||||
log=logger,
|
||||
cancel=combined_cancel,
|
||||
proxy=resolved or None,
|
||||
timeout=float(poll_timeout_sec),
|
||||
)
|
||||
token_box["token"] = result
|
||||
stop_event.set()
|
||||
|
||||
@@ -20,6 +20,8 @@ def mint_and_export(
|
||||
recycle_every=15,
|
||||
log=None,
|
||||
cancel=None,
|
||||
request_timeout_sec=15.0,
|
||||
poll_timeout_sec=15.0,
|
||||
):
|
||||
logger = log or (lambda message: None)
|
||||
email = str(email or "").strip()
|
||||
@@ -40,6 +42,8 @@ def mint_and_export(
|
||||
cookies=cookies,
|
||||
reuse_browser=bool(reuse_browser),
|
||||
recycle_every=int(recycle_every or 0),
|
||||
request_timeout_sec=float(request_timeout_sec),
|
||||
poll_timeout_sec=float(poll_timeout_sec),
|
||||
)
|
||||
except Exception as exc:
|
||||
logger("mint failed: %s" % exc)
|
||||
|
||||
+57
-37
@@ -72,34 +72,56 @@ def _validate_endpoint(raw_url, field_name):
|
||||
return value
|
||||
|
||||
|
||||
def discover(proxy=None, timeout=30.0):
|
||||
opener = _build_opener(proxy)
|
||||
def discover(proxy=None, timeout=30.0, cancel=None, retries=2):
|
||||
request = urllib.request.Request(
|
||||
DISCOVERY_URL,
|
||||
method="GET",
|
||||
headers={"Accept": "application/json", "User-Agent": "grok-register-cpa/1.0"},
|
||||
)
|
||||
try:
|
||||
with opener.open(request, timeout=timeout) as response:
|
||||
body = response.read().decode("utf-8", errors="replace")
|
||||
status = int(getattr(response, "status", 200) or 200)
|
||||
except urllib.error.HTTPError as exc:
|
||||
body = exc.read().decode("utf-8", errors="replace")
|
||||
raise OAuthDeviceError("xAI discovery failed HTTP %s: %s" % (exc.code, body))
|
||||
except Exception as exc:
|
||||
raise OAuthDeviceError("xAI discovery request failed: %s" % exc)
|
||||
if status != 200:
|
||||
raise OAuthDeviceError("xAI discovery failed HTTP %s: %s" % (status, body))
|
||||
try:
|
||||
payload = json.loads(body)
|
||||
except Exception as exc:
|
||||
raise OAuthDeviceError("xAI discovery parse failed: %s" % exc)
|
||||
return {
|
||||
"device_authorization_endpoint": _validate_endpoint(
|
||||
payload.get("device_authorization_endpoint"), "device_authorization_endpoint"
|
||||
),
|
||||
"token_endpoint": _validate_endpoint(payload.get("token_endpoint"), "token_endpoint"),
|
||||
}
|
||||
last_error = None
|
||||
for attempt in range(max(int(retries), 0) + 1):
|
||||
_check_cancel(cancel)
|
||||
opener = _build_opener(proxy)
|
||||
try:
|
||||
with opener.open(request, timeout=float(timeout)) as response:
|
||||
body = response.read().decode("utf-8", errors="replace")
|
||||
status = int(getattr(response, "status", 200) or 200)
|
||||
_check_cancel(cancel)
|
||||
except urllib.error.HTTPError as exc:
|
||||
body = exc.read().decode("utf-8", errors="replace")
|
||||
raise OAuthDeviceError("xAI discovery failed HTTP %s: %s" % (exc.code, body))
|
||||
except Exception as exc:
|
||||
last_error = exc
|
||||
if not _is_transient_net_error(exc) or attempt >= int(retries):
|
||||
raise OAuthDeviceError("xAI discovery request failed: %s" % exc)
|
||||
_sleep_with_cancel(1.0 * (attempt + 1), cancel)
|
||||
continue
|
||||
if status != 200:
|
||||
raise OAuthDeviceError("xAI discovery failed HTTP %s: %s" % (status, body))
|
||||
try:
|
||||
payload = json.loads(body)
|
||||
except Exception as exc:
|
||||
raise OAuthDeviceError("xAI discovery parse failed: %s" % exc)
|
||||
return {
|
||||
"device_authorization_endpoint": _validate_endpoint(
|
||||
payload.get("device_authorization_endpoint"), "device_authorization_endpoint"
|
||||
),
|
||||
"token_endpoint": _validate_endpoint(payload.get("token_endpoint"), "token_endpoint"),
|
||||
}
|
||||
raise OAuthDeviceError("xAI discovery failed: %s" % last_error)
|
||||
|
||||
|
||||
def _check_cancel(cancel):
|
||||
if cancel and cancel():
|
||||
raise OAuthDeviceError("cancelled")
|
||||
|
||||
|
||||
def _sleep_with_cancel(seconds, cancel=None):
|
||||
deadline = time.time() + max(float(seconds), 0.0)
|
||||
while time.time() < deadline:
|
||||
_check_cancel(cancel)
|
||||
time.sleep(min(0.2, max(deadline - time.time(), 0.0)))
|
||||
_check_cancel(cancel)
|
||||
|
||||
|
||||
def _is_transient_net_error(exc):
|
||||
@@ -145,7 +167,7 @@ def _is_transient_net_error(exc):
|
||||
return False
|
||||
|
||||
|
||||
def _post_form(url, form, timeout=30.0, proxy=None, retries=0, retry_sleep=1.5):
|
||||
def _post_form(url, form, timeout=30.0, proxy=None, retries=0, retry_sleep=1.5, cancel=None):
|
||||
data = urllib.parse.urlencode(form).encode("utf-8")
|
||||
request = urllib.request.Request(
|
||||
url,
|
||||
@@ -159,11 +181,13 @@ def _post_form(url, form, timeout=30.0, proxy=None, retries=0, retry_sleep=1.5):
|
||||
)
|
||||
last_error = None
|
||||
for attempt in range(max(int(retries), 0) + 1):
|
||||
_check_cancel(cancel)
|
||||
opener = _build_opener(proxy)
|
||||
try:
|
||||
with opener.open(request, timeout=timeout) as response:
|
||||
body = response.read().decode("utf-8", errors="replace")
|
||||
status = int(getattr(response, "status", 200) or 200)
|
||||
_check_cancel(cancel)
|
||||
except urllib.error.HTTPError as exc:
|
||||
body = exc.read().decode("utf-8", errors="replace")
|
||||
status = int(exc.code)
|
||||
@@ -171,7 +195,7 @@ def _post_form(url, form, timeout=30.0, proxy=None, retries=0, retry_sleep=1.5):
|
||||
last_error = exc
|
||||
if not _is_transient_net_error(exc) or attempt >= int(retries):
|
||||
raise
|
||||
time.sleep(float(retry_sleep) * (attempt + 1))
|
||||
_sleep_with_cancel(float(retry_sleep) * (attempt + 1), cancel)
|
||||
continue
|
||||
try:
|
||||
return status, json.loads(body)
|
||||
@@ -182,8 +206,9 @@ def _post_form(url, form, timeout=30.0, proxy=None, retries=0, retry_sleep=1.5):
|
||||
raise OAuthDeviceError("form request failed without response")
|
||||
|
||||
|
||||
def request_device_code(client_id=CLIENT_ID, scope=SCOPE, timeout=30.0, proxy=None):
|
||||
discovery = discover(proxy=proxy, timeout=timeout)
|
||||
def request_device_code(client_id=CLIENT_ID, scope=SCOPE, timeout=15.0, proxy=None, cancel=None, retries=2):
|
||||
discovery = discover(proxy=proxy, timeout=timeout, cancel=cancel, retries=retries)
|
||||
_check_cancel(cancel)
|
||||
device_endpoint = discovery["device_authorization_endpoint"]
|
||||
token_endpoint = discovery["token_endpoint"]
|
||||
status, payload = _post_form(
|
||||
@@ -191,9 +216,11 @@ def request_device_code(client_id=CLIENT_ID, scope=SCOPE, timeout=30.0, proxy=No
|
||||
{"client_id": client_id, "scope": scope},
|
||||
timeout=timeout,
|
||||
proxy=proxy,
|
||||
retries=2,
|
||||
retries=retries,
|
||||
retry_sleep=1.0,
|
||||
cancel=cancel,
|
||||
)
|
||||
_check_cancel(cancel)
|
||||
if status != 200 or not isinstance(payload, dict):
|
||||
raise OAuthDeviceError("device code request failed HTTP %s: %r" % (status, payload))
|
||||
device_code = str(payload.get("device_code") or "").strip()
|
||||
@@ -216,14 +243,6 @@ def request_device_code(client_id=CLIENT_ID, scope=SCOPE, timeout=30.0, proxy=No
|
||||
)
|
||||
|
||||
|
||||
def _sleep_with_cancel(seconds, cancel=None):
|
||||
deadline = time.time() + max(float(seconds), 0.0)
|
||||
while time.time() < deadline:
|
||||
if cancel and cancel():
|
||||
raise OAuthDeviceError("cancelled")
|
||||
time.sleep(min(0.2, max(deadline - time.time(), 0.0)))
|
||||
|
||||
|
||||
def poll_device_token(
|
||||
device_code,
|
||||
token_endpoint,
|
||||
@@ -251,10 +270,11 @@ def poll_device_token(
|
||||
"device_code": str(device_code).strip(),
|
||||
"client_id": client_id,
|
||||
},
|
||||
timeout=min(float(timeout), 5.0),
|
||||
timeout=float(timeout),
|
||||
proxy=proxy,
|
||||
retries=0,
|
||||
retry_sleep=1.0,
|
||||
cancel=cancel,
|
||||
)
|
||||
net_streak = 0
|
||||
except Exception as exc:
|
||||
|
||||
Reference in New Issue
Block a user