From 3656bf9b942f2c89423f6047085528526ecd01d1 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Thu, 24 Sep 2026 10:03:19 +0530 Subject: [PATCH] Fix ABDM HIP link-token failure: strictly sanitize abha_number, decouple abha_address from 14-digit abha_id in profile & modal --- app/Controllers/AbdmGateway.php | 32 ++++++++++++++++++-- app/Libraries/Abdm/EAtriaBridgeConnector.php | 18 +++++++++++ app/Views/billing/Patient_Profile_Opd_V.php | 7 +++-- app/Views/billing/Person_profile_V.php | 10 +++--- app/Views/billing/opd_prescription_basic.php | 6 ++-- app/Views/partials/abdm_hip_link_modal.php | 30 ++++++++++++++++-- 6 files changed, 87 insertions(+), 16 deletions(-) diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index c9dd607..b141c16 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -10385,7 +10385,20 @@ class AbdmGateway extends BaseController ->get(1) ->getRowArray(); if (! empty($pat['abha_id'])) { - $body['abha_number'] = trim((string) $pat['abha_id']); + $candidateNum = trim((string) $pat['abha_id']); + if (strpos($candidateNum, '@') === false && strlen(preg_replace('/\D/', '', $candidateNum)) === 14) { + $body['abha_number'] = preg_replace('/\D/', '', $candidateNum); + } + } + } + + // Sanitize abha_number: only keep if valid 14-digit numeric ABHA number. Never pass email/abha_address! + if (! empty($body['abha_number'])) { + $cleanedAbhaNum = preg_replace('/\D/', '', (string) $body['abha_number']); + if (strlen($cleanedAbhaNum) === 14 && strpos((string) $body['abha_number'], '@') === false) { + $body['abha_number'] = $cleanedAbhaNum; + } else { + unset($body['abha_number']); } } @@ -10434,7 +10447,20 @@ class AbdmGateway extends BaseController ->get(1) ->getRowArray(); if (! empty($pat['abha_id'])) { - $body['abha_number'] = trim((string) $pat['abha_id']); + $candidateNum = trim((string) $pat['abha_id']); + if (strpos($candidateNum, '@') === false && strlen(preg_replace('/\D/', '', $candidateNum)) === 14) { + $body['abha_number'] = preg_replace('/\D/', '', $candidateNum); + } + } + } + + // Sanitize abha_number: only keep if valid 14-digit numeric ABHA number. Never pass email/abha_address! + if (! empty($body['abha_number'])) { + $cleanedAbhaNum = preg_replace('/\D/', '', (string) $body['abha_number']); + if (strlen($cleanedAbhaNum) === 14 && strpos((string) $body['abha_number'], '@') === false) { + $body['abha_number'] = $cleanedAbhaNum; + } else { + unset($body['abha_number']); } } @@ -10656,7 +10682,7 @@ class AbdmGateway extends BaseController 'year_of_birth' => $yob, 'dob' => $dob, 'abha_address' => $effAbhaAddress, - 'abha_number' => trim((string) ($patient['abha_id'] ?? '')), + 'abha_number' => (strpos((string) ($patient['abha_id'] ?? ''), '@') === false && strlen(preg_replace('/\D/', '', (string) ($patient['abha_id'] ?? ''))) === 14) ? preg_replace('/\D/', '', (string) $patient['abha_id']) : '', 'phone' => $cleanPhone, ], 'care_contexts' => $contextsList, diff --git a/app/Libraries/Abdm/EAtriaBridgeConnector.php b/app/Libraries/Abdm/EAtriaBridgeConnector.php index c8d7e2d..25daba6 100644 --- a/app/Libraries/Abdm/EAtriaBridgeConnector.php +++ b/app/Libraries/Abdm/EAtriaBridgeConnector.php @@ -1728,6 +1728,15 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface } } + if (! empty($payload['abha_number'])) { + $cleaned = preg_replace('/\D/', '', (string) $payload['abha_number']); + if (strlen($cleaned) === 14 && strpos((string) $payload['abha_number'], '@') === false) { + $payload['abha_number'] = $cleaned; + } else { + unset($payload['abha_number']); + } + } + if ($this->hfrId !== '' && empty($payload['hfr_id'])) { $payload['hfr_id'] = $this->hfrId; } @@ -1736,6 +1745,15 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface public function hipLinkCareContext(array $payload): array { + if (! empty($payload['abha_number'])) { + $cleaned = preg_replace('/\D/', '', (string) $payload['abha_number']); + if (strlen($cleaned) === 14 && strpos((string) $payload['abha_number'], '@') === false) { + $payload['abha_number'] = $cleaned; + } else { + unset($payload['abha_number']); + } + } + if ($this->hfrId !== '' && empty($payload['hfr_id'])) { $payload['hfr_id'] = $this->hfrId; } diff --git a/app/Views/billing/Patient_Profile_Opd_V.php b/app/Views/billing/Patient_Profile_Opd_V.php index 239a44e..6c28fda 100644 --- a/app/Views/billing/Patient_Profile_Opd_V.php +++ b/app/Views/billing/Patient_Profile_Opd_V.php @@ -69,8 +69,11 @@ if ($patientPhotoPath === '') {

OPD History

-
-
- mphone1)) : ?> diff --git a/app/Views/billing/opd_prescription_basic.php b/app/Views/billing/opd_prescription_basic.php index 500815c..2eb86bd 100644 --- a/app/Views/billing/opd_prescription_basic.php +++ b/app/Views/billing/opd_prescription_basic.php @@ -573,6 +573,8 @@ } } } + $rawPmAbhaId = trim((string) ($patient_master[0]->abha_id ?? '')); + $validPmAbhaNum = (strpos($rawPmAbhaId, '@') === false && strlen(preg_replace('/\D/', '', $rawPmAbhaId)) === 14) ? preg_replace('/\D/', '', $rawPmAbhaId) : ''; ?> Clinical Assist (Local) -
@@ -659,7 +661,7 @@
ABHA: -
diff --git a/app/Views/partials/abdm_hip_link_modal.php b/app/Views/partials/abdm_hip_link_modal.php index 0c89a03..7caed96 100644 --- a/app/Views/partials/abdm_hip_link_modal.php +++ b/app/Views/partials/abdm_hip_link_modal.php @@ -388,7 +388,11 @@ if (data.ok && data.patient) { var p = data.patient; if (p.abha_address) document.getElementById('hipAbhaAddress').value = p.abha_address; - if (p.abha_number) document.getElementById('hipAbhaNumber').value = p.abha_number; + var pAbhaNum = (p.abha_number || '').trim(); + if (pAbhaNum.indexOf('@') !== -1 || pAbhaNum.replace(/\D/g, '').length !== 14) { + pAbhaNum = ''; + } + document.getElementById('hipAbhaNumber').value = pAbhaNum; if (p.name) document.getElementById('hipPatientName').value = p.name; if (p.gender) document.getElementById('hipGender').value = p.gender; if (p.year_of_birth) document.getElementById('hipYob').value = p.year_of_birth; @@ -428,7 +432,11 @@ // Reset fields document.getElementById('hipAbhaAddress').value = abhaAddress || prefill.abha_address || ''; - document.getElementById('hipAbhaNumber').value = prefill.abha_number || prefill.abha_id || ''; + var rawPrefillNum = (prefill.abha_number || prefill.abha_id || '').trim(); + if (rawPrefillNum.indexOf('@') !== -1 || rawPrefillNum.replace(/\D/g, '').length !== 14) { + rawPrefillNum = ''; + } + document.getElementById('hipAbhaNumber').value = rawPrefillNum; document.getElementById('hipPatientName').value = prefill.name || prefill.patient_name || ''; document.getElementById('hipGender').value = prefill.gender || 'M'; document.getElementById('hipYob').value = prefill.year_of_birth || prefill.yob || ''; @@ -484,7 +492,11 @@ */ window.executeHipInitiatedLinking = async function() { var abhaAddress = document.getElementById('hipAbhaAddress').value.trim(); - var abhaNumber = document.getElementById('hipAbhaNumber').value.trim(); + var rawAbhaNum = (document.getElementById('hipAbhaNumber').value || '').trim(); + var abhaNumber = ''; + if (rawAbhaNum.indexOf('@') === -1 && rawAbhaNum.replace(/\D/g, '').length === 14) { + abhaNumber = rawAbhaNum.replace(/\D/g, ''); + } var name = document.getElementById('hipPatientName').value.trim(); var gender = document.getElementById('hipGender').value; var yobVal = document.getElementById('hipYob').value.trim(); @@ -519,6 +531,18 @@ return; } + var allAlreadyLinked = selectedContexts.length > 0 && selectedContexts.every(function(c) { + var cb = document.querySelector('.care-context-cb[value="' + c.ref.replace(/"/g, '\\"') + '"]'); + return cb && cb.closest('.border') && cb.closest('.border').querySelector('.badge.bg-success-subtle'); + }); + if (allAlreadyLinked) { + alertBox.className = 'alert alert-success py-2 px-3 small'; + alertBox.innerHTML = 'Already Linked! ' + + 'The selected care context(s) are already linked with this patient\'s ABHA. Patient can view and fetch the records directly in their PHR app.'; + alertBox.classList.remove('d-none'); + return; + } + var origBtnHtml = submitBtn.innerHTML; submitBtn.disabled = true; submitBtn.innerHTML = 'Verifying...';