Only SameSite=Lax protected the acknowledge and zone save/delete endpoints, even though a Csrf helper and mintable token already existed. Add GET /api/csrf (CsrfController::token) to mint/return a per-session token, check it (auth -> rbac -> csrf -> mutate) in EventDetailController::acknowledge and ZoneConfigController::save/delete, and wire app.js/zone-draw.js to fetch the token on load and send it as X-Csrf-Token on every POST.
39 lines
1.7 KiB
PHP
39 lines
1.7 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
namespace App\Dashboard;
|
|
|
|
use App\Http\{Request, Response};
|
|
use App\Auth\{SessionStore, Rbac};
|
|
use App\Security\Csrf;
|
|
use App\Repository\{EventRepository, SnapshotRepository, AuditRepository};
|
|
|
|
final class EventDetailController
|
|
{
|
|
public function __construct(
|
|
private EventRepository $events, private SnapshotRepository $snaps,
|
|
private AuditRepository $audit, private SessionStore $sess
|
|
) {}
|
|
|
|
public function show(Request $req, array $params): Response
|
|
{
|
|
if ($this->sess->get('user_id') === null) return Response::json(['error' => 'unauthorized'], 401);
|
|
$id = (int)($params['id'] ?? 0);
|
|
$event = $this->events->find($id);
|
|
if ($event === null) return Response::json(['error' => 'not_found'], 404);
|
|
return Response::json(['event' => $event, 'snapshots' => $this->snaps->forEvent($id)], 200);
|
|
}
|
|
|
|
public function acknowledge(Request $req, array $params): Response
|
|
{
|
|
if ($this->sess->get('user_id') === null) return Response::json(['error' => 'unauthorized'], 401);
|
|
if (!Rbac::can((string)$this->sess->get('role'), 'acknowledge')) return Response::json(['error' => 'forbidden'], 403);
|
|
if (!Csrf::check((string)$this->sess->get('csrf'), (string)$req->header('X-Csrf-Token'))) {
|
|
return Response::json(['error' => 'csrf'], 403);
|
|
}
|
|
$id = (int)($params['id'] ?? 0);
|
|
$user = (string)$this->sess->get('username');
|
|
if (!$this->events->acknowledge($id, $user)) return Response::json(['error' => 'not_found'], 404);
|
|
$this->audit->append($user, 'acknowledge', "event:$id", [], []);
|
|
return Response::json(['ok' => true], 200);
|
|
}
|
|
}
|