#!/usr/bin/env python3
"""
Esempio integrazione Vocea (whistleblowing) — Python 3.9+.
Dipendenze: pip install cryptography requests

Flusso:
  setup           — (admin, una tantum) genera 3 coppie RSA-4096, enrolla i key holder,
                    salva le chiavi private (servono per decifrare).
  submit [testo]  — recupera le chiavi pubbliche del canale, cifra (AES-256-GCM +
                    RSA-OAEP-SHA256) e invia la segnalazione (zero-knowledge).
  status <code>   — stato per codice di tracking.

Uso:
  HOST=https://api.vocea.cloud API_KEY=wbk_... SLUG=teleconsul python vocea_integration.py setup
  HOST=https://api.vocea.cloud API_KEY=wbk_... SLUG=teleconsul python vocea_integration.py submit
  HOST=https://api.vocea.cloud API_KEY=wbk_... SLUG=teleconsul python vocea_integration.py status <code>

⚠️ La chiave API è server-to-server: mai in browser/client. Le chiavi private dei key
   holder restano da voi (zero-knowledge).
"""
import base64, json, os, sys
import requests
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

HOST = os.environ.get("HOST", "https://api.vocea.cloud")
API_KEY = os.environ.get("API_KEY")
SLUG = os.environ.get("SLUG")
API = f"{HOST}/v1/integrations"
PRIV_FILE = f"keyholders-private.{SLUG}.json"  # ⚠️ custodire come segreto
b64 = lambda b: base64.b64encode(b).decode()

if not API_KEY or not SLUG:
    sys.exit("Imposta API_KEY e SLUG (env).")

def api(path, method="GET", body=None, auth=True):
    headers = {"Content-Type": "application/json"}
    if auth:
        headers["X-API-Key"] = API_KEY
    r = requests.request(method, API + path, headers=headers, data=json.dumps(body) if body else None, timeout=30)
    if not r.ok:
        raise RuntimeError(f"{method} {path} -> {r.status_code} {r.text}")
    return r.json() if r.text else {}

HOLDERS = [
    ("K_content", "ODV_MEMBER", "OdV - contenuto"),
    ("K_identity", "LEGAL_RPD", "RPD - identita"),
    ("K_metadata", "COMPLIANCE", "Compliance - metadati"),
]

def setup_key_holders():
    saved = {}
    for ck, role, name in HOLDERS:
        key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
        pub_pem = key.public_key().public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo).decode()
        priv_pem = key.private_bytes(serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()).decode()
        r = api("/keyholders", "POST", {
            "name": name, "email": f"{ck.lower()}@{SLUG}.example",
            "role": role, "controls_key": ck, "rsa_public_key_pem": pub_pem,
        })
        saved[ck] = {"id": r["id"], "private_key_pem": priv_pem}
        print(f"enrollato {ck} (id {r['id']})")
    with open(PRIV_FILE, "w") as f:
        json.dump(saved, f, indent=2)
    os.chmod(PRIV_FILE, 0o600)
    print(f"Chiavi private salvate in {PRIV_FILE} — CUSTODIRE COME SEGRETO.")

def seal(plaintext: str, pub_pem: str):
    aes_key = AESGCM.generate_key(bit_length=256)
    iv = os.urandom(12)
    ct_tag = AESGCM(aes_key).encrypt(iv, plaintext.encode(), None)  # ...|tag(16)
    ciphertext, tag = ct_tag[:-16], ct_tag[-16:]
    pub = serialization.load_pem_public_key(pub_pem.encode())
    wrapped = pub.encrypt(aes_key, padding.OAEP(mgf=padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None))
    return {"ciphertext": b64(ciphertext), "iv": b64(iv), "authTag": b64(tag), "wrapped": b64(wrapped)}

def submit_report(content="Segnalazione di prova inviata via API.", category="OTHER"):
    info = requests.get(f"{HOST}/tenants/{SLUG}/info", timeout=30).json()
    by = {k["controls_key"]: k for k in info["key_holders"]}
    if "K_content" not in by or "K_metadata" not in by:
        raise RuntimeError("Canale senza key holder: enrolla prima (setup).")
    c = seal(content, by["K_content"]["rsa_public_key_pem"])
    m = seal(json.dumps({"via": "api-example"}), by["K_metadata"]["rsa_public_key_pem"])
    out = api("/reports/submit", "POST", {
        "content_ciphertext": c["ciphertext"], "content_iv": c["iv"], "content_auth_tag": c["authTag"],
        "identity_ciphertext": None, "identity_iv": None, "identity_auth_tag": None,
        "metadata_ciphertext": m["ciphertext"], "metadata_iv": m["iv"], "metadata_auth_tag": m["authTag"],
        "key_wrappers": [
            {"keyholder_id": by["K_content"]["id"], "key_type": "K_content", "encrypted_aes_key": c["wrapped"]},
            {"keyholder_id": by["K_metadata"]["id"], "key_type": "K_metadata", "encrypted_aes_key": m["wrapped"]},
        ],
        "category": category, "submission_channel": "API",
    })
    print("Inviata. Codice di tracking:", out["anonymous_token"])
    return out["anonymous_token"]

if __name__ == "__main__":
    cmd = sys.argv[1] if len(sys.argv) > 1 else ""
    if cmd == "setup":
        setup_key_holders()
    elif cmd == "submit":
        submit_report(sys.argv[2] if len(sys.argv) > 2 else "Segnalazione di prova inviata via API.")
    elif cmd == "status":
        print(json.dumps(api(f"/reports/{sys.argv[2]}/status"), indent=2))
    else:
        print("comandi: setup | submit [testo] | status <code>")
