Spaces:
Sleeping
Sleeping
Download db_api_keys.py from alesamodio/Socrates_docker: direct link, hf CLI and curl.
- Browser
- Download file 3.37 kB
-
https://huggingface.co/spaces/alesamodio/Socrates_docker/resolve/main/db_api_keys.py
- Command line
-
hf download hf://spaces/alesamodio/Socrates_docker/db_api_keys.py
-
curl -L -o db_api_keys.py https://huggingface.co/spaces/alesamodio/Socrates_docker/resolve/main/db_api_keys.py
3.37 kB
| """ | |
| db_api_keys.py β user-supplied Anthropic/OpenAI API keys (user_api_keys table). | |
| Ciphertext only ever leaves this module decrypted via | |
| get_active_decrypted_api_keys() / get_decrypted_api_key(), for runtime | |
| injection into an LLM call (see llm_client.py). Never log a decrypted value β | |
| see the hard rule in crypto_util.py. | |
| """ | |
| from db_client import supabase | |
| from crypto_util import encrypt_secret, decrypt_secret | |
| PROVIDERS = {"anthropic", "openai"} | |
| def get_api_key_status(user_id: str) -> dict: | |
| """{'anthropic': {'has_key': bool, 'active': bool, 'last4': str|None}, 'openai': {...}}. | |
| No decryption β safe for GET /profile/load.""" | |
| status = {p: {"has_key": False, "active": False, "last4": None} for p in PROVIDERS} | |
| try: | |
| resp = supabase.table("user_api_keys").select("provider,active,key_last4").eq("user_id", user_id).execute() | |
| for row in resp.data or []: | |
| provider = row.get("provider") | |
| if provider in status: | |
| status[provider] = { | |
| "has_key": True, | |
| "active": bool(row.get("active")), | |
| "last4": row.get("key_last4"), | |
| } | |
| except Exception as e: | |
| print(f"[get_api_key_status] failed for {user_id}: {e}") | |
| return status | |
| def get_decrypted_api_key(user_id: str, provider: str) -> str | None: | |
| """Decrypted key for runtime use only, or None if no active key is stored.""" | |
| resp = ( | |
| supabase.table("user_api_keys") | |
| .select("key_ciphertext") | |
| .eq("user_id", user_id) | |
| .eq("provider", provider) | |
| .eq("active", True) | |
| .execute() | |
| ) | |
| if not resp.data: | |
| return None | |
| return decrypt_secret(resp.data[0]["key_ciphertext"]) | |
| def get_active_decrypted_api_keys(user_id: str) -> dict: | |
| """{'anthropic': 'sk-...', 'openai': 'sk-...'} β only providers with an active | |
| stored key. Used once per request to populate llm_client's ContextVar.""" | |
| resp = supabase.table("user_api_keys").select("provider,key_ciphertext").eq("user_id", user_id).eq("active", True).execute() | |
| return {row["provider"]: decrypt_secret(row["key_ciphertext"]) for row in (resp.data or [])} | |
| def set_api_key(user_id: str, provider: str, raw_key: str) -> dict: | |
| """Encrypt and store raw_key, marking it active. Caller must have already | |
| validated raw_key with a live provider call β this function does not validate.""" | |
| ciphertext = encrypt_secret(raw_key) | |
| last4 = raw_key[-4:] if len(raw_key) >= 4 else raw_key | |
| supabase.table("user_api_keys").upsert({ | |
| "user_id": user_id, | |
| "provider": provider, | |
| "key_ciphertext": ciphertext, | |
| "key_last4": last4, | |
| "active": True, | |
| }).execute() | |
| return {"has_key": True, "active": True, "last4": last4} | |
| def set_active(user_id: str, provider: str, active: bool) -> dict: | |
| """Flip the use-my-key/use-default toggle without touching the stored ciphertext.""" | |
| supabase.table("user_api_keys").update({"active": active}).eq("user_id", user_id).eq("provider", provider).execute() | |
| status = get_api_key_status(user_id) | |
| return status.get(provider, {"has_key": False, "active": False, "last4": None}) | |
| def delete_api_key(user_id: str, provider: str) -> None: | |
| supabase.table("user_api_keys").delete().eq("user_id", user_id).eq("provider", provider).execute() | |