refactor(kernel): unify HTTP and CLI application lifecycle
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -8,8 +8,8 @@ use KTXC\Http\Request\Request;
|
||||
use KTXC\Models\Firewall\FirewallRuleObject;
|
||||
use KTXC\Models\Firewall\FirewallLogObject;
|
||||
use KTXC\Stores\FirewallStore;
|
||||
use KTXC\SessionTenant;
|
||||
use KTXF\Event\EventBus;
|
||||
use KTXC\Context\TenantContextInterface;
|
||||
use KTXF\Event\EventDispatcherInterface;
|
||||
use KTXF\Event\SecurityEvent;
|
||||
use KTXF\IpUtils;
|
||||
|
||||
@@ -41,33 +41,9 @@ class FirewallService
|
||||
|
||||
public function __construct(
|
||||
private readonly FirewallStore $store,
|
||||
private readonly SessionTenant $tenant,
|
||||
private readonly EventBus $eventBus
|
||||
private readonly TenantContextInterface $tenantContext,
|
||||
private readonly EventDispatcherInterface $events,
|
||||
) {
|
||||
// Listen for auth failures to detect brute force
|
||||
$this->eventBus->subscribe(
|
||||
SecurityEvent::AUTH_FAILURE,
|
||||
[$this, 'handleAuthFailure'],
|
||||
100 // High priority
|
||||
);
|
||||
|
||||
// Log all security events asynchronously
|
||||
$this->eventBus->subscribeAsync(
|
||||
SecurityEvent::AUTH_FAILURE,
|
||||
[$this, 'logSecurityEvent']
|
||||
);
|
||||
$this->eventBus->subscribeAsync(
|
||||
SecurityEvent::AUTH_SUCCESS,
|
||||
[$this, 'logSecurityEvent']
|
||||
);
|
||||
$this->eventBus->subscribeAsync(
|
||||
SecurityEvent::ACCESS_DENIED,
|
||||
[$this, 'logSecurityEvent']
|
||||
);
|
||||
$this->eventBus->subscribeAsync(
|
||||
SecurityEvent::BRUTE_FORCE_DETECTED,
|
||||
[$this, 'logSecurityEvent']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +76,7 @@ class FirewallService
|
||||
return new FirewallAnalyzeResult(true);
|
||||
}
|
||||
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
return new FirewallAnalyzeResult(true);
|
||||
}
|
||||
@@ -158,7 +134,7 @@ class FirewallService
|
||||
public function handleAuthFailure(SecurityEvent $event): void
|
||||
{
|
||||
$ipAddress = $event->getIpAddress();
|
||||
$tenantId = $event->getTenantId() ?? $this->tenant->identifier();
|
||||
$tenantId = $event->getTenantId() ?? $this->tenantContext->identifier();
|
||||
|
||||
if (!$ipAddress || !$tenantId) {
|
||||
return;
|
||||
@@ -198,8 +174,8 @@ class FirewallService
|
||||
): void {
|
||||
// Publish brute force event
|
||||
$event = SecurityEvent::bruteForceDetected($ipAddress, $failureCount, $windowSeconds);
|
||||
$event->setTenantId($this->tenant->identifier());
|
||||
$this->eventBus->publish($event);
|
||||
$event->setTenantId($this->tenantContext->identifier());
|
||||
$this->events->dispatch($event);
|
||||
|
||||
// Auto-block the IP
|
||||
$blockDuration = $this->getConfig(
|
||||
@@ -220,7 +196,7 @@ class FirewallService
|
||||
*/
|
||||
public function logSecurityEvent(SecurityEvent $event): void
|
||||
{
|
||||
$tenantId = $event->getTenantId() ?? $this->tenant->identifier();
|
||||
$tenantId = $event->getTenantId() ?? $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
return;
|
||||
}
|
||||
@@ -283,8 +259,8 @@ class FirewallService
|
||||
$rule->getId(),
|
||||
$rule->getReason()
|
||||
);
|
||||
$event->setTenantId($this->tenant->identifier());
|
||||
$this->eventBus->publish($event);
|
||||
$event->setTenantId($this->tenantContext->identifier());
|
||||
$this->events->dispatch($event);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
@@ -300,7 +276,7 @@ class FirewallService
|
||||
?string $createdBy = null,
|
||||
?int $durationSeconds = null
|
||||
): FirewallRuleObject {
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
|
||||
}
|
||||
@@ -340,7 +316,7 @@ class FirewallService
|
||||
$event->setIpAddress($ipAddress)
|
||||
->setReason($reason)
|
||||
->setTenantId($tenantId);
|
||||
$this->eventBus->publish($event);
|
||||
$this->events->dispatch($event);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
@@ -353,7 +329,7 @@ class FirewallService
|
||||
?string $reason = null,
|
||||
?string $createdBy = null
|
||||
): FirewallRuleObject {
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
|
||||
}
|
||||
@@ -376,7 +352,7 @@ class FirewallService
|
||||
$event->setIpAddress($ipAddress)
|
||||
->setReason($reason)
|
||||
->setTenantId($tenantId);
|
||||
$this->eventBus->publish($event);
|
||||
$this->events->dispatch($event);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
@@ -389,7 +365,7 @@ class FirewallService
|
||||
?string $reason = null,
|
||||
?string $createdBy = null
|
||||
): FirewallRuleObject {
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
|
||||
}
|
||||
@@ -419,7 +395,7 @@ class FirewallService
|
||||
?string $createdBy = null,
|
||||
?int $durationSeconds = null
|
||||
): FirewallRuleObject {
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
|
||||
}
|
||||
@@ -448,7 +424,7 @@ class FirewallService
|
||||
$event->setDeviceFingerprint($fingerprint)
|
||||
->setReason($reason)
|
||||
->setTenantId($tenantId);
|
||||
$this->eventBus->publish($event);
|
||||
$this->events->dispatch($event);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
@@ -464,7 +440,7 @@ class FirewallService
|
||||
}
|
||||
|
||||
// Verify tenant ownership
|
||||
if ($rule->getTenantId() !== $this->tenant->identifier()) {
|
||||
if ($rule->getTenantId() !== $this->tenantContext->identifier()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -485,7 +461,7 @@ class FirewallService
|
||||
}
|
||||
|
||||
// Verify tenant ownership
|
||||
if ($rule->getTenantId() !== $this->tenant->identifier()) {
|
||||
if ($rule->getTenantId() !== $this->tenantContext->identifier()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -501,7 +477,7 @@ class FirewallService
|
||||
*/
|
||||
public function listRules(bool $activeOnly = true): array
|
||||
{
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
return [];
|
||||
}
|
||||
@@ -518,7 +494,7 @@ class FirewallService
|
||||
?string $result = null,
|
||||
int $limit = 100
|
||||
): array {
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
return [];
|
||||
}
|
||||
@@ -531,7 +507,7 @@ class FirewallService
|
||||
*/
|
||||
public function getBlockedCount(?\DateTimeImmutable $since = null): int
|
||||
{
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
if (!$tenantId) {
|
||||
return 0;
|
||||
}
|
||||
@@ -556,7 +532,7 @@ class FirewallService
|
||||
*/
|
||||
private function getConfig(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$config = $this->tenant->configuration();
|
||||
$config = $this->tenantContext->configuration();
|
||||
$parts = explode('.', $key);
|
||||
|
||||
foreach ($parts as $part) {
|
||||
@@ -576,7 +552,7 @@ class FirewallService
|
||||
private function getActiveRules(): array
|
||||
{
|
||||
if ($this->rulesCache === null) {
|
||||
$tenantId = $this->tenant->identifier();
|
||||
$tenantId = $this->tenantContext->identifier();
|
||||
$this->rulesCache = $tenantId
|
||||
? $this->store->listRules($tenantId, true)
|
||||
: [];
|
||||
|
||||
Reference in New Issue
Block a user