import base64 import subprocess from pathlib import Path from typing import Optional from fastapi import FastAPI, HTTPException from pydantic import BaseModel app = FastAPI(title="CryptoPro Linux CSP Service", version="0.1.0") CSPTEST = Path("/opt/cprocsp/bin/amd64/csptest") def run_cmd(cmd: list[str], input_bytes: Optional[bytes] = None, allow_fail: bool = False) -> str: try: proc = subprocess.run( cmd, input=input_bytes, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True, ) return proc.stdout.decode("utf-8", errors="replace") except subprocess.CalledProcessError as exc: output = exc.stdout.decode("utf-8", errors="replace") if exc.stdout else "" if allow_fail: return output raise HTTPException(status_code=500, detail={"cmd": cmd, "output": output}) @app.get("/health") def health(): if not CSPTEST.exists(): raise HTTPException(status_code=500, detail="csptest binary not found; ensure CryptoPro CSP is installed") return {"status": "ok", "csptest": str(CSPTEST)} @app.get("/license") def license_info(): output = run_cmd([str(CSPTEST), "-keyset", "-info"], allow_fail=True) return {"output": output} class HashRequest(BaseModel): data_b64: str @app.post("/hash") def hash_data(body: HashRequest): try: data = base64.b64decode(body.data_b64) except Exception: raise HTTPException(status_code=400, detail="Invalid base64") cmd = [str(CSPTEST), "-hash", "-in", "-", "-hash_alg", "gost12_256"] output = run_cmd(cmd, input_bytes=data) return {"output": output}