[FEAT] Fase 3 backend: portale fornitore OTP/magic-link (SupplierPortalController)
Auth fornitore SEPARATA dagli utenti interni (supplier_users/otp/sessions, mig 034): - SUPPLIER_JWT_SECRET dedicato, aud=supplier-portal, claim sp_uid/supplier_id/org_id (mai user_id); requireSupplierSession() verifica jti in supplier_sessions (revocabile), non tocca users/active_sessions. - OTP 8 cifre SHA-256, 15min, lockout persistente (attempts+locked_until), invalidazione OTP precedenti, hash_equals, rate-limit email+IP. - magic-link 32B hashed single-use (consumo atomico solo su verify). - request-otp risposta opaca anti-enumerazione. - OTP via EmailService::sendViaTemplate (/api/emails/send, fuori da email_log). - Endpoint: requestOtp/verifyOtp (no auth) + me/getQuestionnaire/saveAnswers (PATCH autosave)/submitQuestionnaire. Ownership campaign.supplier_id==session (no IDOR). - Scoring per-vulnerabilita (Art.21.3), snapshot domande immutabile. - config: SUPPLIER_JWT_SECRET + PATCH in CORS_ALLOWED_METHODS. - routes: controllerMap + actionMap supplier-portal. php -l OK su tutti. Tabelle 034 gia' applicate su host. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
261fc4cdd5
commit
de09af6d7e
@@ -110,6 +110,7 @@ $controllerMap = [
|
||||
'knowledgebase' => 'KnowledgeBaseController', // KB multi-livello (Migration 012-014)
|
||||
'ai' => 'AiController', // Assistente AI ARIA (askWithRag + fonti certe)
|
||||
'branding' => 'BrandingController', // White-label firm (Fase 5 / G16)
|
||||
'supplier-portal' => 'SupplierPortalController', // Portale fornitore Fase 3 (auth OTP/magic-link separata)
|
||||
];
|
||||
|
||||
if (!isset($controllerMap[$controllerName])) {
|
||||
@@ -301,6 +302,18 @@ $actionMap = [
|
||||
'DELETE:{id}' => 'delete',
|
||||
],
|
||||
|
||||
// ── SupplierPortalController — portale fornitore (auth OTP/magic-link, SEPARATA da users) ──
|
||||
'supplier-portal' => [
|
||||
'POST:requestOtp' => 'requestOtp', // NO AUTH (opaco)
|
||||
'POST:request-otp' => 'requestOtp',
|
||||
'POST:verifyOtp' => 'verifyOtp', // NO AUTH (apre sessione)
|
||||
'POST:verify-otp' => 'verifyOtp',
|
||||
'GET:me' => 'me', // sessione fornitore
|
||||
'GET:{id}' => 'getQuestionnaire',
|
||||
'POST:{id}/submit' => 'submitQuestionnaire',
|
||||
'PATCH:{id}/answers' => 'saveAnswers', // autosave
|
||||
],
|
||||
|
||||
// ── TrainingController ──────────────────────────
|
||||
'training' => [
|
||||
'GET:courses' => 'listCourses',
|
||||
|
||||
Reference in New Issue
Block a user