instances added god may help
This commit is contained in:
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user