b06c18d38e
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
306 lines
9.8 KiB
PHP
306 lines
9.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXC\Controllers;
|
|
|
|
use KTXC\Http\Request\Request;
|
|
use KTXC\Http\Response\JsonResponse;
|
|
use KTXC\Service\FirewallRuleConflictException;
|
|
use KTXC\Service\SystemFirewallLogService;
|
|
use KTXC\Service\SystemFirewallRuleService;
|
|
use KTXC\Service\SystemFirewallStatusService;
|
|
use KTXC\Service\TenantFirewallLogService;
|
|
use KTXC\Service\TenantFirewallRuleService;
|
|
use KTXC\Service\TenantFirewallStatusService;
|
|
use KTXF\Controller\ControllerAbstract;
|
|
use KTXF\Routing\Attributes\AuthenticatedRoute;
|
|
|
|
final class FirewallController extends ControllerAbstract
|
|
{
|
|
public function __construct(
|
|
private readonly TenantFirewallRuleService $tenantRules,
|
|
private readonly SystemFirewallRuleService $systemRules,
|
|
private readonly TenantFirewallLogService $tenantLogs,
|
|
private readonly SystemFirewallLogService $systemLogs,
|
|
private readonly TenantFirewallStatusService $tenantStatus,
|
|
private readonly SystemFirewallStatusService $systemStatus,
|
|
) {
|
|
}
|
|
|
|
#[AuthenticatedRoute(
|
|
'/firewall/rules',
|
|
name: 'firewall.tenant.rules.list',
|
|
permissions: [TenantFirewallRuleService::PERMISSION_READ],
|
|
)]
|
|
public function tenantRules(
|
|
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->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);
|
|
}
|
|
}
|
|
}
|