"""
sample_vulnerable_code.py - INTENTIONALLY VULNERABLE training sample
Chapter 4, Lab 4.3 (Capstone audit)

This file is a synthetic, entirely fictional code sample seeded with
the cryptographic pitfalls from Section 4.13 of the chapter.
It is NOT production code and must NEVER be imported or run as-is.

The student's task: run crypto_audit.py against this file, identify
every pitfall, map each to OWASP A02:2021, and propose a concrete fix.
"""

# ---- Pitfall 1: ECB mode (Section 4.5, field guide #2) ----------------------
from Crypto.Cipher import AES  # type: ignore  # pycryptodome if installed

def encrypt_user_data_WRONG(data: bytes, key: bytes) -> bytes:
    """ECB mode: identical blocks produce identical ciphertext. Never use."""
    cipher = AES.new(key, AES.MODE_ECB)
    # ... padding omitted for brevity
    return cipher.encrypt(data)


# ---- Pitfall 2: MD5 password storage (Section 4.7, field guide #4) ----------
import hashlib
import random  # <-- statistical PRNG (field guide #6)

def store_password_WRONG(password: str) -> str:
    """Unsalted MD5: rainbow-table vulnerable, fast to crack."""
    return hashlib.md5(password.encode()).hexdigest()


# ---- Pitfall 3: Bare SHA-256 prefix-MAC (Section 4.6.3, field guide #3) ----
import hmac  # correct import but used wrongly below

def compute_mac_WRONG(secret: bytes, message: bytes) -> str:
    """
    SHA-256(secret || message) - vulnerable to length extension.
    An attacker can append data and produce a valid tag without the secret.
    Fix: use hmac.new(secret, message, hashlib.sha256).hexdigest()
    """
    return hashlib.sha256(secret + message).hexdigest()


# ---- Pitfall 4: Non-constant-time comparison (Section 4.6, field guide #8) --
def verify_token_WRONG(provided: str, expected: str) -> bool:
    """
    String == comparison: bails on first differing byte, leaking timing.
    Fix: use hmac.compare_digest(provided, expected)
    """
    return provided == expected


# ---- Pitfall 5: Weak PRNG for session tokens (Section 4.3, field guide #6) --
def generate_session_token_WRONG() -> str:
    """
    random.randint is a statistical PRNG - predictable if state is observed.
    Fix: use secrets.token_hex(32)
    """
    return str(random.randint(100000, 999999))


# ---- Pitfall 6: Disabled TLS verification (Section 4.10, field guide #9) ---
import requests as req  # rename to avoid shadowing earlier import

def fetch_user_profile_WRONG(url: str) -> dict:
    """
    verify=False disables certificate validation: MITM trivial.
    Fix: remove verify=False and let requests use the system CA bundle.
    """
    resp = req.get(url, verify=False)  # noqa: S501
    return resp.json()


# ---- Pitfall 7: Static IV / nonce (Section 4.5.2, field guide #5) ----------
STATIC_IV = b"\x00" * 16  # hardcoded IV: nonce reuse guaranteed

def encrypt_log_entry_WRONG(key: bytes, plaintext: bytes) -> bytes:
    """
    CBC with a fixed IV: identical plaintexts produce identical ciphertexts,
    and a predictable IV enables the BEAST attack.
    Fix: generate a fresh random IV for every message.
    """
    from Crypto.Cipher import AES as _AES  # type: ignore
    cipher = _AES.new(key, _AES.MODE_CBC, STATIC_IV)
    return cipher.encrypt(plaintext)
