false, 'error' => 'forbidden'], 403); } $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; $action = trim((string)($_GET['action'] ?? '')); if ($method === 'GET') { if ($action === 'devices') { json_out(['ok' => true, 'devices' => RemoteAccessRepository::listDevices()]); } if ($action === 'sessions') { $filter = trim((string)($_GET['status'] ?? '')); json_out(['ok' => true, 'sessions' => RemoteAccessRepository::listSessions($filter)]); } if ($action === 'events') { json_out(['ok' => true, 'events' => RemoteAccessRepository::listEvents((int)($_GET['limit'] ?? 100))]); } if ($action === 'dashboard') { $payload = RemoteAccessRepository::buildDashboardPayload( rtrim(Auth::basePath(), '/'), '/app/androidcast_project' ); json_out([ 'ok' => true, 'devices' => $payload['devices'], 'active_sessions' => $payload['active_sessions'], 'inactive_sessions' => $payload['inactive_sessions'], 'recent_events' => $payload['recent_events'], 'permissions' => [ 'can_operate' => Rbac::can('remote_access_operate'), 'can_admin' => Rbac::can('remote_access_admin'), ], 'config' => [ 'wg_endpoint' => (string) cfg('remote_access.wg_endpoint', ''), ], ]); } json_out(['ok' => false, 'error' => 'unknown_action'], 400); } if ($method !== 'POST') { json_out(['ok' => false, 'error' => 'method_not_allowed'], 405); } $raw = file_get_contents('php://input') ?: ''; $body = json_decode($raw, true); if (!is_array($body)) { json_out(['ok' => false, 'error' => 'invalid_json'], 400); } $user = Auth::user(); $userId = (int)($user['id'] ?? 0); if ($action === 'whitelist') { if (!Rbac::can('remote_access_admin')) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } $deviceId = trim((string)($body['device_id'] ?? '')); if ($deviceId === '') { json_out(['ok' => false, 'error' => 'missing_device_id'], 400); } if (!RemoteAccessRepository::canAccessDevice($deviceId)) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } if (!RemoteAccessRepository::setDeviceWhitelist($deviceId, !empty($body['whitelisted']), $body['notes'] ?? null)) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } RemoteAccessRepository::logEvent($deviceId, null, $userId, 'whitelist_update', null, [ 'whitelisted' => !empty($body['whitelisted']), ], ''); json_out(['ok' => true]); } if ($action === 'open_session') { if (!Rbac::can('remote_access_operate')) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } $deviceId = trim((string)($body['device_id'] ?? '')); if ($deviceId === '') { json_out(['ok' => false, 'error' => 'missing_device_id'], 400); } if (!RemoteAccessRepository::canAccessDevice($deviceId)) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } $result = RemoteAccessRepository::openSession($deviceId, $userId); if (empty($result['ok'])) { $err = $result['error'] ?? 'failed'; json_out(['ok' => false, 'error' => $err], $err === 'forbidden' ? 403 : 400); } json_out(['ok' => true, 'session_id' => $result['session_id'] ?? '']); } if ($action === 'close_session') { if (!Rbac::can('remote_access_operate')) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } $sessionId = trim((string)($body['session_id'] ?? '')); if ($sessionId === '') { json_out(['ok' => false, 'error' => 'missing_session_id'], 400); } if (!RemoteAccessRepository::canOperatorCloseSession($sessionId, $userId)) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } RemoteAccessRepository::closeSession($sessionId, RemoteAccessRepository::STATUS_CLOSED, 'operator_closed'); RemoteAccessRepository::logEvent((string)($body['device_id'] ?? ''), $sessionId, $userId, 'session_close', 'operator', null, ''); json_out(['ok' => true]); } json_out(['ok' => false, 'error' => 'unknown_action'], 400);