security: fix 27 vulnerabilities + UI integration (Issues tab, project nav, validation)

Security fixes (27 vulnerabilities across 20 files):
CRITICAL:
- MediaManager: whitelist mediable types prevents RCE via class instantiation
- MediaManager/OfflineSyncController: IDOR fixes, remove Auth::id()??1 fallback
- ClientProjects: verify project ownership on all mutations (IDOR)
- CompanyManagement: Admin role check on mount() and mutations (auth bypass)
- ProjectMap: scope feature/template lookups to current project (IDOR x5)
- PhaseList/TemplateManager/LayerManager: scope mutations to owned resources (IDOR)
- ProjectEditTabs: Gate::authorize on mount() and updateProject()
- routes/web.php: reports routes moved inside can:manage all middleware (auth bypass)

MEDIUM:
- layer-manager: escapeHtml() on Leaflet popup interpolations (XSS)
- MediaManager: server-side MIME validation + 50MB limit
- ProjectList/ProjectUsers/ProjectCompanies/PhaseProgress: auth checks added
- AdminUsers/ReportsDashboard/ExportController: role/permission checks added

LOW:
- config/session.php: secure cookie tied to production env
- OfflineSyncController: sanitize storage path (path traversal)

UI integration:
- project-map: Issues tab (4th) with open-count badge
- project-map: project navigation bar (Dashboard/Map/Gantt/Report/Issues)
- project-dashboard: action buttons for Map/Gantt/Report/Issues
- project-form: validation error summary + per-field @error spans
- template-manager: validation error display

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 18:25:36 +02:00
parent 7d854ffb0a
commit f8a1310c0f
26 changed files with 1166 additions and 1195 deletions
+6 -4
View File
@@ -95,10 +95,12 @@ Route::middleware(['auth'])->group(function () {
'recentIssues' => $recentIssues,
]);
})->name('dashboard');
Route::get('/reports/dashboard', ReportsDashboard::class)->name('reports.dashboard');
Route::prefix('reports')->name('reports.')->group(function () {
Route::get('export/projects', [App\Http\Controllers\Reports\ExportController::class, 'exportProjects'])->name('export.projects');
Route::get('export/phases', [App\Http\Controllers\Reports\ExportController::class, 'exportPhases'])->name('export.phases');
// Reports — Admin only
Route::middleware(['can:manage all'])->prefix('reports')->name('reports.')->group(function () {
Route::get('/dashboard', ReportsDashboard::class)->name('dashboard');
Route::get('export/projects', [App\Http\Controllers\Reports\ExportController::class, 'exportProjects'])->name('export.projects');
Route::get('export/phases', [App\Http\Controllers\Reports\ExportController::class, 'exportPhases'])->name('export.phases');
Route::get('export/inspections', [App\Http\Controllers\Reports\ExportController::class, 'exportInspections'])->name('export.inspections');
});