#!/usr/bin/env python3 """ Script pour repeupler la base de données avec : - 1700 utilisateurs - 10 élections passées (historique) - 5 élections actives - 15 élections futures - Votes distribués aléatoirement (pas tous les users dans chaque election) """ import subprocess import random from datetime import datetime, timedelta import bcrypt import tempfile import os # Configuration DB_USER = "evoting_user" DB_PASSWORD = "evoting_pass123" DB_NAME = "evoting_db" HASHED_PASSWORD = bcrypt.hashpw(b"epita1234", b"$2b$12$zxCiC3MJpa32FfpX8u7Lx.").decode('utf-8') def run_sql(sql): """Exécuter du SQL via docker exec""" cmd = f'docker exec -i evoting_db mariadb -u {DB_USER} -p{DB_PASSWORD} {DB_NAME}' result = subprocess.run(cmd, shell=True, input=sql, capture_output=True, text=True) return result def log(msg, emoji="📝"): """Afficher un message formaté""" print(f"{emoji} {msg}") # ============================================================================ # PHASE 0: NETTOYER LA BASE DE DONNÉES # ============================================================================ log("PHASE 0: Nettoyage de la base de données...", "🧹") # Utiliser mysql client directement pour avoir plus de control cleanup_sql = """ SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS votes; DROP TABLE IF EXISTS candidates; DROP TABLE IF EXISTS elections; DROP TABLE IF EXISTS voters; SET FOREIGN_KEY_CHECKS=1; """ # Écrire dans un fichier temporaire et exécuter import tempfile import os with tempfile.NamedTemporaryFile(mode='w', suffix='.sql', delete=False) as f: f.write(cleanup_sql) temp_file = f.name try: cmd = f'docker exec -i evoting_db mariadb -u {DB_USER} -p{DB_PASSWORD} {DB_NAME} < {temp_file}' result = subprocess.run(cmd, shell=True, capture_output=True, text=True) if result.returncode == 0: log("✓ Anciennes tables supprimées", "✅") else: log(f"⚠️ Nettoyage échoué: {result.stderr}", "⚠️") finally: os.unlink(temp_file) # Recréer les tables create_tables_sql = """ CREATE TABLE voters ( id INT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, first_name VARCHAR(100), last_name VARCHAR(100), citizen_id VARCHAR(50) UNIQUE, public_key LONGBLOB, has_voted BOOLEAN DEFAULT FALSE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, certificate_hash VARCHAR(255), INDEX idx_email (email) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE elections ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, description TEXT, start_date DATETIME NOT NULL, end_date DATETIME NOT NULL, elgamal_p INT, elgamal_g INT, public_key LONGBLOB, is_active BOOLEAN DEFAULT FALSE, results_published BOOLEAN DEFAULT FALSE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_active (is_active) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE candidates ( id INT PRIMARY KEY AUTO_INCREMENT, election_id INT NOT NULL, name VARCHAR(255) NOT NULL, description TEXT, `order` INT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (election_id) REFERENCES elections(id) ON DELETE CASCADE, INDEX idx_election (election_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE votes ( id INT PRIMARY KEY AUTO_INCREMENT, voter_id INT NOT NULL, election_id INT NOT NULL, candidate_id INT NOT NULL, encrypted_vote LONGBLOB NOT NULL, zero_knowledge_proof LONGBLOB, ballot_hash VARCHAR(255), timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, ip_address VARCHAR(45), FOREIGN KEY (voter_id) REFERENCES voters(id) ON DELETE CASCADE, FOREIGN KEY (election_id) REFERENCES elections(id) ON DELETE CASCADE, FOREIGN KEY (candidate_id) REFERENCES candidates(id) ON DELETE CASCADE, INDEX idx_voter (voter_id), INDEX idx_election (election_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; """ with tempfile.NamedTemporaryFile(mode='w', suffix='.sql', delete=False) as f: f.write(create_tables_sql) temp_file = f.name try: cmd = f'docker exec -i evoting_db mariadb -u {DB_USER} -p{DB_PASSWORD} {DB_NAME} < {temp_file}' result = subprocess.run(cmd, shell=True, capture_output=True, text=True) if result.returncode == 0: log("✓ Tables recréées", "✅") else: log(f"Erreur: {result.stderr}", "❌") finally: os.unlink(temp_file) # ============================================================================ log("PHASE 1: Création de 1700 utilisateurs...", "👥") sql_users = "INSERT INTO voters (email, password_hash, first_name, last_name, citizen_id, certificate_hash, public_key, created_at) VALUES\n" values = [] # 1698 utilisateurs normaux for i in range(1, 1699): email = f"voter_{i}@voting.local" first_name = f"User{i}" last_name = f"Voter{i}" citizen_id = f"ID_{i:06d}" values.append(f"('{email}', '{HASHED_PASSWORD}', '{first_name}', '{last_name}', '{citizen_id}', 'cert_{i}', 'pk_{i}', NOW())") # 2 utilisateurs spéciaux special_users = [ ("new_user_e13_157@voting.local", "NewUser157", "Election13_157", "ID_SPEC_157"), ("new_user_e13_192@voting.local", "NewUser192", "Election13_192", "ID_SPEC_192"), ] for email, first_name, last_name, citizen_id in special_users: values.append(f"('{email}', '{HASHED_PASSWORD}', '{first_name}', '{last_name}', '{citizen_id}', 'cert_special', 'pk_special', NOW())") sql_users += ",\n".join(values) + ";" result = run_sql(sql_users) if result.returncode == 0: log("✓ 1700 utilisateurs créés", "✅") else: log(f"Erreur: {result.stderr}", "❌") # ============================================================================ # PHASE 2: CRÉER LES 30 ÉLECTIONS (10 passées + 5 actives + 15 futures) # ============================================================================ log("PHASE 2: Création des 30 élections...", "🗳️") now = datetime.now() elections = [] # 10 élections passées (historique) for i in range(1, 11): start = (now - timedelta(days=365-i*30)).strftime("%Y-%m-%d") end = (now - timedelta(days=365-(i*30)-7)).strftime("%Y-%m-%d") elections.append({ "name": f"Historical Election {i}", "description": f"Past election {i}", "start": start, "end": end, "is_active": 0 }) # 5 élections actives (en cours) for i in range(1, 6): start = (now - timedelta(days=7-i)).strftime("%Y-%m-%d") end = (now + timedelta(days=30+i)).strftime("%Y-%m-%d") elections.append({ "name": f"Active Election {i}", "description": f"Current election {i}", "start": start, "end": end, "is_active": 1 }) # 15 élections futures for i in range(1, 16): start = (now + timedelta(days=30+i*5)).strftime("%Y-%m-%d") end = (now + timedelta(days=37+i*5)).strftime("%Y-%m-%d") elections.append({ "name": f"Upcoming Election {i}", "description": f"Future election {i}", "start": start, "end": end, "is_active": 0 }) sql_elections = "INSERT INTO elections (name, description, start_date, end_date, elgamal_p, elgamal_g, public_key, is_active, results_published) VALUES\n" election_values = [] for idx, election in enumerate(elections, 1): election_values.append( f"('{election['name']}', '{election['description']}', '{election['start']}', '{election['end']}', '23', '5', 'pk_{idx}', {election['is_active']}, 0)" ) sql_elections += ",\n".join(election_values) + ";" result = run_sql(sql_elections) if result.returncode == 0: log(f"✓ 30 élections créées (10 passées + 5 actives + 15 futures)", "✅") else: log(f"Erreur: {result.stderr}", "❌") # ============================================================================ # PHASE 3: CRÉER LES CANDIDATS # ============================================================================ log("PHASE 3: Création des candidats...", "🎭") candidate_names = [ "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Emily Davis", "Frank Miller", "Grace Wilson", "Henry Moore" ] sql_candidates = "INSERT INTO candidates (election_id, name, description, `order`, created_at) VALUES\n" candidate_values = [] for election_id in range(1, 31): # 4-8 candidats par élection num_candidates = random.randint(4, 8) selected_candidates = random.sample(candidate_names, min(num_candidates, len(candidate_names))) for order, name in enumerate(selected_candidates, 1): candidate_values.append( f"({election_id}, '{name}', 'Candidate {name}', {order}, NOW())" ) sql_candidates += ",\n".join(candidate_values) + ";" result = run_sql(sql_candidates) if result.returncode == 0: log(f"✓ Candidats créés pour toutes les élections", "✅") else: log(f"Erreur: {result.stderr}", "❌") # ============================================================================ # PHASE 4: CRÉER LES VOTES # ============================================================================ log("PHASE 4: Création des votes...", "🗳️") sql_votes = "INSERT INTO votes (voter_id, election_id, candidate_id, encrypted_vote, ballot_hash, timestamp) VALUES\n" vote_values = [] # Pour chaque élection for election_id in range(1, 31): # Récupérer les candidats de cette élection result_candidates = run_sql(f"SELECT id FROM candidates WHERE election_id = {election_id};") candidate_ids = [] if result_candidates.returncode == 0: lines = result_candidates.stdout.strip().split('\n')[1:] for line in lines: if line.strip(): candidate_ids.append(int(line.split()[0])) if not candidate_ids: continue # Déterminer le nombre de votants pour cette élection # Entre 20% et 80% des utilisateurs votent pour cette élection num_voters = random.randint(int(1700 * 0.2), int(1700 * 0.8)) # Sélectionner les votants aléatoirement voter_ids = random.sample(range(1, 1701), num_voters) for voter_id in voter_ids: candidate_id = random.choice(candidate_ids) ballot_hash = f"hash_{voter_id}_{election_id}" vote_values.append( f"({voter_id}, {election_id}, {candidate_id}, 'encrypted_{voter_id}_{election_id}', '{ballot_hash}', NOW())" ) # Insérer tous les votes en batch batch_size = 1000 for i in range(0, len(vote_values), batch_size): batch = vote_values[i:i+batch_size] sql_batch = "INSERT INTO votes (voter_id, election_id, candidate_id, encrypted_vote, ballot_hash, timestamp) VALUES\n" sql_batch += ",\n".join(batch) + ";" result = run_sql(sql_batch) if result.returncode != 0: log(f"Erreur batch {i//batch_size}: {result.stderr}", "❌") log(f"✓ {len(vote_values)} votes créés", "✅") # ============================================================================ # PHASE 5: VOTES SPÉCIAUX POUR new_user_e13_192 # ============================================================================ log("PHASE 5: Configuration des votes pour new_user_e13_192...", "⚙️") # Récupérer l'ID de new_user_e13_192 result = run_sql("SELECT id FROM voters WHERE email = 'new_user_e13_192@voting.local';") special_user_id = None if result.returncode == 0 and result.stdout.strip(): lines = result.stdout.strip().split('\n') if len(lines) > 1: special_user_id = int(lines[1].split()[0]) if special_user_id: # Supprimer tous les votes actuels pour cet utilisateur run_sql(f"DELETE FROM votes WHERE voter_id = {special_user_id};") special_votes = [] # 10 votes pour les élections passées (1-10) for election_id in range(1, 11): result_cand = run_sql(f"SELECT id FROM candidates WHERE election_id = {election_id} LIMIT 1;") if result_cand.returncode == 0 and result_cand.stdout.strip(): lines = result_cand.stdout.strip().split('\n') if len(lines) > 1: candidate_id = int(lines[1].split()[0]) ballot_hash = f"hash_{special_user_id}_{election_id}" special_votes.append( f"({special_user_id}, {election_id}, {candidate_id}, 'encrypted_{special_user_id}_{election_id}', '{ballot_hash}', NOW())" ) # 4 votes pour les élections actives (11, 12, 14, 15) - PAS 13 for election_id in [11, 12, 14, 15]: result_cand = run_sql(f"SELECT id FROM candidates WHERE election_id = {election_id} LIMIT 1;") if result_cand.returncode == 0 and result_cand.stdout.strip(): lines = result_cand.stdout.strip().split('\n') if len(lines) > 1: candidate_id = int(lines[1].split()[0]) ballot_hash = f"hash_{special_user_id}_{election_id}" special_votes.append( f"({special_user_id}, {election_id}, {candidate_id}, 'encrypted_{special_user_id}_{election_id}', '{ballot_hash}', NOW())" ) # 4 votes pour les élections futures (21, 24, 27, 30) for election_id in [21, 24, 27, 30]: result_cand = run_sql(f"SELECT id FROM candidates WHERE election_id = {election_id} LIMIT 1;") if result_cand.returncode == 0 and result_cand.stdout.strip(): lines = result_cand.stdout.strip().split('\n') if len(lines) > 1: candidate_id = int(lines[1].split()[0]) ballot_hash = f"hash_{special_user_id}_{election_id}" special_votes.append( f"({special_user_id}, {election_id}, {candidate_id}, 'encrypted_{special_user_id}_{election_id}', '{ballot_hash}', NOW())" ) if special_votes: sql_special = "INSERT INTO votes (voter_id, election_id, candidate_id, encrypted_vote, ballot_hash, timestamp) VALUES\n" sql_special += ",\n".join(special_votes) + ";" result = run_sql(sql_special) if result.returncode == 0: log(f"✓ 18 votes spéciaux créés pour new_user_e13_192 (10 + 4 + 4)", "✅") else: log(f"Erreur: {result.stderr}", "❌") # ============================================================================ # PHASE 6: STATISTIQUES FINALES # ============================================================================ log("PHASE 6: Vérification des données...", "📊") result = run_sql(""" SELECT (SELECT COUNT(*) FROM elections) as total_elections, (SELECT COUNT(*) FROM voters) as total_voters, (SELECT COUNT(*) FROM candidates) as total_candidates, (SELECT COUNT(*) FROM votes) as total_votes; """) if result.returncode == 0: print("\n" + "="*60) print("✅ BASE DE DONNÉES REPUPLÉE AVEC SUCCÈS!") print("="*60) print(result.stdout) print("="*60) # Afficher les utilisateurs spéciaux result = run_sql("SELECT id, email, first_name, last_name FROM voters WHERE email LIKE 'new_user_e13_%' ORDER BY id;") if result.returncode == 0: print("\n" + "="*60) print("👤 UTILISATEURS SPÉCIAUX:") print("="*60) print(result.stdout) print("\n✅ Vous pouvez maintenant vous connecter avec:") print(" Email: new_user_e13_192@voting.local") print(" Mot de passe: epita1234") print(" Votes: 10 historiques + 4 actifs + 4 futurs") print(" Élection sans vote: Active Election 3 (ID 13)") print("="*60)