75 lines
2.3 KiB
Python
Executable File
75 lines
2.3 KiB
Python
Executable File
#!/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()
|