""" Přihlášení na portál VoZP pomocí certifikátu (bez NMSigneru). JAK TO FUNGUJE: Portál používá challenge-response autentizaci: 1. Skript načte přihlašovací stránku → dostane session cookie (SID) 2. Požádá server o zprávu k podpisu (challenge s časovým razítkem) 3. Podepíše ji certifikátem jako PKCS7/CMS detached signature (RSA + SHA-256) 4. Odešle podpis na server → server ověří a vrátí přihlášení 5. Výsledné cookies uloží do vozp_cookies.json pro další skripty POUŽITÍ: pip install requests cryptography python 01_prihlaseni.py CERTIFIKÁT: Exportuj z Windows: certmgr.msc → Osobní → pravý klik → Exportovat Formát: PKCS #12 (.PFX), bez CA řetězu Uložit do: ../../Certificates/MBQualifiedCert.pfx """ import json import os import requests from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.serialization import pkcs7, pkcs12 PFX_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../Certificates/MBQualifiedCert.pfx")) PFX_PASSWORD = b"Vlado7309208104++" COOKIES_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "vozp_cookies.json")) BASE_URL = "https://portal.vozp.cz" CHALLENGE_URL = f"{BASE_URL}/json-api/prihlaseni/prihlasovaci-zprava" CERTLOGIN_URL = f"{BASE_URL}/json-api/prihlaseni/prihlaseni-certifikatem" def main() -> None: session = requests.Session() session.headers.update({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "X-Requested-With": "XMLHttpRequest", "Origin": BASE_URL, "Referer": BASE_URL + "/", }) # 1. Načti login stránku → SID cookie r = session.get(f"{BASE_URL}/app/prihlaseni") r.raise_for_status() session.cookies.set("pzp_sign", "CERT", domain="portal.vozp.cz", path="/") # 2. Získej challenge r = session.post(CHALLENGE_URL, json={"login_sign": "CERT"}, headers={"Content-Type": "application/json; charset=UTF-8"}) r.raise_for_status() zprava = r.json()["data"]["zprava"] # 3. Podepis (PKCS7 detached, RSA + SHA-256, bez CA řetězu) with open(PFX_PATH, "rb") as f: private_key, cert, _ = pkcs12.load_key_and_certificates(f.read(), PFX_PASSWORD) podpis = ( pkcs7.PKCS7SignatureBuilder() .set_data(zprava.encode("utf-8")) .add_signer(cert, private_key, hashes.SHA256()) .sign(serialization.Encoding.PEM, [pkcs7.PKCS7Options.DetachedSignature]) .decode("ascii").strip() ) # 4. Přihlas se r = session.post(CERTLOGIN_URL, json={"zprava": zprava, "podpis": podpis}, headers={"Content-Type": "application/json; charset=UTF-8"}) r.raise_for_status() data = r.json()["data"] if not data.get("prihlasen"): print(f"Přihlášení selhalo: {r.json()['errMsg']}") return print(f"Přihlášení úspěšné — {data.get('url', '')}") # 5. Ulož cookies cookies = [ { "name": c.name, "value": c.value, "domain": c.domain if c.domain.startswith(".") else "." + c.domain, "path": c.path or "/", "expires": int(c.expires) if c.expires else -1, "secure": bool(c.secure), "httpOnly": False, "sameSite": "Lax", } for c in session.cookies ] with open(COOKIES_FILE, "w", encoding="utf-8") as f: json.dump(cookies, f, indent=2, ensure_ascii=False) print(f"Uloženo {len(cookies)} cookies → {COOKIES_FILE}") if __name__ == "__main__": main()