Replace repository with grok-reg-protocol-cpa project
Overwrite previous grok-keygen contents with the local registration/CPA protocol codebase (secrets and runtime data excluded).
This commit is contained in:
commit
6f7c949681
33 files changed
+11125
No files matched your search
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Batch mint CPA xai-*.json from register accounts_cli.txt.
|
||||
|
||||
Default: headed Chromium + turnstilePatch (headless is Cloudflare-blocked on
|
||||
accounts.x.ai). Token poll is source of truth; consent Allow uses real click.
|
||||
|
||||
Example (from grok_reg project root):
|
||||
export DISPLAY=:0
|
||||
uv run python -u scripts/backfill_cpa_xai_from_accounts.py \\
|
||||
--limit 1 --probe
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(_ROOT))
|
||||
|
||||
from cpa_xai import existing_cpa_emails, mint_and_export, parse_accounts_file # noqa: E402
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument(
|
||||
"--accounts",
|
||||
default=str(_ROOT / "accounts_cli.txt"),
|
||||
)
|
||||
ap.add_argument(
|
||||
"--out-dir",
|
||||
default=str(_ROOT / "cpa_auths"),
|
||||
help="Primary output under register machine",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--cpa-dir",
|
||||
default="",
|
||||
help="Optional CPA hot-load auth-dir; files are copied here after success",
|
||||
)
|
||||
ap.add_argument("--limit", type=int, default=0, help="0 = all missing")
|
||||
ap.add_argument("--offset", type=int, default=0)
|
||||
ap.add_argument("--email", default="", help="Only this email")
|
||||
ap.add_argument("--skip-existing", action="store_true", default=True)
|
||||
ap.add_argument("--no-skip-existing", action="store_false", dest="skip_existing")
|
||||
ap.add_argument(
|
||||
"--headless",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Headless Chromium (usually blocked by Cloudflare on accounts.x.ai)",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--headed",
|
||||
action="store_true",
|
||||
default=True,
|
||||
help="Show browser (default; required for stable device consent)",
|
||||
)
|
||||
ap.add_argument("--probe", action="store_true", default=True)
|
||||
ap.add_argument("--no-probe", action="store_false", dest="probe")
|
||||
ap.add_argument("--probe-chat", action="store_true", default=False)
|
||||
ap.add_argument(
|
||||
"--proxy",
|
||||
default="",
|
||||
help="Outbound proxy. Empty → read register config.json cpa_proxy/proxy, else env",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--config",
|
||||
default=str(_ROOT / "config.json"),
|
||||
help="register config.json for cpa_proxy/proxy defaults",
|
||||
)
|
||||
ap.add_argument("--timeout", type=float, default=300.0)
|
||||
ap.add_argument("--sleep", type=float, default=3.0, help="Sleep between accounts")
|
||||
ap.add_argument(
|
||||
"--fail-log",
|
||||
default=str(_ROOT / "cpa_auths" / "backfill_failed.jsonl"),
|
||||
help="Append failures JSONL",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--force-standalone",
|
||||
action="store_true",
|
||||
default=True,
|
||||
help="Always open fresh Chromium (default)",
|
||||
)
|
||||
args = ap.parse_args()
|
||||
|
||||
if args.headless:
|
||||
args.headed = False
|
||||
else:
|
||||
args.headless = False
|
||||
|
||||
# Resolve proxy: CLI > config cpa_proxy/proxy > env
|
||||
if not args.proxy:
|
||||
try:
|
||||
cfg_path = Path(args.config)
|
||||
if cfg_path.is_file():
|
||||
cfg = json.loads(cfg_path.read_text(encoding="utf-8"))
|
||||
if isinstance(cfg, dict):
|
||||
cfg = {
|
||||
k: v
|
||||
for k, v in cfg.items()
|
||||
if not (isinstance(k, str) and (k.startswith("//") or k.startswith("#")))
|
||||
}
|
||||
args.proxy = (cfg.get("cpa_proxy") or cfg.get("proxy") or "").strip()
|
||||
if not args.cpa_dir:
|
||||
args.cpa_dir = (cfg.get("cpa_hotload_dir") or "").strip()
|
||||
except Exception as e: # noqa: BLE001
|
||||
print(f"warn: read config proxy failed: {e}", flush=True)
|
||||
if not args.proxy:
|
||||
args.proxy = (
|
||||
os.environ.get("https_proxy")
|
||||
or os.environ.get("HTTPS_PROXY")
|
||||
or os.environ.get("http_proxy")
|
||||
or ""
|
||||
).strip()
|
||||
print(f"proxy={args.proxy or '(none)'}", flush=True)
|
||||
|
||||
accounts = parse_accounts_file(args.accounts)
|
||||
if args.email:
|
||||
accounts = [a for a in accounts if a.email.lower() == args.email.lower()]
|
||||
accounts = accounts[args.offset :]
|
||||
|
||||
have = set()
|
||||
if args.skip_existing:
|
||||
have |= {e.lower() for e in existing_cpa_emails(args.out_dir)}
|
||||
if args.cpa_dir:
|
||||
have |= {e.lower() for e in existing_cpa_emails(args.cpa_dir)}
|
||||
|
||||
todo = []
|
||||
for a in accounts:
|
||||
if args.skip_existing and a.email.lower() in have:
|
||||
continue
|
||||
todo.append(a)
|
||||
if args.limit and len(todo) >= args.limit:
|
||||
break
|
||||
|
||||
print(f"accounts total={len(parse_accounts_file(args.accounts))} todo={len(todo)} out={args.out_dir}")
|
||||
Path(args.out_dir).mkdir(parents=True, exist_ok=True)
|
||||
if args.cpa_dir:
|
||||
Path(args.cpa_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
ok_n = fail_n = 0
|
||||
results = []
|
||||
for i, acc in enumerate(todo, 1):
|
||||
print(f"\n=== [{i}/{len(todo)}] {acc.email} ===", flush=True)
|
||||
|
||||
def log(msg: str, _email=acc.email) -> None:
|
||||
print(f"[{time.strftime('%H:%M:%S')}] [{_email}] {msg}", flush=True)
|
||||
|
||||
r = mint_and_export(
|
||||
email=acc.email,
|
||||
password=acc.password,
|
||||
auth_dir=args.out_dir,
|
||||
page=None,
|
||||
proxy=args.proxy or None,
|
||||
headless=args.headless,
|
||||
probe=args.probe,
|
||||
probe_chat=args.probe_chat,
|
||||
browser_timeout_sec=args.timeout,
|
||||
force_standalone=args.force_standalone,
|
||||
sso=acc.sso or None,
|
||||
prefer_protocol=True,
|
||||
log=log,
|
||||
)
|
||||
results.append(r)
|
||||
if r.get("ok") and r.get("path"):
|
||||
ok_n += 1
|
||||
# mirror into CPA auth-dir
|
||||
if args.cpa_dir:
|
||||
src = Path(r["path"])
|
||||
dst = Path(args.cpa_dir) / src.name
|
||||
shutil.copy2(src, dst)
|
||||
os.chmod(dst, 0o600)
|
||||
print(f"copied -> {dst}", flush=True)
|
||||
else:
|
||||
fail_n += 1
|
||||
if args.fail_log:
|
||||
Path(args.fail_log).parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(args.fail_log, "a", encoding="utf-8") as f:
|
||||
f.write(json.dumps(r, ensure_ascii=False) + "\n")
|
||||
if args.sleep and i < len(todo):
|
||||
time.sleep(args.sleep)
|
||||
|
||||
print(f"\n=== done ok={ok_n} fail={fail_n} ===", flush=True)
|
||||
summary = Path(args.out_dir) / f"backfill_summary_{int(time.time())}.json"
|
||||
summary.write_text(json.dumps(results, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
print(f"summary {summary}")
|
||||
return 0 if ok_n > 0 or not todo else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert ~/.grok/auth.json (Grok Build CLI) → CPA xai-<email>.json.
|
||||
|
||||
Usage (from grok_reg project root):
|
||||
uv run python scripts/export_cpa_xai_from_grok_auth.py \\
|
||||
--auth-json ~/.grok/auth.json \\
|
||||
--out-dir ./cpa_auths
|
||||
|
||||
Then any agent can use CPA:
|
||||
POST http://127.0.0.1:8317/v1/chat/completions model=grok-4.5
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(_ROOT))
|
||||
|
||||
from cpa_xai import ( # noqa: E402
|
||||
DEFAULT_BASE_URL,
|
||||
build_cpa_xai_auth,
|
||||
write_cpa_xai_auth,
|
||||
)
|
||||
|
||||
|
||||
def load_grok_auth(path: Path) -> dict:
|
||||
raw = json.loads(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(raw, dict) or not raw:
|
||||
raise SystemExit(f"empty or invalid auth.json: {path}")
|
||||
# grok stores one top-level key: "https://auth.x.ai::<client_id>"
|
||||
entry = next(iter(raw.values()))
|
||||
if not isinstance(entry, dict):
|
||||
raise SystemExit("auth.json entry is not an object")
|
||||
return entry
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument(
|
||||
"--auth-json",
|
||||
default=str(Path.home() / ".grok" / "auth.json"),
|
||||
help="Grok Build CLI auth.json path",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--out-dir",
|
||||
default=str(_ROOT / "cpa_auths"),
|
||||
help="Output dir for xai-*.json (register cpa_auths or CPA auth-dir)",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--base-url",
|
||||
default=DEFAULT_BASE_URL,
|
||||
help="Must be cli-chat-proxy for free Grok 4.5 promo",
|
||||
)
|
||||
ap.add_argument("--dry-run", action="store_true", help="Print JSON only, do not write")
|
||||
args = ap.parse_args()
|
||||
|
||||
entry = load_grok_auth(Path(args.auth_json).expanduser())
|
||||
access = entry.get("key") or entry.get("access_token") or ""
|
||||
refresh = entry.get("refresh_token") or ""
|
||||
email = entry.get("email") or ""
|
||||
sub = entry.get("user_id") or entry.get("principal_id") or entry.get("sub") or ""
|
||||
|
||||
payload = build_cpa_xai_auth(
|
||||
email=email,
|
||||
access_token=access,
|
||||
refresh_token=refresh,
|
||||
sub=sub,
|
||||
base_url=args.base_url,
|
||||
)
|
||||
|
||||
if args.dry_run:
|
||||
redacted = dict(payload)
|
||||
for k in ("access_token", "refresh_token", "id_token"):
|
||||
if k in redacted and isinstance(redacted[k], str) and redacted[k]:
|
||||
v = redacted[k]
|
||||
redacted[k] = v[:16] + f"...(len={len(v)})"
|
||||
print(json.dumps(redacted, indent=2, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
path = write_cpa_xai_auth(args.out_dir, payload)
|
||||
print(f"wrote {path}")
|
||||
print(f"email={payload.get('email')} base_url={payload.get('base_url')}")
|
||||
print("CPA will hot-reload; test:")
|
||||
print(' curl -sS http://127.0.0.1:8317/v1/models -H "Authorization: Bearer <CPA_KEY>" | grep grok-4.5')
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user