store->queryTenantLogs( $tenantId, $this->validate($filters, $limit, $offset), $limit, $offset ); } public function system(?string $tenantId, array $filters, int $limit, int $offset): array { if ($tenantId !== null && ($tenantId === '' || strlen($tenantId) > 128)) { throw new \InvalidArgumentException('Invalid tenant filter.'); } return $this->store->querySystemLogs( $tenantId, $this->validate($filters, $limit, $offset), $limit, $offset ); } private function validate(array $filters, int $limit, int $offset): array { if ($limit < 1 || $limit > self::MAX_LIMIT || $offset < 0) { throw new \InvalidArgumentException('Pagination requires limit 1-100 and offset 0 or greater.'); } $ipAddress = self::nullableString($filters, 'ipAddress'); if ($ipAddress !== null && filter_var($ipAddress, FILTER_VALIDATE_IP) === false) { throw new \InvalidArgumentException('Invalid IP address filter.'); } $eventType = self::nullableString($filters, 'eventType'); if ($eventType !== null && !in_array($eventType, self::EVENT_TYPES, true)) { throw new \InvalidArgumentException('Invalid firewall event type filter.'); } $result = self::nullableString($filters, 'result'); if ($result !== null && !in_array($result, [ FirewallLogObject::RESULT_ALLOWED, FirewallLogObject::RESULT_BLOCKED, FirewallLogObject::RESULT_RECORDED, ], true)) { throw new \InvalidArgumentException('Invalid firewall result filter.'); } $ruleScope = self::nullableString($filters, 'ruleScope'); if ($ruleScope !== null && !in_array($ruleScope, [ FirewallRuleObject::SCOPE_TENANT, FirewallRuleObject::SCOPE_SYSTEM, ], true)) { throw new \InvalidArgumentException('Invalid rule scope filter.'); } $from = self::date($filters, 'from'); $to = self::date($filters, 'to'); if ($from !== null && $to !== null && $from > $to) { throw new \InvalidArgumentException('The from date must not be later than the to date.'); } return [ 'ipAddress' => $ipAddress, 'eventType' => $eventType, 'result' => $result, 'ruleId' => self::nullableString($filters, 'ruleId'), 'ruleScope' => $ruleScope, 'from' => $from, 'to' => $to, ]; } private static function nullableString(array $filters, string $key): ?string { $value = $filters[$key] ?? null; if ($value === null) { return null; } if (!is_string($value) || $value === '' || strlen($value) > 255) { throw new \InvalidArgumentException("Invalid {$key} filter."); } return $value; } private static function date(array $filters, string $key): ?\DateTimeImmutable { $value = self::nullableString($filters, $key); if ($value === null) { return null; } try { return new \DateTimeImmutable($value); } catch (\Exception) { throw new \InvalidArgumentException("Invalid {$key} date filter."); } } }