#!/usr/bin/env python3 import os KF_BASE = os.path.dirname(os.path.abspath(__file__)) os.makedirs(os.path.join(KF_BASE, "data"), exist_ok=True) """Validate all tokens in gh_tokens.txt via GitHub API /user. Alive + scope info -> data/alive_tokens.json """ import json import concurrent.futures as cf import sys import time import requests TOKENS_FILE = os.path.join(KF_BASE, "gh_tokens.txt") OUT = os.path.join(KF_BASE, "data/alive_tokens.json") HEADERS_BASE = {"Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28"} def check(tok: str): try: r = requests.get("https://api.github.com/user", headers={**HEADERS_BASE, "Authorization": f"Bearer {tok}"}, timeout=12) if r.status_code != 200: return None u = r.json() # scopes header present on some responses scopes = r.headers.get("x-oauth-scopes", "") return {"pat": tok, "login": u.get("login"), "id": u.get("id"), "scopes": scopes, "created": u.get("created_at", "")[:10], "suspended": bool(u.get("suspended_at"))} except Exception: return None def main(): limit = int(sys.argv[1]) if len(sys.argv) > 1 else 0 toks = [t.strip() for t in open(TOKENS_FILE, encoding="utf-8") if t.strip().startswith("ghp_")] if limit: toks = toks[:limit] print(f"checking {len(toks)} tokens", flush=True) alive = [] done = 0 t0 = time.time() with cf.ThreadPoolExecutor(max_workers=64) as ex: for res in ex.map(check, toks): done += 1 if res: alive.append(res) if done % 250 == 0: print(f" [{done}/{len(toks)}] alive={len(alive)} " f"({time.time()-t0:.0f}s)", flush=True) with open(OUT, "w", encoding="utf-8") as f: json.dump(alive, f, indent=1) # stats with_repo = [a for a in alive if "repo" in a["scopes"]] with_repo_all = [a for a in alive if "repo" in a["scopes"] and "workflow" in a["scopes"]] print(f"\nTOTAL checked: {done}") print(f"ALIVE: {len(alive)}") print(f" with repo scope: {len(with_repo)}") print(f" with repo+workflow scope: {len(with_repo_all)}") print(f"saved -> {OUT}") if __name__ == "__main__": main()