1000) { throw new \InvalidArgumentException('A change reason containing 1-1000 bytes is required.'); } self::bounded($maxAuthFailures, 1, 1000, 'Maximum authentication failures'); self::bounded($authFailureWindow, 1, 86400, 'Authentication failure window'); self::bounded($autoBlockDuration, 1, 31536000, 'Automatic block duration'); $tenant = $this->tenants->fetchById($tenantId); if ($tenant === null) { return null; } $previous = $tenant->getConfiguration()->firewall()->jsonSerialize(); $current = [ 'enabled' => $enabled, 'maxAuthFailures' => $maxAuthFailures, 'authFailureWindow' => $authFailureWindow, 'autoBlockDuration' => $autoBlockDuration, ]; $configuration = (new TenantConfiguration())->jsonDeserialize([ ...$tenant->getConfiguration()->jsonSerialize(), 'firewall' => $current, ]); $tenant->setConfiguration($configuration); $this->tenants->deposit($tenant); $event = new SecurityEvent(SecurityEvent::FIREWALL_SETTINGS_UPDATED, [ 'changeReason' => $reason, 'changeOrigin' => FirewallRuleManager::ORIGIN_MANUAL, 'previous' => $previous, 'current' => $current, ]); $event->setTenantId($tenantId)->setIdentityId($actorId); $this->events->dispatch($event); return $current; } private static function bounded(int $value, int $minimum, int $maximum, string $label): void { if ($value < $minimum || $value > $maximum) { throw new \InvalidArgumentException( "{$label} must be between {$minimum} and {$maximum}." ); } } }