#!/usr/bin/env python3 """DeepSeek deep hunter. Pipeline: 1. Load all DeepSeek keys from extracted_keys.txt (sk-[a-f0-9]{32}). 2. Deep-verify each key against multiple endpoints: a. GET /user/balance — most reliable auth test b. POST /v1/chat/completions — deepseek-chat c. POST /v1/chat/completions — deepseek-reasoner 3. Classification rule (LO said: anything NOT 401 is kept): - 200 with valid balance/response → USABLE - balance available but <0 / 402 / 429 → NO_BALANCE (key valid) - 400/403/404/5xx → NO_ACCESS (key valid, endpoint/model issue) - network / timeout → UNKNOWN - 401 → DEAD (discard only this) Outputs (results/deepseek/): extracted_keys.txt — unique keys with source URLs usable.txt — 200 OK with positive balance / chat response no_balance.txt — valid key but no balance no_access.txt — valid key but endpoint/model error unknown.txt — network errors dead.txt — 401 only all_non_401.txt — combined live (everything but 401) """ import argparse import json import os import re import subprocess import sys import time import urllib.request import urllib.error from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path HERE = Path(__file__).parent RESULTS_DIR = HERE / "results" / "deepseek" RESULTS_DIR.mkdir(parents=True, exist_ok=True) EXTRACTED_FILE = RESULTS_DIR / "extracted_keys.txt" USABLE_FILE = RESULTS_DIR / "usable.txt" NO_BAL_FILE = RESULTS_DIR / "no_balance.txt" NO_ACC_FILE = RESULTS_DIR / "no_access.txt" UNKNOWN_FILE = RESULTS_DIR / "unknown.txt" DEAD_FILE = RESULTS_DIR / "dead.txt" NON401_FILE = RESULTS_DIR / "all_non_401.txt" SOURCE_FILE = HERE / "results" / "extracted_keys.txt" UA = "curl/8.5.0" BASE = "https://api.deepseek.com" def http_request(method, path, key, body=None, timeout=30): url = f"{BASE}{path}" headers = { "User-Agent": UA, "Accept": "*/*", "Authorization": f"Bearer {key}", } data = None if body is not None: data = json.dumps(body).encode() headers["Content-Type"] = "application/json" req = urllib.request.Request(url, data=data, headers=headers, method=method) try: with urllib.request.urlopen(req, timeout=timeout) as resp: return resp.getcode(), resp.read().decode("utf-8", errors="replace") except urllib.error.HTTPError as e: try: return e.code, e.read().decode("utf-8", errors="replace") except Exception: return e.code, "" except Exception as e: return 0, f"network: {type(e).__name__}: {e}" def classify_balance(code, body): """Classify using /user/balance result.""" if code == 200: try: data = json.loads(body) bal = data.get("balance_infos", []) if not bal: # is_available / balance fields if data.get("is_available") is True: return "USABLE", "balance: available" if data.get("is_available") is False: return "NO_BALANCE", "balance: unavailable" return "USABLE", f"balance: {body[:120]}" total = 0.0 for b in bal: try: total += float(b.get("total_balance", 0)) except (TypeError, ValueError): pass if total > 0: return "USABLE", f"balance: {total:.2f} {bal[0].get('currency','USD')}" return "NO_BALANCE", "balance: 0" except json.JSONDecodeError: return "USABLE", f"balance: {body[:120]}" if code in (402, 429): return "NO_BALANCE", f"balance HTTP {code}: {body[:120]}" if code == 401: return "DEAD", "401 unauthorized" if code == 0: return "UNKNOWN", body[:160] return "NO_ACCESS", f"balance HTTP {code}: {body[:160]}" def classify_chat(code, body): bl = (body or "").lower() if code == 200: if '"choices"' in bl or '"id"' in bl: return "USABLE", "chat: 200 OK" if any(x in bl for x in ("balance", "quota", "arrearage", "insufficient")): return "NO_BALANCE", f"chat: {body[:120]}" return "USABLE", f"chat: {body[:120]}" if code in (402, 429): return "NO_BALANCE", f"chat HTTP {code}: {body[:120]}" if code == 401: return "DEAD", "chat: 401" if code == 0: return "UNKNOWN", body[:160] return "NO_ACCESS", f"chat HTTP {code}: {body[:160]}" def verify_key(key): """Verify via balance endpoint, fall back to chat. Return (verdict, detail).""" rank = {"USABLE": 4, "NO_BALANCE": 3, "NO_ACCESS": 2, "UNKNOWN": 1, "DEAD": 0} best = "DEAD" best_detail = "" # 1) balance code, body = http_request("GET", "/user/balance", key) verdict, detail = classify_balance(code, body) if rank[verdict] > rank[best]: best, best_detail = verdict, detail # If balance says USABLE, we're done. if best == "USABLE": return best, best_detail # 2) chat completion — deepseek-chat code, body = http_request("POST", "/v1/chat/completions", key, body={ "model": "deepseek-chat", "messages": [{"role": "user", "content": "hi"}], "max_tokens": 1, }) verdict, detail = classify_chat(code, body) if rank[verdict] > rank[best]: best, best_detail = verdict, detail if best == "USABLE": return best, best_detail # 3) chat completion — deepseek-reasoner (some keys only have reasoner access) code, body = http_request("POST", "/v1/chat/completions", key, body={ "model": "deepseek-reasoner", "messages": [{"role": "user", "content": "hi"}], "max_tokens": 1, }) verdict, detail = classify_chat(code, body) if rank[verdict] > rank[best]: best, best_detail = verdict, detail return best, best_detail def load_keys(): """Load unique DeepSeek keys from extracted_keys.txt; filter obvious fakes.""" keys = {} if not SOURCE_FILE.exists(): print(f"ERROR: {SOURCE_FILE} not found. Run extract.py first.", file=sys.stderr) sys.exit(1) fake_substrs = ("xxxx", "your-", "example", "test-key", "placeholder", "00000000000000000000000000000000", "1234567890abcdef") with open(SOURCE_FILE) as f: for line in f: line = line.strip() if not line.startswith("DeepSeek|"): continue parts = line.split("|", 3) if len(parts) < 3: continue key = parts[1] url = parts[2] if len(parts) > 2 else "" low = key.lower() if any(x in low for x in fake_substrs): continue if not re.fullmatch(r"sk-[a-f0-9]{32}", key): continue if key not in keys: keys[key] = url # write snapshot with open(EXTRACTED_FILE, "w") as f: for k, src in sorted(keys.items()): f.write(f"{k}|{src}\n") print(f"Loaded {len(keys)} unique DeepSeek keys (written to {EXTRACTED_FILE})") return keys def main(): ap = argparse.ArgumentParser() ap.add_argument("--workers", type=int, default=10, help="Concurrent workers (default: 10)") ap.add_argument("--limit", type=int, default=0, help="Only verify first N keys (0 = all)") args = ap.parse_args() keys = load_keys() if args.limit > 0: keys = dict(list(keys.items())[:args.limit]) print(f" (limited to first {args.limit})") if not keys: print("No keys to verify.") return print(f"\nDeep verifying {len(keys)} keys against api.deepseek.com (workers={args.workers})...") print("Rule: only 401 = dead; everything else is kept.\n") buckets = {"USABLE": [], "NO_BALANCE": [], "NO_ACCESS": [], "UNKNOWN": [], "DEAD": []} details = [] processed = 0 start = time.time() with ThreadPoolExecutor(max_workers=args.workers) as pool: futs = {pool.submit(verify_key, k): (k, src) for k, src in keys.items()} for fut in as_completed(futs): k, src = futs[fut] processed += 1 try: verdict, detail = fut.result() except Exception as e: verdict, detail = "UNKNOWN", str(e) buckets[verdict].append((k, src)) details.append(f"{verdict:11s} | {k} | {detail} | src={src}") if processed % 25 == 0: el = time.time() - start print( f" [{processed}/{len(keys)}] " f"usable={len(buckets['USABLE'])} " f"nobal={len(buckets['NO_BALANCE'])} " f"noacc={len(buckets['NO_ACCESS'])} " f"unk={len(buckets['UNKNOWN'])} " f"dead={len(buckets['DEAD'])} " f"({processed/el:.1f}/s)" ) elapsed = time.time() - start print(f"\nDone in {elapsed:.1f}s") for name in ("USABLE", "NO_BALANCE", "NO_ACCESS", "UNKNOWN", "DEAD"): print(f" {name:11s}: {len(buckets[name])}") # Write buckets for name, path in [ ("USABLE", USABLE_FILE), ("NO_BALANCE", NO_BAL_FILE), ("NO_ACCESS", NO_ACC_FILE), ("UNKNOWN", UNKNOWN_FILE), ("DEAD", DEAD_FILE), ]: with open(path, "w") as f: for k, src in sorted(buckets[name]): f.write(f"{k}|{src}\n") print(f" written: {path}") # Combined non-401 with open(NON401_FILE, "w") as f: for name in ("USABLE", "NO_BALANCE", "NO_ACCESS", "UNKNOWN"): for k, src in sorted(buckets[name]): f.write(f"{name}|{k}|{src}\n") print(f" written: {NON401_FILE}") # Show usable if buckets["USABLE"]: print("\n=== USABLE keys (with positive balance) ===") for k, src in sorted(buckets["USABLE"]): print(f" {k} {src}") if __name__ == "__main__": main()