KeyHunter parser v10 + 18 scanners + tests (synthetic fixtures only, no keys/db/tokens)
This commit is contained in:
81
merge_pat.py
Normal file
81
merge_pat.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""Merge PATs from ACCOUNTS_PAT.txt (and other pools) into gh_tokens.txt.
|
||||
Live-verify each PAT via /user endpoint; dedup; append only new valid ones."""
|
||||
import os
|
||||
KF_BASE = os.path.dirname(os.path.abspath(__file__))
|
||||
import json
|
||||
import time
|
||||
import urllib.request
|
||||
|
||||
POOLS = [
|
||||
r"C:/Users/User/tmp/ACCOUNTS_PAT.txt",
|
||||
]
|
||||
TARGET = os.path.join(KF_BASE, "gh_tokens.txt")
|
||||
UA = {"User-Agent": "Mozilla/5.0", "Accept": "application/vnd.github+json"}
|
||||
|
||||
|
||||
def log(msg):
|
||||
print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True)
|
||||
|
||||
|
||||
def check(pat):
|
||||
try:
|
||||
req = urllib.request.Request("https://api.github.com/user", headers={**UA, "Authorization": f"token {pat}"})
|
||||
with urllib.request.urlopen(req, timeout=20) as r:
|
||||
if r.status == 200:
|
||||
d = json.loads(r.read())
|
||||
return d.get("login", "?")
|
||||
except Exception as e:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def load_json_pool(path):
|
||||
pats = []
|
||||
try:
|
||||
d = json.load(open(path, encoding="utf-8"))
|
||||
for a in d:
|
||||
if isinstance(a, dict) and a.get("github_pat"):
|
||||
pats.append(a["github_pat"])
|
||||
except Exception:
|
||||
pass
|
||||
return pats
|
||||
|
||||
|
||||
def main():
|
||||
with open(TARGET, encoding="utf-8") as f:
|
||||
existing = {line.strip() for line in f if line.strip().startswith("ghp_")}
|
||||
log(f"existing tokens: {len(existing)}")
|
||||
total_new = 0
|
||||
for pool in POOLS:
|
||||
try:
|
||||
with open(pool, encoding="utf-8", errors="replace") as f:
|
||||
lines = [l.strip() for l in f if l.strip() and not l.startswith("#")]
|
||||
except FileNotFoundError:
|
||||
log(f"pool {pool} not found, skip")
|
||||
continue
|
||||
pats = []
|
||||
for l in lines:
|
||||
# login | pat | totp | password | email
|
||||
parts = [p.strip() for p in l.split("|")]
|
||||
for p in parts:
|
||||
if p.startswith("ghp_") or p.startswith("github_pat_"):
|
||||
pats.append(p)
|
||||
log(f"{pool}: {len(pats)} PATs parsed")
|
||||
for i, pat in enumerate(pats):
|
||||
if pat in existing:
|
||||
continue
|
||||
login = check(pat)
|
||||
if login:
|
||||
existing.add(pat)
|
||||
total_new += 1
|
||||
with open(TARGET, "a", encoding="utf-8") as f:
|
||||
f.write(pat + "\n")
|
||||
log(f" + {login} {pat[:14]}... valid, appended")
|
||||
else:
|
||||
log(f" x {pat[:14]}... dead")
|
||||
time.sleep(0.4)
|
||||
log(f"DONE: +{total_new} new live PATs, total {len(existing)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user