From eb31a0a504776a17865af5559e58850a3cd8b822 Mon Sep 17 00:00:00 2001 From: DevEnv nis2-agile Date: Mon, 9 Mar 2026 09:12:45 +0100 Subject: [PATCH] [FIX] simulate-nis2: seed DB diretto per evitare rate limit registrazione - dbSeedUser(): inserisce utenti demo direttamente nel DB MySQL (bypass HTTP rate limit) - ensureUser(): usa dbSeedUser() come metodo primario, API /register come fallback - Rimosse le 2 chiamate register doppie (DEMO_EMAIL + email reale) - Aggiunto seed consultant@nis2agile.demo + membership a tutte le org demo Co-Authored-By: Claude Sonnet 4.6 --- simulate-nis2.php | 107 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/simulate-nis2.php b/simulate-nis2.php index 6eb1eb4..93d2193 100644 --- a/simulate-nis2.php +++ b/simulate-nis2.php @@ -176,6 +176,39 @@ function apiOk(array $res, string $ctx = ''): bool // ── Idempotent helpers ─────────────────────────────────────────────────────── +/** + * Seed utente direttamente nel DB (bypassa rate limit HTTP). + * Ritorna true se inserito/già esistente. + */ +function dbSeedUser(string $fullName, string $email, string $password, string $role): bool +{ + $envFile = __DIR__ . '/.env'; + if (!is_file($envFile)) return false; + $env = []; + foreach (file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) { + if (str_starts_with(trim($line), '#') || !str_contains($line, '=')) continue; + [$k, $v] = explode('=', $line, 2); + $env[trim($k)] = trim($v); + } + try { + $dsn = sprintf('mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4', + $env['DB_HOST'] ?? '127.0.0.1', + $env['DB_PORT'] ?? '3306', + $env['DB_NAME'] ?? 'nis2_agile_db' + ); + $pdo = new PDO($dsn, $env['DB_USER'] ?? '', $env['DB_PASS'] ?? '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); + $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 10]); + $pdo->prepare( + 'INSERT INTO users (email, password_hash, full_name, role, is_active) + VALUES (?,?,?,?,1) + ON DUPLICATE KEY UPDATE password_hash=VALUES(password_hash), full_name=VALUES(full_name), role=VALUES(role), is_active=1' + )->execute([$email, $hash, $fullName, $role]); + return true; + } catch (\Throwable $e) { + return false; + } +} + /** Registra un utente se non esiste già, ritorna il JWT. */ function ensureUser(string $firstName, string $lastName, string $email, string $password, string $role = 'org_admin'): ?string { @@ -185,7 +218,7 @@ function ensureUser(string $firstName, string $lastName, string $email, string $ return $S['users'][$email]['jwt']; } - // Prova login + // Prova login prima (utente già esistente) $loginRes = api('POST', '/auth/login', ['email' => $email, 'password' => $password]); if (!empty($loginRes['data']['access_token'])) { $jwt = $loginRes['data']['access_token']; @@ -194,39 +227,33 @@ function ensureUser(string $firstName, string $lastName, string $email, string $ return $jwt; } - // Registrazione - $regRes = api('POST', '/auth/register', [ - 'full_name' => trim("$firstName $lastName"), - 'email' => DEMO_EMAIL !== $email ? DEMO_EMAIL : $email, - 'password' => $password, - 'role' => $role, - ]); - // Override email per demo (sempre DEMO_EMAIL ma tracking per slug) - $regRes2 = api('POST', '/auth/register', [ - 'full_name' => trim("$firstName $lastName"), - 'email' => $email, - 'password' => $password, - 'role' => $role, - ]); - if (!empty($regRes2['data']['access_token'])) { - $jwt = $regRes2['data']['access_token']; - $uid = $regRes2['data']['user']['id'] ?? null; - $S['users'][$email] = ['jwt' => $jwt, 'id' => $uid]; - ok("Registrato: $firstName $lastName <$email>"); - return $jwt; - } - if (!empty($regRes2['success'])) { - // Login dopo registrazione + // Seed diretto nel DB (evita rate limit HTTP su /auth/register) + $fullName = trim("$firstName $lastName"); + if (dbSeedUser($fullName, $email, $password, $role)) { $loginRes2 = api('POST', '/auth/login', ['email' => $email, 'password' => $password]); if (!empty($loginRes2['data']['access_token'])) { $jwt = $loginRes2['data']['access_token']; $S['users'][$email] = ['jwt' => $jwt, 'id' => $loginRes2['data']['user']['id'] ?? null]; - ok("Registrato + login: $firstName $lastName <$email>"); + ok("Registrato: $firstName $lastName <$email>"); return $jwt; } } - fail("Registrazione fallita per $email: " . ($regRes2['error'] ?? 'errore')); + // Fallback: registrazione via API + $regRes = api('POST', '/auth/register', [ + 'full_name' => $fullName, + 'email' => $email, + 'password' => $password, + 'role' => $role, + ]); + if (!empty($regRes['data']['access_token'])) { + $jwt = $regRes['data']['access_token']; + $S['users'][$email] = ['jwt' => $jwt, 'id' => $regRes['data']['user']['id'] ?? null]; + ok("Registrato (API): $firstName $lastName <$email>"); + return $jwt; + } + + fail("Registrazione fallita per $email: " . ($regRes['message'] ?? 'errore')); return null; } @@ -647,6 +674,34 @@ foreach ($COMPANIES as $slug => $comp) { info(" {$comp['name']}: {$comp['employees']} dip, fatturato " . number_format($comp['annual_turnover']/1000000, 1) . "M€, settore {$comp['sector']}"); } +// ── Seed consulente demo (cross-org, accesso a tutte le aziende) ───────────── +$consultantEmail = 'consultant@nis2agile.demo'; +$consultantJwt = ensureUser('Marco', 'Consulente', $consultantEmail, DEMO_PWD, 'consultant'); +if ($consultantJwt) { + // Aggiungi il consultant a tutte le org create + foreach ($S['orgs'] as $slug => $orgData) { + if (empty($orgData['id'])) continue; + $orgId = $orgData['id']; + // Verifica se già membro + $envFile = __DIR__ . '/.env'; + $env = []; + foreach (file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) { + if (!str_contains($line, '=')) continue; + [$k, $v] = explode('=', $line, 2); + $env[trim($k)] = trim($v); + } + try { + $dsn = sprintf('mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4', $env['DB_HOST']??'127.0.0.1', $env['DB_PORT']??'3306', $env['DB_NAME']??'nis2_agile_db'); + $pdo = new PDO($dsn, $env['DB_USER']??'', $env['DB_PASS']??'', [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]); + $uid = $S['users'][$consultantEmail]['id'] ?? null; + if ($uid) { + $pdo->prepare('INSERT IGNORE INTO user_organizations (user_id, organization_id, role) VALUES (?,?,\'consultant\')')->execute([$uid, $orgId]); + ok("Consultant aggiunto a org #{$orgId} ({$orgData['name']})"); + } + } catch (\Throwable) {} + } +} + // ──────────────────────────────────────────────────────────────────────────── // SIM-01 — FASE 3: Gap Assessment 80 domande per ogni azienda // ────────────────────────────────────────────────────────────────────────────