queryResponse( fn(int $parsedLimit, int $parsedOffset): array => $this->tenantRules->queryRules( $status, $type, $action, $parsedLimit, $parsedOffset ), $limit, $offset ); } #[AuthenticatedRoute( '/firewall/rules/{ruleId}', name: 'firewall.tenant.rules.fetch', permissions: [TenantFirewallRuleService::PERMISSION_READ], )] public function tenantRule(string $ruleId): JsonResponse { return $this->ruleResponse($this->tenantRules->fetchRule($ruleId)); } #[AuthenticatedRoute( '/firewall/effective-policy', name: 'firewall.tenant.policy.effective', permissions: [TenantFirewallRuleService::PERMISSION_READ], )] public function effectivePolicy(): JsonResponse { return new JsonResponse($this->tenantRules->effectivePolicy()); } #[AuthenticatedRoute( '/firewall/system/rules', name: 'firewall.system.rules.list', permissions: [SystemFirewallRuleService::PERMISSION_READ], )] public function systemRules( string $status = 'active', ?string $type = null, ?string $action = null, string $limit = '50', string $offset = '0' ): JsonResponse { return $this->queryResponse( fn(int $parsedLimit, int $parsedOffset): array => $this->systemRules->queryRules( $status, $type, $action, $parsedLimit, $parsedOffset ), $limit, $offset ); } #[AuthenticatedRoute( '/firewall/system/rules/{ruleId}', name: 'firewall.system.rules.fetch', permissions: [SystemFirewallRuleService::PERMISSION_READ], )] public function systemRule(string $ruleId): JsonResponse { return $this->ruleResponse($this->systemRules->fetchRule($ruleId)); } #[AuthenticatedRoute( '/firewall/rules', name: 'firewall.tenant.rules.create', methods: ['POST'], permissions: [TenantFirewallRuleService::PERMISSION_MANAGE], )] public function createTenantRule( Request $request, string $type, string $action, string $value, string $reason, ?int $durationSeconds = null, bool $confirmCurrentIp = false ): JsonResponse { return $this->mutationResponse(fn() => $this->tenantRules->createRule( $type, $action, $value, $reason, $durationSeconds, $request->getClientIp(), $confirmCurrentIp )); } #[AuthenticatedRoute( '/firewall/system/rules', name: 'firewall.system.rules.create', methods: ['POST'], permissions: [SystemFirewallRuleService::PERMISSION_MANAGE], )] public function createSystemRule( Request $request, string $type, string $action, string $value, string $reason, ?int $durationSeconds = null, bool $confirmCurrentIp = false ): JsonResponse { return $this->mutationResponse(fn() => $this->systemRules->createRule( $type, $action, $value, $reason, $durationSeconds, $request->getClientIp(), $confirmCurrentIp )); } #[AuthenticatedRoute( '/firewall/logs', name: 'firewall.tenant.logs.list', permissions: [TenantFirewallLogService::PERMISSION_READ], )] public function tenantLogs( ?string $ipAddress = null, ?string $eventType = null, ?string $result = null, ?string $ruleId = null, ?string $ruleScope = null, ?string $from = null, ?string $to = null, string $limit = '50', string $offset = '0' ): JsonResponse { return $this->queryResponse( fn(int $parsedLimit, int $parsedOffset): array => $this->tenantLogs->query( compact('ipAddress', 'eventType', 'result', 'ruleId', 'ruleScope', 'from', 'to'), $parsedLimit, $parsedOffset ), $limit, $offset ); } #[AuthenticatedRoute( '/firewall/system/logs', name: 'firewall.system.logs.list', permissions: [SystemFirewallLogService::PERMISSION_READ], )] public function systemLogs( ?string $tenantId = null, ?string $ipAddress = null, ?string $eventType = null, ?string $result = null, ?string $ruleId = null, ?string $ruleScope = null, ?string $from = null, ?string $to = null, string $limit = '50', string $offset = '0' ): JsonResponse { return $this->queryResponse( fn(int $parsedLimit, int $parsedOffset): array => $this->systemLogs->query( $tenantId, compact('ipAddress', 'eventType', 'result', 'ruleId', 'ruleScope', 'from', 'to'), $parsedLimit, $parsedOffset ), $limit, $offset ); } #[AuthenticatedRoute( '/firewall/metrics', name: 'firewall.tenant.metrics.read', permissions: [TenantFirewallLogService::PERMISSION_READ], )] public function tenantMetrics(?string $since = null): JsonResponse { return $this->readResponse(fn(): array => $this->tenantStatus->metrics($since)); } #[AuthenticatedRoute( '/firewall/configuration', name: 'firewall.tenant.configuration.read', permissions: [TenantFirewallStatusService::PERMISSION_SETTINGS_READ], )] public function tenantConfiguration(): JsonResponse { return new JsonResponse($this->tenantStatus->configuration()); } #[AuthenticatedRoute( '/firewall/system/metrics', name: 'firewall.system.metrics.read', permissions: [SystemFirewallLogService::PERMISSION_READ], )] public function systemMetrics(?string $tenantId = null, ?string $since = null): JsonResponse { return $this->readResponse(fn(): array => $this->systemStatus->metrics($tenantId, $since)); } #[AuthenticatedRoute( '/firewall/system/maintenance', name: 'firewall.system.maintenance.read', permissions: [SystemFirewallStatusService::PERMISSION_MAINTENANCE_READ], )] public function maintenanceStatus(): JsonResponse { return new JsonResponse($this->systemStatus->maintenanceStatus()); } private function queryResponse(callable $query, string $limit, string $offset): JsonResponse { try { if (!ctype_digit($limit) || !ctype_digit($offset)) { throw new \InvalidArgumentException('Pagination values must be non-negative integers.'); } return new JsonResponse($query((int)$limit, (int)$offset)); } catch (\InvalidArgumentException $error) { return new JsonResponse(['error' => $error->getMessage()], JsonResponse::HTTP_BAD_REQUEST); } } private function ruleResponse(?\JsonSerializable $rule): JsonResponse { if ($rule === null) { return new JsonResponse(['error' => 'Firewall rule not found.'], JsonResponse::HTTP_NOT_FOUND); } return new JsonResponse($rule); } private function readResponse(callable $read): JsonResponse { try { return new JsonResponse($read()); } catch (\InvalidArgumentException $error) { return new JsonResponse(['error' => $error->getMessage()], JsonResponse::HTTP_BAD_REQUEST); } } private function mutationResponse(callable $mutation): JsonResponse { try { return new JsonResponse(['rule' => $mutation()], JsonResponse::HTTP_CREATED); } catch (FirewallRuleConflictException $error) { return new JsonResponse(['error' => [ 'code' => $error->conflictCode, 'message' => $error->getMessage(), ]], JsonResponse::HTTP_CONFLICT); } catch (\InvalidArgumentException $error) { return new JsonResponse(['error' => [ 'code' => 'invalid_firewall_rule', 'message' => $error->getMessage(), ]], JsonResponse::HTTP_BAD_REQUEST); } } }