From 646347534db17d3e97d0c3dc4c7296b5550a5032 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Tue, 28 Jul 2026 00:46:47 +0530 Subject: [PATCH] Harden consent date range across bridge and HIU paths --- app/Libraries/Abdm/EAtriaBridgeConnector.php | 43 ++++++++++++++++++++ app/Libraries/Abdm/M3HiuGatewayClient.php | 11 ++--- app/Libraries/Abdm/M3HiuWorkflowService.php | 17 ++++---- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/app/Libraries/Abdm/EAtriaBridgeConnector.php b/app/Libraries/Abdm/EAtriaBridgeConnector.php index e822963..e316674 100644 --- a/app/Libraries/Abdm/EAtriaBridgeConnector.php +++ b/app/Libraries/Abdm/EAtriaBridgeConnector.php @@ -668,10 +668,13 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface string $consentHandle, array $rawPayload = [] ): array { + [$safeFrom, $safeTo] = $this->buildSafeConsentDateRange(); $body = [ 'patient_abha' => $abhaId, 'purpose' => $purposeCode !== '' ? $purposeCode : 'TREATMENT', 'hi_types' => $rawPayload['hi_types'] ?? ['OPConsultation'], + 'date_range_from' => (string) ($rawPayload['date_range_from'] ?? $safeFrom), + 'date_range_to' => $this->clampUtcIsoToSafePast((string) ($rawPayload['date_range_to'] ?? $safeTo)), ]; if ($expiresAt !== '') { $body['expires_at'] = $expiresAt; @@ -684,6 +687,46 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface return $result; } + /** + * @return array{0:string,1:string} + */ + private function buildSafeConsentDateRange(): array + { + $nowUtc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); + $safeTo = $nowUtc->modify('-120 seconds'); + $safeFrom = $safeTo->modify('-365 days'); + + return [ + $safeFrom->format('Y-m-d\TH:i:s.000\Z'), + $safeTo->format('Y-m-d\TH:i:s.000\Z'), + ]; + } + + private function clampUtcIsoToSafePast(string $candidate): string + { + $candidate = trim($candidate); + $safeNowUtc = (new \DateTimeImmutable('now', new \DateTimeZone('UTC'))) + ->modify('-120 seconds'); + $safeNowIso = $safeNowUtc->format('Y-m-d\TH:i:s.000\Z'); + + if ($candidate === '') { + return $safeNowIso; + } + + try { + $candidateAt = new \DateTimeImmutable($candidate); + if ($candidateAt->getTimestamp() > $safeNowUtc->getTimestamp()) { + return $safeNowIso; + } + + return $candidateAt + ->setTimezone(new \DateTimeZone('UTC')) + ->format('Y-m-d\TH:i:s.000\Z'); + } catch (\Throwable $e) { + return $safeNowIso; + } + } + // ------------------------------------------------------------------------- // Health Record Sharing // ------------------------------------------------------------------------- diff --git a/app/Libraries/Abdm/M3HiuGatewayClient.php b/app/Libraries/Abdm/M3HiuGatewayClient.php index 6748b63..6ba1f44 100644 --- a/app/Libraries/Abdm/M3HiuGatewayClient.php +++ b/app/Libraries/Abdm/M3HiuGatewayClient.php @@ -195,16 +195,17 @@ class M3HiuGatewayClient return $payload; } - $nowUtc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - $nowIso = $nowUtc->format('Y-m-d\TH:i:s.000\Z'); + $safeNowUtc = (new \DateTimeImmutable('now', new \DateTimeZone('UTC'))) + ->modify('-120 seconds'); + $safeNowIso = $safeNowUtc->format('Y-m-d\TH:i:s.000\Z'); try { $toAt = new \DateTimeImmutable($toRaw); - if ($toAt->getTimestamp() > $nowUtc->getTimestamp()) { - $payload['consent']['permission']['dateRange']['to'] = $nowIso; + if ($toAt->getTimestamp() > $safeNowUtc->getTimestamp()) { + $payload['consent']['permission']['dateRange']['to'] = $safeNowIso; } } catch (\Throwable $e) { - $payload['consent']['permission']['dateRange']['to'] = $nowIso; + $payload['consent']['permission']['dateRange']['to'] = $safeNowIso; } return $payload; diff --git a/app/Libraries/Abdm/M3HiuWorkflowService.php b/app/Libraries/Abdm/M3HiuWorkflowService.php index 2cfa3dd..11874ba 100644 --- a/app/Libraries/Abdm/M3HiuWorkflowService.php +++ b/app/Libraries/Abdm/M3HiuWorkflowService.php @@ -922,13 +922,15 @@ class M3HiuWorkflowService $istTz = new \DateTimeZone('Asia/Kolkata'); $utcTz = new \DateTimeZone('UTC'); $nowIst = new \DateTimeImmutable('now', $istTz); + $safeToUtc = $nowIst + ->setTimezone($utcTz) + ->modify('-120 seconds'); $fromUtc = $nowIst ->modify('-365 days') ->setTime(0, 0, 0) ->setTimezone($utcTz) ->format('Y-m-d\TH:i:s.000\Z'); - $toUtc = $nowIst - ->setTimezone($utcTz) + $toUtc = $safeToUtc ->format('Y-m-d\TH:i:s.000\Z'); $eraseAtUtc = $nowIst ->modify('+365 days') @@ -999,17 +1001,18 @@ class M3HiuWorkflowService return $consent; } - $nowUtc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - $nowIso = $nowUtc->format('Y-m-d\TH:i:s.000\Z'); + $safeNowUtc = (new \DateTimeImmutable('now', new \DateTimeZone('UTC'))) + ->modify('-120 seconds'); + $safeNowIso = $safeNowUtc->format('Y-m-d\TH:i:s.000\Z'); try { $toAt = new \DateTimeImmutable($toRaw); - if ($toAt->getTimestamp() > $nowUtc->getTimestamp()) { - $consent['permission']['dateRange']['to'] = $nowIso; + if ($toAt->getTimestamp() > $safeNowUtc->getTimestamp()) { + $consent['permission']['dateRange']['to'] = $safeNowIso; } } catch (\Throwable $e) { // Fall back to current UTC to avoid sending invalid timestamp shapes. - $consent['permission']['dateRange']['to'] = $nowIso; + $consent['permission']['dateRange']['to'] = $safeNowIso; } return $consent;