axiom-engine-api / app /api /keys.py
EATosin's picture
Axiom V4.6: Production-Locked. Multilingual Neural Core Operational.
f775c99
import secrets
import hashlib
import asyncio
from fastapi import APIRouter, Depends, HTTPException, Path
from pydantic import BaseModel, Field
from typing import List, Dict, Any, cast
from app.core.auth import get_current_user
from app.core.database import db
router = APIRouter()
# --- 1. STRICT SCHEMAS ---
class CreateKeyRequest(BaseModel):
# Firewall: Prevent DB Overflow by capping the name length
name: str = Field(..., min_length=1, max_length=64, description="Name identifier for the API key")
def generate_secure_key():
"""
Generates a production-grade API key.
Returns: (raw_key_for_user, hashed_key_for_db, key_hint_for_ui)
"""
raw_secret = secrets.token_hex(24)
full_key = f"axm_live_{raw_secret}"
key_hash = hashlib.sha256(full_key.encode()).hexdigest()
key_hint = f"{full_key[:12]}...{full_key[-4:]}"
return full_key, key_hash, key_hint
# --- 2. ASYNC ENDPOINTS ---
@router.post("/")
async def create_api_key(req: CreateKeyRequest, user_id: str = Depends(get_current_user)):
"""Generates a new API key. The raw key is returned ONLY ONCE."""
if not db: raise HTTPException(503, "DB Offline")
full_key, key_hash, key_hint = generate_secure_key()
# Non-blocking DB Insert
await asyncio.to_thread(
lambda: db.table("api_keys").insert({
"user_id": user_id,
"name": req.name,
"key_value": key_hash,
"key_hint": key_hint
}).execute()
)
return {
"status": "success",
"name": req.name,
"key_value": full_key,
"message": "Please copy this key now. You will not be able to see it again."
}
@router.get("/")
async def list_api_keys(user_id: str = Depends(get_current_user)):
"""Lists all active API keys using their secure hints asynchronously."""
if not db: raise HTTPException(503, "DB Offline")
res = await asyncio.to_thread(
lambda: db.table("api_keys")
.select("id, name, created_at, last_used_at, is_active, key_hint")
.eq("user_id", user_id)
.order("created_at", desc=True)
.execute()
)
return {"keys": cast(List[Dict[str, Any]], res.data)}
@router.delete("/{key_id}")
async def revoke_api_key(
key_id: str = Path(..., description="ID of the key to revoke"),
user_id: str = Depends(get_current_user)
):
"""Instantly revokes an API key (Sets is_active to False) without freezing the UI."""
if not db: raise HTTPException(503, "DB Offline")
await asyncio.to_thread(
lambda: db.table("api_keys")
.update({"is_active": False})
.eq("id", key_id)
.eq("user_id", user_id)
.execute()
)
return {"status": "revoked", "id": key_id}