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:
1 parent
a3f698806b
commit
5d215e1649
684 files changed
+133838
No files matched your search
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Add newly-hunted keys (FreeModel / DeepSeek / Kimi) to NewAPI.
|
||||
|
||||
Reads each provider's non-401 key file, probes both endpoints to find
|
||||
which one actually accepts the key, creates a channel for every
|
||||
working combination, tests it, and auto-disables channels that fail
|
||||
(so they don't break routing, but can be re-enabled later).
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from newapi_client import (
|
||||
add_channel, list_channels, update_channel, test_channel,
|
||||
TYPE_OPENAI, TYPE_ANTHROPIC,
|
||||
)
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
HUNTER = HERE / "llm-key-hunter" / "results"
|
||||
|
||||
# Each entry: provider label, key file, list of endpoint specs
|
||||
# Endpoint spec: (channel_name_suffix, type, base_url, models, header_template)
|
||||
PROVIDERS = [
|
||||
{
|
||||
"name": "FreeModel",
|
||||
"file": HUNTER / "freemodel" / "all_non_401.txt",
|
||||
"parse": lambda line: line.split("|", 2)[1], # USABLE|key|src
|
||||
"endpoints": [
|
||||
{
|
||||
"suffix": "Anthropic",
|
||||
"type": TYPE_ANTHROPIC,
|
||||
"base_url": "https://cc.freemodel.dev",
|
||||
"models": (
|
||||
"claude-sonnet-4-6,claude-opus-4-6,claude-opus-5,"
|
||||
"claude-opus-4-8,claude-opus-4-7,claude-fable-5,"
|
||||
"claude-haiku-4-5,claude-sonnet-4-20250514,"
|
||||
"claude-opus-4-20250514,claude-3-5-haiku-20241022,"
|
||||
"claude-3-7-sonnet-20250219"
|
||||
),
|
||||
},
|
||||
{
|
||||
"suffix": "OpenAI",
|
||||
"type": TYPE_OPENAI,
|
||||
"base_url": "https://api.freemodel.dev",
|
||||
"models": (
|
||||
"gpt-5.6-luna,gpt-5.6-sol,gpt-5.6-terra,"
|
||||
"claude-sonnet-4-20250514"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "DeepSeek",
|
||||
"file": HUNTER / "deepseek" / "all_non_401.txt",
|
||||
"parse": lambda line: line.split("|", 2)[1],
|
||||
"endpoints": [
|
||||
{
|
||||
"suffix": "",
|
||||
"type": TYPE_OPENAI,
|
||||
"base_url": "https://api.deepseek.com",
|
||||
"models": "deepseek-chat,deepseek-reasoner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Kimi",
|
||||
"file": HUNTER / "kimi" / "all_non_401.txt",
|
||||
"parse": lambda line: line.split("|", 2)[1],
|
||||
"endpoints": [
|
||||
{
|
||||
"suffix": "",
|
||||
"type": TYPE_OPENAI,
|
||||
"base_url": "https://api.moonshot.cn",
|
||||
"models": (
|
||||
"moonshot-v1-8k,moonshot-v1-32k,moonshot-v1-128k,"
|
||||
"kimi-k2-0905-preview,kimi-k2-turbo-preview,"
|
||||
"kimi-latest"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def existing_channel_keys():
|
||||
"""Return set of keys already present in NewAPI (from full channel details)."""
|
||||
keys = set()
|
||||
for ch in list_channels():
|
||||
cid = ch["id"]
|
||||
try:
|
||||
from newapi_client import get_channel
|
||||
d = get_channel(cid)
|
||||
k = (d or {}).get("key", "")
|
||||
if k:
|
||||
keys.add(k)
|
||||
except Exception:
|
||||
pass
|
||||
return keys
|
||||
|
||||
|
||||
def main():
|
||||
print("Loading existing channels to avoid duplicates...")
|
||||
existing_keys = existing_channel_keys()
|
||||
print(f" {len(existing_keys)} unique keys already configured.\n")
|
||||
|
||||
added = []
|
||||
skipped = 0
|
||||
failed_test = 0
|
||||
|
||||
for prov in PROVIDERS:
|
||||
path = prov["file"]
|
||||
if not path.exists():
|
||||
print(f"[{prov['name']}] no file at {path}, skipping")
|
||||
continue
|
||||
|
||||
raw_keys = []
|
||||
seen = set()
|
||||
for line in path.read_text().splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
try:
|
||||
k = prov["parse"](line)
|
||||
except IndexError:
|
||||
continue
|
||||
if k and k not in seen:
|
||||
seen.add(k)
|
||||
raw_keys.append(k)
|
||||
|
||||
print(f"[{prov['name']}] {len(raw_keys)} keys from {path.name}")
|
||||
|
||||
for idx, key in enumerate(raw_keys, 1):
|
||||
if key in existing_keys:
|
||||
print(f" [{idx}/{len(raw_keys)}] {key[:18]}... already in NewAPI, skip")
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
for ep in prov["endpoints"]:
|
||||
suffix = ep["suffix"]
|
||||
name = f"{prov['name']}_{key[-6:]}"
|
||||
if suffix:
|
||||
name = f"{name}-{suffix}"
|
||||
|
||||
channel = {
|
||||
"name": name,
|
||||
"type": ep["type"],
|
||||
"key": key,
|
||||
"base_url": ep["base_url"],
|
||||
"models": ep["models"],
|
||||
"groups": ["default"],
|
||||
"model_mapping": "",
|
||||
"priority": 0,
|
||||
"weight": 0,
|
||||
"auto_ban": 1,
|
||||
}
|
||||
success, msg = add_channel(channel)
|
||||
if not success:
|
||||
print(f" [{idx}] {name} ADD FAIL: {msg}")
|
||||
continue
|
||||
|
||||
# find new channel id
|
||||
new_id = None
|
||||
for ch in list_channels():
|
||||
if ch["name"] == name:
|
||||
new_id = ch["id"]
|
||||
break
|
||||
if new_id is None:
|
||||
print(f" [{idx}] {name} added but couldn't find id")
|
||||
continue
|
||||
|
||||
# test it
|
||||
t_ok, t_msg, _ = test_channel(new_id)
|
||||
if t_ok:
|
||||
print(f" [{idx}] {name} ID={new_id} ✅ {t_msg[:80]}")
|
||||
added.append((new_id, name, key[:18], t_msg[:80]))
|
||||
else:
|
||||
# auto-disable so it doesn't burn retries
|
||||
update_channel(new_id, status=2)
|
||||
print(f" [{idx}] {name} ID={new_id} ❌ DISABLED ({t_msg[:80]})")
|
||||
failed_test += 1
|
||||
time.sleep(0.3)
|
||||
|
||||
print()
|
||||
|
||||
print("=== Summary ===")
|
||||
print(f" Added & test-passed: {len(added)}")
|
||||
print(f" Added but auto-disabled: {failed_test}")
|
||||
print(f" Skipped (already present): {skipped}")
|
||||
if added:
|
||||
print("\nLive channels:")
|
||||
for cid, name, k, msg in added:
|
||||
print(f" ID={cid:3d} {name:35s} key={k}... {msg}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user