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, commit_status_transaction, default_input_file, default_proxy_file, ensure_output_files, iter_findings, load_checked_statuses, load_known_keys, load_proxies, mask_secret, read_plain_keys, record_validation_result, recover_status_transaction, request_error_message, require_provider_authority, service_output_dir, should_skip_key, write_keycheck_event, ) SERVICE = "groq" DETECTOR = "Groq" 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, "groqChecked.txt") RESULTS_FILE = os.path.join(OUTPUT_DIR, "groqResults.jsonl") STATUS_FILES = { "VALID": os.path.join(OUTPUT_DIR, "groqAlive.txt"), "NO_BALANCE": os.path.join(OUTPUT_DIR, "groqNoBalance.txt"), "DEAD": os.path.join(OUTPUT_DIR, "groqDead.txt"), "RESTRICTED": os.path.join(OUTPUT_DIR, "groqRestricted.txt"), "LIMITED": os.path.join(OUTPUT_DIR, "groqLimited.txt"), "NO_CONTEXT": os.path.join(OUTPUT_DIR, "groqNoContext.txt"), "NETWORK": os.path.join(OUTPUT_DIR, "groqNetwork.txt"), "UNKNOWN": os.path.join(OUTPUT_DIR, "groqUnknown.txt"), } GROQ_KEY_REGEX = re.compile(r"\bgsk_[A-Za-z0-9_-]{20,}\b") MODELS_URL = "https://api.groq.com/openai/v1/models" CHAT_URL = "https://api.groq.com/openai/v1/chat/completions" CHAT_MODEL_PRIORITY = ( "llama-3.1-8b-instant", "llama-3.3-70b-versatile", "llama3-8b-8192", "llama3-70b-8192", "mixtral-8x7b-32768", "gemma2-9b-it", ) NO_BALANCE_MARKERS = ( "quota", "billing", "balance", "credit", "payment", "insufficient", "depleted", ) def ensure_files(): ensure_output_files([CHECKED_FILE, RESULTS_FILE, *STATUS_FILES.values()]) recover_status_transaction(CHECKED_FILE, STATUS_FILES) def extract_candidates(input_file, plain_files): seen_plain = set() for item in iter_findings(input_file, [DETECTOR]): key = item["raw"] if key and GROQ_KEY_REGEX.fullmatch(key): yield key, item["source"], item["finding"] for item in read_plain_keys(plain_files, GROQ_KEY_REGEX): key = item["key"] if key not in seen_plain: seen_plain.add(key) yield key, item["source"], {} def classify_groq_response(response): message = request_error_message(response).lower() if response.status_code == 401: return "DEAD" if response.status_code == 403: return "RESTRICTED" if response.status_code == 429: if any(marker in message for marker in NO_BALANCE_MARKERS): return "NO_BALANCE" return "LIMITED" return classify_common_http_status(response.status_code) def notable_models(payload): models = payload.get("data", []) if isinstance(payload, dict) else [] ids = [] for item in models: if isinstance(item, dict) and item.get("id"): ids.append(str(item.get("id"))) priority = [] for marker in ("llama", "mixtral", "gemma", "whisper"): for model in ids: if marker in model.lower() and model not in priority: priority.append(model) return priority[:20], len(ids), ids def choose_chat_model(model_ids): model_ids = [str(model or "") for model in model_ids if model] by_lower = {model.lower(): model for model in model_ids} for model in CHAT_MODEL_PRIORITY: if model.lower() in by_lower: return by_lower[model.lower()] for marker in ("llama", "mixtral", "gemma"): for model in model_ids: lowered = model.lower() if marker in lowered and "whisper" not in lowered and "guard" not in lowered: return model return "" def probe_chat_completion(key, model, proxy, timeout, debug=False): if not model: return {"status": "NO_CONTEXT", "message": "no chat-capable model from /models", "model": ""} headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"} payload = {"model": model, "messages": [{"role": "user", "content": "ping"}], "max_tokens": 1} try: response = requests.post(CHAT_URL, headers=headers, json=payload, proxies=proxy, timeout=timeout) except requests.RequestException as exc: return {"status": "NETWORK", "message": str(exc), "model": model} if debug: print(f" DEBUG chat ping {model}: HTTP {response.status_code}: {response.text[:500].replace(key, '***REDACTED***')}") if response.status_code == 200: return {"status": "GENERATION_OK", "message": "chat completion accepted", "model": model} return { "status": classify_groq_response(response), "http_status": response.status_code, "message": request_error_message(response).replace(key, "***REDACTED***"), "model": model, } def check_key(key, proxy, timeout, debug=False): headers = {"Authorization": f"Bearer {key}", "Accept": "application/json"} try: response = requests.get(MODELS_URL, headers=headers, proxies=proxy, timeout=timeout) except requests.RequestException as exc: return {"status": "NETWORK", "message": str(exc)} if debug: print(f" DEBUG /models: HTTP {response.status_code}: {response.text[:500].replace(key, '***REDACTED***')}") if response.status_code == 200: try: payload = response.json() except ValueError: payload = {} models, model_count, model_ids = notable_models(payload) chat_model = choose_chat_model(model_ids) probe = probe_chat_completion(key, chat_model, proxy, timeout, debug) if probe.get("status") != "GENERATION_OK": return { "status": probe.get("status") or "UNKNOWN", "message": probe.get("message", ""), "model_count": model_count, "models": models, "llm_probe_status": probe.get("status"), "llm_probe_model": probe.get("model", chat_model), "llm_probe_http_status": probe.get("http_status"), } return { "status": "VALID", "message": f"chat ping ok; model={chat_model}; models={model_count}", "model_count": model_count, "models": models, "llm_probe_status": probe.get("status"), "llm_probe_model": chat_model, } return { "status": classify_groq_response(response), "http_status": response.status_code, "message": request_error_message(response).replace(key, "***REDACTED***"), } def write_result(key, result, source, finding): status = result.get("status") or "UNKNOWN" write_keycheck_event(SERVICE, RESULTS_FILE, key, result, source, finding, DETECTOR) extra = ",".join(result.get("models") or [])[:500] if status == "VALID" else source commit_status_transaction( CHECKED_FILE, STATUS_FILES, key, status, result.get("message", ""), extra, ) record_validation_result(SERVICE, key, result, source, finding, DETECTOR) def parse_args(): parser = argparse.ArgumentParser(description="Groq 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=15) 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-restricted", 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") parser.add_argument("--debug", 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.add("UNKNOWN") if args.retry_restricted: retry_statuses.add("RESTRICTED") if args.retry_no_balance: retry_statuses.add("NO_BALANCE") if args.retry_valid: retry_statuses.add("VALID") print("--- Groq key checker ---") processed = 0 skipped = 0 for key, source, finding in extract_candidates(args.input, args.plain): if should_skip_key(key, checked, known, args, retry_statuses, service=SERVICE, source=source, finding=finding, detector=DETECTOR): skipped += 1 continue if args.max_keys and processed >= args.max_keys: break processed += 1 print(f"\n[{processed}] Groq candidate {mask_secret(key)} from {source}") proxy = next(proxy_cycler) if proxy_cycler else None result = check_key(key, proxy, args.timeout, args.debug) 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()