Initial server source import
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
import sys
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
|
||||
import requests
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from keycheck_common import (
|
||||
append_jsonl,
|
||||
classify_common_http_status,
|
||||
combined_provider_routing_hint,
|
||||
commit_status_transaction,
|
||||
default_input_file,
|
||||
default_proxy_file,
|
||||
ensure_output_files,
|
||||
iter_findings,
|
||||
keycheck_input_mode,
|
||||
load_checked_statuses,
|
||||
load_known_keys,
|
||||
load_proxies,
|
||||
mask_secret,
|
||||
provider_routing_database_failed,
|
||||
recover_status_transaction,
|
||||
request_error_message,
|
||||
record_validation_result,
|
||||
require_provider_authority,
|
||||
service_output_dir,
|
||||
should_skip_key,
|
||||
write_keycheck_event,
|
||||
)
|
||||
from keycheckers.provider_resolution import resolve_provider_key
|
||||
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
PARENT_DIR = os.path.dirname(SCRIPT_DIR)
|
||||
SERVICE = "deepseek"
|
||||
OUTPUT_DIR = os.getenv("KEYCHECK_OUTPUT_DIR") or service_output_dir(SERVICE)
|
||||
|
||||
INPUT_FILE = os.getenv("KEYCHECK_INPUT_FILE") or default_input_file()
|
||||
PROXY_FILE = os.getenv("KEYCHECK_PROXY_FILE") or default_proxy_file()
|
||||
CHECKED_FILE = os.path.join(OUTPUT_DIR, "deepseekChecked.txt")
|
||||
RESULTS_FILE = os.path.join(OUTPUT_DIR, "deepseekResults.jsonl")
|
||||
|
||||
STATUS_FILES = {
|
||||
"VALID": os.path.join(OUTPUT_DIR, "deepseekAlive.txt"),
|
||||
"NO_BALANCE": os.path.join(OUTPUT_DIR, "deepseekNoBalance.txt"),
|
||||
"DEAD": os.path.join(OUTPUT_DIR, "deepseekDead.txt"),
|
||||
"LIMITED": os.path.join(OUTPUT_DIR, "deepseekLimited.txt"),
|
||||
"NETWORK": os.path.join(OUTPUT_DIR, "deepseekNetwork.txt"),
|
||||
"NO_CONTEXT": os.path.join(OUTPUT_DIR, "deepseekNoContext.txt"),
|
||||
"UNKNOWN": os.path.join(OUTPUT_DIR, "deepseekUnknown.txt"),
|
||||
}
|
||||
|
||||
DEEPSEEK_REGEX = re.compile(r"sk-[a-z0-9]{32}")
|
||||
DEEPSEEK_DETECTOR_NAMES = {"deepseek", "deepseekapikey", "deepseek_api_key"}
|
||||
DEEPSEEK_EXPLICIT_DETECTOR_NAMES = {"deepseekapikey", "deepseek_api_key"}
|
||||
QWEN_EXPLICIT_DETECTOR_NAMES = {"qwendashscope", "qwen_dashscope"}
|
||||
KIMI_EXPLICIT_DETECTOR_NAMES = {"kimimoonshot", "moonshotai"}
|
||||
QWEN_CONTEXT_REGEX = re.compile(
|
||||
r"(?:DASHSCOPE_API_KEY|QWEN_API_KEY|dashscope|qwen|model[_-]?studio|bailian)",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
DEEPSEEK_CONTEXT_REGEX = re.compile(r"(?:DEEPSEEK_API_KEY|deepseek|api\.deepseek\.com)", re.IGNORECASE)
|
||||
KIMI_CONTEXT_REGEX = re.compile(
|
||||
r"(?:MOONSHOT_API_KEY|KIMI_API_KEY|api\.moonshot\.(?:ai|cn)|platform\.kimi\.(?:ai|com))",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
AMBIGUOUS_PROVIDER_HINT = "ambiguous_qwen_deepseek"
|
||||
AMBIGUOUS_GENERIC_SK_HINT = "ambiguous_generic_sk"
|
||||
GENERIC_SK_PROVIDERS = {"qwen", "deepseek", "kimi", "zai"}
|
||||
EXPLICIT_ASSIGNMENT_HINT_SOURCE = "explicit_assignment"
|
||||
|
||||
|
||||
def ensure_files():
|
||||
ensure_output_files([CHECKED_FILE, RESULTS_FILE, *STATUS_FILES.values()])
|
||||
recover_status_transaction(CHECKED_FILE, STATUS_FILES)
|
||||
|
||||
|
||||
def iter_candidate_decisions(input_file, plain_files):
|
||||
detector_names = ["DeepSeek", "DeepSeekApiKey", "DeepSeek_API_Key", "CustomRegex"]
|
||||
for item in iter_findings(input_file, detector_names):
|
||||
finding = item.get("finding") or {}
|
||||
if not finding_has_deepseek_detector(finding):
|
||||
continue
|
||||
key = item.get("credential_secret_text") or item["raw"]
|
||||
if key and DEEPSEEK_REGEX.fullmatch(key):
|
||||
hint = combined_provider_routing_hint(key, finding_provider_routing_hint(finding))
|
||||
if provider_routing_database_failed():
|
||||
raise RuntimeError("provider routing evidence lookup failed closed")
|
||||
yield key, item["source"], finding, hint
|
||||
|
||||
|
||||
def extract_candidates(input_file, plain_files):
|
||||
for key, source, finding, hint in iter_candidate_decisions(input_file, plain_files):
|
||||
if hint == "deepseek":
|
||||
yield key, source, finding
|
||||
|
||||
|
||||
def route_rejection_result(hint):
|
||||
normalized = str(hint or "missing").strip().lower()
|
||||
return {
|
||||
"status": "NO_CONTEXT",
|
||||
"routing_hint": normalized,
|
||||
"message": f"candidate is not safely attributable to DeepSeek; routing_hint={normalized}",
|
||||
}
|
||||
|
||||
|
||||
def finding_detector_names(finding):
|
||||
if not isinstance(finding, dict):
|
||||
return set()
|
||||
extra = finding.get("ExtraData") if isinstance(finding.get("ExtraData"), dict) else {}
|
||||
names = {
|
||||
str(finding.get("DetectorName") or finding.get("detector") or "").strip().lower(),
|
||||
str(extra.get("name") or "").strip().lower(),
|
||||
}
|
||||
return {name for name in names if name}
|
||||
|
||||
|
||||
def finding_has_deepseek_detector(finding):
|
||||
return bool(finding_detector_names(finding) & DEEPSEEK_DETECTOR_NAMES)
|
||||
|
||||
|
||||
def finding_has_explicit_detector(finding, detector_names):
|
||||
return bool(finding_detector_names(finding) & set(detector_names))
|
||||
|
||||
|
||||
def finding_provider_routing_hint(finding):
|
||||
if not isinstance(finding, dict):
|
||||
return ""
|
||||
context = finding.get("ScannerContext") if isinstance(finding.get("ScannerContext"), dict) else {}
|
||||
persisted_hint = context.get("provider_hint")
|
||||
if (
|
||||
context.get("provider_hint_source") == EXPLICIT_ASSIGNMENT_HINT_SOURCE
|
||||
and persisted_hint in (*GENERIC_SK_PROVIDERS, AMBIGUOUS_PROVIDER_HINT, AMBIGUOUS_GENERIC_SK_HINT)
|
||||
):
|
||||
return persisted_hint
|
||||
parts = []
|
||||
for key in ("nearby", "file"):
|
||||
if context.get(key):
|
||||
parts.append(str(context.get(key)))
|
||||
metadata = finding.get("SourceMetadata") if isinstance(finding.get("SourceMetadata"), dict) else {}
|
||||
data = metadata.get("Data") if isinstance(metadata.get("Data"), dict) else {}
|
||||
for details in data.values():
|
||||
if not isinstance(details, dict):
|
||||
continue
|
||||
for key in ("file", "repository", "repo", "link", "image"):
|
||||
if details.get(key):
|
||||
parts.append(str(details.get(key)))
|
||||
text = "\n".join(parts)
|
||||
evidence = set()
|
||||
if QWEN_CONTEXT_REGEX.search(text) or finding_has_explicit_detector(finding, QWEN_EXPLICIT_DETECTOR_NAMES):
|
||||
evidence.add("qwen")
|
||||
if DEEPSEEK_CONTEXT_REGEX.search(text) or finding_has_explicit_detector(finding, DEEPSEEK_EXPLICIT_DETECTOR_NAMES):
|
||||
evidence.add("deepseek")
|
||||
if KIMI_CONTEXT_REGEX.search(text) or finding_has_explicit_detector(finding, KIMI_EXPLICIT_DETECTOR_NAMES):
|
||||
evidence.add("kimi")
|
||||
if persisted_hint == AMBIGUOUS_PROVIDER_HINT:
|
||||
evidence.update(("qwen", "deepseek"))
|
||||
elif persisted_hint == AMBIGUOUS_GENERIC_SK_HINT:
|
||||
evidence.update(GENERIC_SK_PROVIDERS)
|
||||
elif persisted_hint in GENERIC_SK_PROVIDERS:
|
||||
evidence.add(persisted_hint)
|
||||
if len(evidence) > 1:
|
||||
return AMBIGUOUS_PROVIDER_HINT if evidence == {"qwen", "deepseek"} else AMBIGUOUS_GENERIC_SK_HINT
|
||||
return next(iter(evidence)) if evidence else ""
|
||||
|
||||
|
||||
def finding_has_ambiguous_provider_hint(finding):
|
||||
return finding_provider_routing_hint(finding) in (AMBIGUOUS_PROVIDER_HINT, AMBIGUOUS_GENERIC_SK_HINT)
|
||||
|
||||
|
||||
def finding_looks_like_qwen_context(finding):
|
||||
return finding_provider_routing_hint(finding) == "qwen"
|
||||
|
||||
|
||||
def check_key(key, proxy, timeout):
|
||||
url = "https://api.deepseek.com/user/balance"
|
||||
headers = {"Authorization": f"Bearer {key}"}
|
||||
try:
|
||||
response = requests.get(url, headers=headers, proxies=proxy, timeout=timeout)
|
||||
except requests.RequestException as exc:
|
||||
return {"status": "NETWORK", "message": str(exc)}
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
balance_infos = data.get("balance_infos", [])
|
||||
total_usd = 0.0
|
||||
for balance in balance_infos:
|
||||
amount = float(balance.get("total_balance", "0") or 0)
|
||||
currency = balance.get("currency", "USD")
|
||||
if currency == "CNY":
|
||||
amount *= 0.14
|
||||
total_usd += amount
|
||||
available = bool(data.get("is_available", False))
|
||||
status = "VALID" if available and total_usd > 0 else "NO_BALANCE"
|
||||
return {
|
||||
"status": status,
|
||||
"authenticated": True,
|
||||
"available": available,
|
||||
"balance_usd": round(total_usd, 4),
|
||||
"message": f"available={available}; balance=${total_usd:.4f}",
|
||||
}
|
||||
|
||||
status = classify_common_http_status(response.status_code)
|
||||
return {"status": status, "http_status": response.status_code, "message": request_error_message(response)}
|
||||
|
||||
|
||||
def write_result(key, result, source, finding):
|
||||
write_keycheck_event(SERVICE, RESULTS_FILE, key, result, source, finding, "DeepSeek")
|
||||
commit_status_transaction(
|
||||
CHECKED_FILE, STATUS_FILES, key, result["status"], result.get("message", ""), source,
|
||||
)
|
||||
record_validation_result(SERVICE, key, result, source, finding, "DeepSeek")
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="DeepSeek key checker")
|
||||
parser.add_argument("--input", default=INPUT_FILE)
|
||||
parser.add_argument("--plain", action="append", default=[])
|
||||
parser.add_argument("--proxy-file", default=PROXY_FILE)
|
||||
parser.add_argument("--timeout", type=int, default=20)
|
||||
parser.add_argument("--max-keys", type=int, default=0)
|
||||
parser.add_argument("--retry-network", action="store_true")
|
||||
parser.add_argument("--retry-limited", action="store_true")
|
||||
parser.add_argument("--retry-unknown", action="store_true")
|
||||
parser.add_argument("--retry-no-balance", action="store_true")
|
||||
parser.add_argument("--retry-valid", action="store_true")
|
||||
parser.add_argument("--recheck-all", action="store_true")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
require_provider_authority(SERVICE)
|
||||
args = parse_args()
|
||||
ensure_files()
|
||||
proxy_cycler = load_proxies(args.proxy_file)
|
||||
checked = load_checked_statuses(CHECKED_FILE)
|
||||
known = load_known_keys(CHECKED_FILE, STATUS_FILES)
|
||||
retry_statuses = set()
|
||||
if args.retry_network:
|
||||
retry_statuses.add("NETWORK")
|
||||
if args.retry_limited:
|
||||
retry_statuses.add("LIMITED")
|
||||
if args.retry_unknown:
|
||||
retry_statuses.update({"UNKNOWN", "NO_CONTEXT"})
|
||||
if args.retry_no_balance:
|
||||
retry_statuses.add("NO_BALANCE")
|
||||
if args.retry_valid:
|
||||
retry_statuses.add("VALID")
|
||||
|
||||
processed = 0
|
||||
skipped = 0
|
||||
postgres_mode = keycheck_input_mode() == "postgres"
|
||||
for key, source, finding, routing_hint in iter_candidate_decisions(args.input, args.plain):
|
||||
route_rejected = routing_hint != "deepseek"
|
||||
ambiguous_route = routing_hint in (AMBIGUOUS_PROVIDER_HINT, AMBIGUOUS_GENERIC_SK_HINT)
|
||||
if route_rejected and not postgres_mode:
|
||||
skipped += 1
|
||||
continue
|
||||
if not route_rejected and should_skip_key(key, checked, known, args, retry_statuses, service=SERVICE, source=source, finding=finding, detector="DeepSeek"):
|
||||
skipped += 1
|
||||
continue
|
||||
if args.max_keys and processed >= args.max_keys:
|
||||
break
|
||||
processed += 1
|
||||
print(f"\n[{processed}] DeepSeek candidate {mask_secret(key)} from {source}")
|
||||
if route_rejected and ambiguous_route:
|
||||
proxy = next(proxy_cycler) if proxy_cycler else None
|
||||
result = resolve_provider_key(
|
||||
key, finding, proxy, args.timeout,
|
||||
hint=routing_hint, origin_service=SERVICE,
|
||||
)
|
||||
elif route_rejected:
|
||||
result = route_rejection_result(routing_hint)
|
||||
else:
|
||||
proxy = next(proxy_cycler) if proxy_cycler else None
|
||||
result = check_key(key, proxy, args.timeout)
|
||||
print(f" STATUS: {result['status']} | {result.get('message', '')[:200]}")
|
||||
write_result(key, result, source, finding)
|
||||
known.add(key)
|
||||
checked[key] = result["status"]
|
||||
|
||||
print(f"\nDone. Processed={processed}, skipped={skipped}, results={RESULTS_FILE}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user