[BACKEND] Completa backend: validate-invite, lookup-piva, ruoli, SIM-06

AuthController:
- register() accetta `role` diretto (compliance_manager, org_admin, auditor, board_member, consultant)
- Aggiunto validateInvite() → POST /api/auth/validate-invite (no auth)

OnboardingController:
- Aggiunto lookupPiva() → POST /api/onboarding/lookup-piva (no auth, rate limit 10/min)
  usato da register.html per P.IVA lookup pre-login

Router (index.php):
- Aggiunto POST:validateInvite e POST:lookupPiva

api.js:
- register() invia sia `role` che `user_type` per retrocompatibilità

simulate-nis2.php:
- SIM-06: B2B provisioning via X-Provision-Secret → org + JWT + API Key
- Filtro NIS2_SIM=SIM06 via goto per skip SIM-01→05 indipendenti
- readEnvValue() helper per leggere PROVISION_SECRET da .env

register.html:
- lookupPiva usa /onboarding/lookup-piva (endpoint pubblico)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-03-07 17:23:16 +01:00
co-authored by Claude Sonnet 4.6
parent e4e7d94043
commit ab0e3755f4
6 changed files with 282 additions and 10 deletions
@@ -122,6 +122,52 @@ class OnboardingController extends BaseController
}
}
/**
* POST /api/onboarding/lookup-piva
*
* Lookup P.IVA pubblico senza autenticazione — usato dalla pagina register.html
* per pre-compilare il nome azienda prima che l'utente abbia un account.
*
* Rate limiting soft: 10 req/min per IP (file-based).
* Restituisce solo company_name e sector (nessun dato sensibile).
*/
public function lookupPiva(): void
{
// Soft rate limiting (no auth)
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$ip = trim(explode(',', $ip)[0]);
RateLimitService::check("piva_lookup:{$ip}", [['max' => 10, 'window_seconds' => 60]]);
RateLimitService::increment("piva_lookup:{$ip}");
$vatNumber = trim($this->getParam('vat_number', ''));
$vatNumber = preg_replace('/^IT/i', '', $vatNumber);
$vatNumber = preg_replace('/\s+/', '', $vatNumber);
if (!preg_match('/^\d{11}$/', $vatNumber)) {
$this->jsonError('Formato P.IVA non valido (11 cifre)', 400, 'INVALID_VAT');
}
try {
$visuraService = new VisuraService();
$data = $visuraService->fetchFromCertiSource($vatNumber);
if (empty($data) || empty($data['company_name'])) {
$this->jsonError('Azienda non trovata', 404, 'COMPANY_NOT_FOUND');
}
// Restituisce solo i campi necessari per il pre-fill del form
$this->jsonSuccess([
'company_name' => $data['company_name'],
'sector' => $data['sector'] ?? null,
'nis2_entity_type'=> $data['nis2_entity_type'] ?? null,
], 'Azienda trovata');
} catch (Throwable $e) {
error_log('[PIVA_LOOKUP_ERROR] ' . $e->getMessage());
$this->jsonError('Errore nel recupero dati', 500, 'LOOKUP_ERROR');
}
}
/**
* POST /api/onboarding/complete
* Completa l'onboarding: crea organizzazione e aggiorna profilo utente