move_detect/cloud/src/Dashboard/EventDetailController.php
유창욱 3405c1e2cc fix(cloud): enforce CSRF on authenticated state-changing POSTs (M1)
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.
2026-07-12 09:16:38 +09:00

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);
}
}