Fix ABDM HIP link-token failure: strictly sanitize abha_number, decouple abha_address from 14-digit abha_id in profile & modal
This commit is contained in:
parent
24089f36a6
commit
3656bf9b94
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,11 @@ if ($patientPhotoPath === '') {
|
|||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
|
||||
<h3 class="card-title mb-0">OPD History</h3>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm fw-semibold" onclick="openAbdmHipLinkModal(<?= (int)$patient->id ?>, '<?= esc($patientAbhaAddress ?? '') ?>', { name: '<?= esc($patient->p_fname ?? '') ?>', gender: '<?= $patient->gender == 1 ? 'M' : ($patient->gender == 2 ? 'F' : 'O') ?>', yob: '<?= !empty($patient->dob) ? date('Y', strtotime($patient->dob)) : '' ?>', phone: '<?= esc($patient->mphone1 ?? '') ?>', abha_number: '<?= esc($patient->abha_id ?? '') ?>' })">
|
||||
<?php
|
||||
$rawAbhaId = trim((string)($patient->abha_id ?? ''));
|
||||
$validModalAbhaNum = (strpos($rawAbhaId, '@') === false && strlen(preg_replace('/\D/', '', $rawAbhaId)) === 14) ? preg_replace('/\D/', '', $rawAbhaId) : '';
|
||||
?>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm fw-semibold" onclick="openAbdmHipLinkModal(<?= (int)$patient->id ?>, '<?= esc($patientAbhaAddress ?? '') ?>', { name: '<?= esc($patient->p_fname ?? '') ?>', gender: '<?= $patient->gender == 1 ? 'M' : ($patient->gender == 2 ? 'F' : 'O') ?>', yob: '<?= !empty($patient->dob) ? date('Y', strtotime($patient->dob)) : '' ?>', phone: '<?= esc($patient->mphone1 ?? '') ?>', abha_number: '<?= esc($validModalAbhaNum) ?>' })">
|
||||
<i class="bi bi-link-45deg me-1"></i>Link to ABHA (HIP)
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm"
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@
|
|||
<?= csrf_field() ?>
|
||||
<?php
|
||||
$patientAbhaId = '';
|
||||
foreach (['abha_id', 'abha_no', 'abha', 'abha_address'] as $abhaField) {
|
||||
foreach (['abha_id', 'abha_no', 'abha'] as $abhaField) {
|
||||
$candidateAbha = trim((string) ($data[0]->{$abhaField} ?? ''));
|
||||
if ($candidateAbha !== '') {
|
||||
if ($candidateAbha !== '' && strpos($candidateAbha, '@') === false) {
|
||||
$patientAbhaId = $candidateAbha;
|
||||
break;
|
||||
}
|
||||
|
|
@ -51,9 +51,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
if ($patientAbhaId === '' && $abhaAddress !== '') {
|
||||
$patientAbhaId = $abhaAddress;
|
||||
}
|
||||
$abhaVerifiedStatus = trim((string) ($data[0]->abha_verified_status ?? ''));
|
||||
$abhaVerificationType = trim((string) ($data[0]->abha_verification_type ?? ''));
|
||||
$abhaKycVerified = (int) ($data[0]->abha_kyc_verified ?? 0) === 1;
|
||||
|
|
@ -103,7 +100,8 @@
|
|||
<i class="bi bi-upload me-1"></i>Upload
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm w-100 mt-2 fw-semibold" onclick="openAbdmHipLinkModal(<?= (int)$data[0]->id ?>, '<?= esc($abhaAddress) ?>', { name: '<?= esc($data[0]->p_fname ?? '') ?>', gender: '<?= $data[0]->gender == 1 ? 'M' : ($data[0]->gender == 2 ? 'F' : 'O') ?>', yob: '<?= !empty($data[0]->dob) ? date('Y', strtotime($data[0]->dob)) : '' ?>', phone: '<?= esc($data[0]->mphone1 ?? '') ?>', abha_number: '<?= esc($patientAbhaId) ?>' })">
|
||||
<?php $validAbhaNumForModal = (strpos($patientAbhaId, '@') === false && strlen(preg_replace('/\D/', '', $patientAbhaId)) === 14) ? preg_replace('/\D/', '', $patientAbhaId) : ''; ?>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm w-100 mt-2 fw-semibold" onclick="openAbdmHipLinkModal(<?= (int)$data[0]->id ?>, '<?= esc($abhaAddress) ?>', { name: '<?= esc($data[0]->p_fname ?? '') ?>', gender: '<?= $data[0]->gender == 1 ? 'M' : ($data[0]->gender == 2 ? 'F' : 'O') ?>', yob: '<?= !empty($data[0]->dob) ? date('Y', strtotime($data[0]->dob)) : '' ?>', phone: '<?= esc($data[0]->mphone1 ?? '') ?>', abha_number: '<?= esc($validAbhaNumForModal) ?>' })">
|
||||
<i class="bi bi-link-45deg me-1"></i>Link Records to ABHA (HIP)
|
||||
</button>
|
||||
<?php if (empty($abhaAddress) && !empty($data[0]->mphone1)) : ?>
|
||||
|
|
|
|||
|
|
@ -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) : '';
|
||||
?>
|
||||
<a href="javascript:load_form('<?= esc($historyUrl, 'js') ?>','Consult History');"
|
||||
class="btn btn-info btn-sm"
|
||||
|
|
@ -596,7 +598,7 @@
|
|||
<button type="button" class="btn btn-outline-success btn-sm text-start" id="btn_local_clinical_assist" title="Local rule-based support using complaints + vitals">Clinical Assist (Local)</button>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm text-start" id="btn_ai_full_draft" title="Use complete OPD data to generate draft notes">AI Draft (Full Form)</button>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm text-start" id="btn_quick_preview_fhir">Preview FHIR JSON</button>
|
||||
<button type="button" class="btn btn-outline-success btn-sm text-start fw-semibold" onclick="openAbdmHipLinkModal(<?= (int)($patient_master[0]->id ?? 0) ?>, $('#abha_address').val(), { name: '<?= esc($patientName) ?>', gender: '<?= esc($patient_master[0]->gender == 1 ? 'M' : ($patient_master[0]->gender == 2 ? 'F' : 'O')) ?>', yob: '<?= !empty($patient_master[0]->dob) ? date('Y', strtotime($patient_master[0]->dob)) : '' ?>', phone: '<?= esc($patient_master[0]->mphone1 ?? '') ?>', abha_number: '<?= esc($patient_master[0]->abha_id ?? '') ?>' })">
|
||||
<button type="button" class="btn btn-outline-success btn-sm text-start fw-semibold" onclick="openAbdmHipLinkModal(<?= (int)($patient_master[0]->id ?? 0) ?>, $('#abha_address').val(), { name: '<?= esc($patientName) ?>', gender: '<?= esc($patient_master[0]->gender == 1 ? 'M' : ($patient_master[0]->gender == 2 ? 'F' : 'O')) ?>', yob: '<?= !empty($patient_master[0]->dob) ? date('Y', strtotime($patient_master[0]->dob)) : '' ?>', phone: '<?= esc($patient_master[0]->mphone1 ?? '') ?>', abha_number: '<?= esc($validPmAbhaNum) ?>' })">
|
||||
<i class="bi bi-link-45deg me-1"></i>Link Records to ABHA (HIP)
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -659,7 +661,7 @@
|
|||
<?php if ($patientAbhaAddress !== '') : ?>
|
||||
<div class="rx-meta-line d-flex align-items-center justify-content-between">
|
||||
<span><strong>ABHA:</strong> <?= esc($patientAbhaAddress) ?></span>
|
||||
<button type="button" class="btn btn-outline-success btn-xs py-0 px-2" style="font-size:0.75rem;" title="Link Records to ABHA (Method 4)" onclick="openAbdmHipLinkModal(<?= (int)($patient_master[0]->id ?? 0) ?>, $('#abha_address').val(), { name: '<?= esc($patientName) ?>', gender: '<?= esc($patient_master[0]->gender == 1 ? 'M' : ($patient_master[0]->gender == 2 ? 'F' : 'O')) ?>', yob: '<?= !empty($patient_master[0]->dob) ? date('Y', strtotime($patient_master[0]->dob)) : '' ?>', phone: '<?= esc($patient_master[0]->mphone1 ?? '') ?>', abha_number: '<?= esc($patient_master[0]->abha_id ?? '') ?>' })">
|
||||
<button type="button" class="btn btn-outline-success btn-xs py-0 px-2" style="font-size:0.75rem;" title="Link Records to ABHA (Method 4)" onclick="openAbdmHipLinkModal(<?= (int)($patient_master[0]->id ?? 0) ?>, $('#abha_address').val(), { name: '<?= esc($patientName) ?>', gender: '<?= esc($patient_master[0]->gender == 1 ? 'M' : ($patient_master[0]->gender == 2 ? 'F' : 'O')) ?>', yob: '<?= !empty($patient_master[0]->dob) ? date('Y', strtotime($patient_master[0]->dob)) : '' ?>', phone: '<?= esc($patient_master[0]->mphone1 ?? '') ?>', abha_number: '<?= esc($validPmAbhaNum) ?>' })">
|
||||
<i class="bi bi-link-45deg"></i> Link
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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 = '<strong><i class="bi bi-check-circle-fill me-1"></i>Already Linked!</strong> '
|
||||
+ '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 = '<span class="spinner-border spinner-border-sm me-1"></span>Verifying...';
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user