instances added god may help

This commit is contained in:
2026-02-23 12:58:19 +01:00
parent 25370a1a55
commit 99db252f60
290 changed files with 9858 additions and 4914 deletions

View File

@@ -13,55 +13,59 @@ class ApiAuditService
private const MAX_STRING_LENGTH = 500;
private const MAX_ARRAY_ITEMS = 30;
private static ?array $context = null;
private ?array $context = null;
public static function startRequestContext(): void
public function __construct(private readonly ApiAuditLogRepository $apiAuditLogRepository)
{
if (self::$context !== null) {
}
public function startRequestContext(): void
{
if ($this->context !== null) {
return;
}
$method = strtoupper(trim((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')));
if ($method === 'OPTIONS') {
self::$context = ['active' => false, 'finished' => true];
$this->context = ['active' => false, 'finished' => true];
return;
}
$path = parse_url((string) ($_SERVER['REQUEST_URI'] ?? ''), PHP_URL_PATH);
$path = is_string($path) ? trim($path) : '';
if ($path === '') {
self::$context = ['active' => false, 'finished' => true];
$this->context = ['active' => false, 'finished' => true];
return;
}
self::$context = [
$this->context = [
'active' => true,
'finished' => false,
'started_at' => microtime(true),
'request_id' => RepoQuery::uuidV4(),
'method' => substr($method !== '' ? $method : 'GET', 0, 8),
'path' => substr($path, 0, 255),
'query_json' => self::buildRedactedQueryJson($_GET),
'query_json' => $this->buildRedactedQueryJson($_GET),
];
}
public static function finish(int $statusCode, ?string $errorCode = null): void
public function finish(int $statusCode, ?string $errorCode = null): void
{
if (!is_array(self::$context)) {
if (!is_array($this->context)) {
return;
}
if (!empty(self::$context['finished'])) {
if (!empty($this->context['finished'])) {
return;
}
self::$context['finished'] = true;
$this->context['finished'] = true;
if (empty(self::$context['active'])) {
if (empty($this->context['active'])) {
return;
}
$durationMs = null;
if (isset(self::$context['started_at'])) {
$durationMs = (int) round((microtime(true) - (float) self::$context['started_at']) * 1000);
if (isset($this->context['started_at'])) {
$durationMs = (int) round((microtime(true) - (float) $this->context['started_at']) * 1000);
if ($durationMs < 0) {
$durationMs = 0;
}
@@ -95,10 +99,10 @@ class ApiAuditService
$tokenTenantId = ApiAuth::isAuthenticated() ? (int) (ApiAuth::scopedTenantId() ?? 0) : 0;
$payload = [
'request_id' => (string) (self::$context['request_id'] ?? RepoQuery::uuidV4()),
'method' => (string) (self::$context['method'] ?? ''),
'path' => (string) (self::$context['path'] ?? ''),
'query_json' => self::$context['query_json'] ?? null,
'request_id' => (string) ($this->context['request_id'] ?? RepoQuery::uuidV4()),
'method' => (string) ($this->context['method'] ?? ''),
'path' => (string) ($this->context['path'] ?? ''),
'query_json' => $this->context['query_json'] ?? null,
'status_code' => $statusCode,
'duration_ms' => $durationMs,
'error_code' => $normalizedErrorCode,
@@ -111,33 +115,33 @@ class ApiAuditService
];
try {
ApiAuditLogRepository::create($payload);
$this->apiAuditLogRepository->create($payload);
} catch (\Throwable $exception) {
// Never break API responses because of audit logging failures.
}
}
public static function listPaged(array $filters): array
public function listPaged(array $filters): array
{
return ApiAuditLogRepository::listPaged($filters);
return $this->apiAuditLogRepository->listPaged($filters);
}
public static function find(int $id): ?array
public function find(int $id): ?array
{
return ApiAuditLogRepository::find($id);
return $this->apiAuditLogRepository->find($id);
}
public static function purgeExpired(): int
public function purgeExpired(): int
{
return ApiAuditLogRepository::purgeOlderThanDays(self::RETENTION_DAYS);
return $this->apiAuditLogRepository->purgeOlderThanDays(self::RETENTION_DAYS);
}
private static function buildRedactedQueryJson(array $query): ?string
private function buildRedactedQueryJson(array $query): ?string
{
if (!$query) {
return null;
}
$redacted = self::redactArray($query);
$redacted = $this->redactArray($query);
if ($redacted === []) {
return null;
}
@@ -145,7 +149,7 @@ class ApiAuditService
return is_string($encoded) ? $encoded : null;
}
private static function redactArray(array $data): array
private function redactArray(array $data): array
{
$result = [];
$i = 0;
@@ -158,20 +162,20 @@ class ApiAuditService
continue;
}
if (self::isSensitiveKey($key)) {
if ($this->isSensitiveKey($key)) {
$result[$key] = '[REDACTED]';
} else {
$result[$key] = self::normalizeValue($value);
$result[$key] = $this->normalizeValue($value);
}
$i++;
}
return $result;
}
private static function normalizeValue(mixed $value): mixed
private function normalizeValue(mixed $value): mixed
{
if (is_array($value)) {
return self::redactArray($value);
return $this->redactArray($value);
}
if (is_bool($value) || is_int($value) || is_float($value) || $value === null) {
@@ -188,7 +192,7 @@ class ApiAuditService
return $string;
}
private static function isSensitiveKey(string $key): bool
private function isSensitiveKey(string $key): bool
{
$key = strtolower(trim($key));
if ($key === '') {
@@ -216,5 +220,4 @@ class ApiAuditService
|| str_contains($key, 'authorization')
|| str_ends_with($key, '_key');
}
}