fix(abdm): bind alternate mobile to enrolment
Use the dedicated Bridge enrolment-mobile OTP endpoints for child/dependent ABHA creation and reject any alternate-mobile response whose ABHA differs from the Aadhaar-verified identity.
This commit is contained in:
parent
c8f44e4493
commit
841b15d27b
|
|
@ -110,6 +110,10 @@ class Abha extends BaseController
|
|||
$profile = $this->pickGatewayAbhaProfile($payload);
|
||||
|
||||
$abhaNum = (string) ($profile['ABHANumber'] ?? $profile['abha_id'] ?? $payload['ABHANumber'] ?? $payload['abha_id'] ?? '');
|
||||
$aadhaarVerifiedAbha = preg_replace('/\D/', '', $abhaNum);
|
||||
if ($newTxnId && strlen($aadhaarVerifiedAbha) === 14) {
|
||||
session()->set('abha_enrol_identity_' . $newTxnId, $aadhaarVerifiedAbha);
|
||||
}
|
||||
$abhaAddress = (string) (
|
||||
($profile['preferredAddress'] ?? '')
|
||||
?: ($profile['preferredAbhaAddress'] ?? '')
|
||||
|
|
@ -224,15 +228,28 @@ class Abha extends BaseController
|
|||
return $this->response->setJSON(['ok' => 0, 'error_text' => 'Valid 10-digit mobile number is required']);
|
||||
}
|
||||
|
||||
if ($txnId === '') {
|
||||
return $this->response->setJSON(['ok' => 0, 'error_text' => 'Aadhaar enrolment txn_id is required']);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = AbdmConnectorFactory::make()->abhaMobileGenerateOtp(['mobile' => $mobile, 'txnId' => $txnId]);
|
||||
$result = AbdmConnectorFactory::make()->abhaEnrolMobileRequestOtp(['mobile' => $mobile, 'txnId' => $txnId]);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->response->setStatusCode(500)->setJSON(['ok' => 0, 'error_text' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
if (! empty($result['ok']) && $result['ok'] == 1) {
|
||||
$newTxnId = $result['txn_id'] ?? $result['data']['txnId'] ?? $result['data']['txn_id'] ?? $txnId;
|
||||
return $this->response->setJSON(['ok' => 1, 'txn_id' => $newTxnId]);
|
||||
$expectedAbha = (string) (session()->get('abha_enrol_identity_' . $txnId) ?? '');
|
||||
if ($expectedAbha !== '') {
|
||||
session()->set('abha_enrol_identity_' . $newTxnId, $expectedAbha);
|
||||
}
|
||||
return $this->response->setJSON([
|
||||
'ok' => 1,
|
||||
'txn_id' => $newTxnId,
|
||||
'message' => (string) ($result['message'] ?? $result['data']['message'] ?? 'OTP sent to alternate mobile.'),
|
||||
'request_id' => (string) ($result['request_id'] ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
|
|
@ -264,7 +281,7 @@ class Abha extends BaseController
|
|||
}
|
||||
|
||||
try {
|
||||
$result = AbdmConnectorFactory::make()->abhaMobileVerifyOtp(['txnId' => $txnId, 'otp' => $otp]);
|
||||
$result = AbdmConnectorFactory::make()->abhaEnrolMobileVerifyOtp(['txnId' => $txnId, 'otp' => $otp]);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->response->setStatusCode(500)->setJSON(['ok' => 0, 'error_text' => $e->getMessage()]);
|
||||
}
|
||||
|
|
@ -290,6 +307,17 @@ class Abha extends BaseController
|
|||
$profile = $this->pickGatewayAbhaProfile($payload);
|
||||
|
||||
$abhaNum = (string) ($profile['ABHANumber'] ?? $profile['abha_id'] ?? $payload['ABHANumber'] ?? $payload['abha_id'] ?? '');
|
||||
$expectedAbha = preg_replace('/\D/', '', (string) (session()->get('abha_enrol_identity_' . $txnId) ?? ''));
|
||||
$returnedAbha = preg_replace('/\D/', '', $abhaNum);
|
||||
if (strlen($expectedAbha) !== 14 || $returnedAbha !== $expectedAbha) {
|
||||
log_message('error', '[ABHA] Enrolment identity mismatch blocked for txn ' . $txnId);
|
||||
return $this->response->setStatusCode(409)->setJSON([
|
||||
'ok' => 0,
|
||||
'error_text' => 'ABHA identity mismatch. The alternate-mobile response did not match the Aadhaar-verified person and was rejected.',
|
||||
'request_id' => (string) ($result['request_id'] ?? ''),
|
||||
]);
|
||||
}
|
||||
session()->remove('abha_enrol_identity_' . $txnId);
|
||||
$abhaAddress = (string) (
|
||||
($profile['preferredAddress'] ?? '')
|
||||
?: ($profile['preferredAbhaAddress'] ?? '')
|
||||
|
|
|
|||
|
|
@ -115,6 +115,10 @@ interface AbdmConnectorInterface
|
|||
*/
|
||||
public function abhaMobileVerifyOtp(array $payload): array;
|
||||
|
||||
public function abhaEnrolMobileRequestOtp(array $payload): array;
|
||||
|
||||
public function abhaEnrolMobileVerifyOtp(array $payload): array;
|
||||
|
||||
/**
|
||||
* ABDM M1: List ABHA address suggestions for an in-progress enrolment.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -157,6 +157,16 @@ class DirectAbdmConnector implements AbdmConnectorInterface
|
|||
);
|
||||
}
|
||||
|
||||
public function abhaEnrolMobileRequestOtp(array $payload): array
|
||||
{
|
||||
throw new \RuntimeException('DirectAbdmConnector::abhaEnrolMobileRequestOtp() not implemented.');
|
||||
}
|
||||
|
||||
public function abhaEnrolMobileVerifyOtp(array $payload): array
|
||||
{
|
||||
throw new \RuntimeException('DirectAbdmConnector::abhaEnrolMobileVerifyOtp() not implemented.');
|
||||
}
|
||||
|
||||
public function abhaAddressSuggestions(array $payload): array
|
||||
{
|
||||
throw new \RuntimeException(
|
||||
|
|
|
|||
|
|
@ -172,6 +172,16 @@ class DreamsoftConnector implements AbdmConnectorInterface
|
|||
);
|
||||
}
|
||||
|
||||
public function abhaEnrolMobileRequestOtp(array $payload): array
|
||||
{
|
||||
throw new \RuntimeException('ABHA enrolment mobile OTP requires the synchronous e-Atria Bridge connector.');
|
||||
}
|
||||
|
||||
public function abhaEnrolMobileVerifyOtp(array $payload): array
|
||||
{
|
||||
throw new \RuntimeException('ABHA enrolment mobile OTP verification requires the synchronous e-Atria Bridge connector.');
|
||||
}
|
||||
|
||||
public function abhaAddressSuggestions(array $payload): array
|
||||
{
|
||||
throw new \RuntimeException(
|
||||
|
|
|
|||
|
|
@ -968,6 +968,37 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
return $this->attachOfficialAbhaCard($result);
|
||||
}
|
||||
|
||||
public function abhaEnrolMobileRequestOtp(array $payload): array
|
||||
{
|
||||
$body = [
|
||||
'txnId' => (string) ($payload['txnId'] ?? $payload['txn_id'] ?? ''),
|
||||
'mobile' => (string) ($payload['mobile'] ?? ''),
|
||||
];
|
||||
if ($this->hfrId !== '') {
|
||||
$body['hfr_id'] = $this->hfrId;
|
||||
}
|
||||
|
||||
return $this->post('/v3/abha/enrol/mobile/request-otp', $body);
|
||||
}
|
||||
|
||||
public function abhaEnrolMobileVerifyOtp(array $payload): array
|
||||
{
|
||||
$body = [
|
||||
'txnId' => (string) ($payload['txnId'] ?? $payload['txn_id'] ?? ''),
|
||||
'otp' => (string) ($payload['otp'] ?? ''),
|
||||
];
|
||||
if ($this->hfrId !== '') {
|
||||
$body['hfr_id'] = $this->hfrId;
|
||||
}
|
||||
|
||||
$result = $this->post('/v3/abha/enrol/mobile/verify-otp', $body);
|
||||
if (empty($result['ok']) || (int) $result['ok'] !== 1) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->attachOfficialAbhaCard($result);
|
||||
}
|
||||
|
||||
public function abhaAddressSuggestions(array $payload): array
|
||||
{
|
||||
$txnId = (string) ($payload['txn_id'] ?? $payload['txnId'] ?? '');
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@
|
|||
<span class="input-group-text"><i class="bi bi-phone"></i></span>
|
||||
<input type="text" class="form-control" id="abhaCreateMobile" maxlength="10" inputmode="numeric" autocomplete="tel" placeholder="10-digit mobile">
|
||||
</div>
|
||||
<div class="form-text">Required by ABDM enrolment. If this differs from the Aadhaar-linked mobile, it is verified separately.</div>
|
||||
<div class="form-text">Required by ABDM enrolment. A different number is verified through the Aadhaar-bound enrolment transaction.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -374,8 +374,7 @@ window.AbhaCreateModal = (function () {
|
|||
stopTimers();
|
||||
createdProfile = response;
|
||||
createTxnId = response.txn_id || createTxnId;
|
||||
var abhaMobile = digits(response.mobile).slice(-10);
|
||||
if (communicationMobile && communicationMobile !== abhaMobile) {
|
||||
if (communicationMobile && digits(response.mobile).slice(-10) !== communicationMobile) {
|
||||
requestMobileOtp();
|
||||
return;
|
||||
}
|
||||
|
|
@ -387,22 +386,22 @@ window.AbhaCreateModal = (function () {
|
|||
}
|
||||
|
||||
function requestMobileOtp() {
|
||||
alertBox('info', 'ABHA verified. Requesting an OTP for the alternate communication mobile...');
|
||||
alertBox('info', 'Aadhaar verified. Requesting OTP for the alternate communication mobile...');
|
||||
$.post('<?= base_url('abha/create/communication') ?>', { mobile: communicationMobile, txn_id: createTxnId, '<?= csrf_token() ?>': csrf() }, function (response) {
|
||||
if (!response || response.ok != 1) {
|
||||
renderProfile(createdProfile || {});
|
||||
alertBox('warning', 'ABHA verification succeeded, but the communication mobile was not updated: ' + apiMessage(response, 'Unable to send the mobile OTP.'));
|
||||
alertBox('warning', 'Aadhaar verification succeeded, but the alternate mobile OTP could not be sent: ' + apiMessage(response, 'Unable to send mobile OTP.'));
|
||||
return;
|
||||
}
|
||||
mobileTxnId = response.txn_id || createTxnId;
|
||||
$('#abhaCreateMobileHint').html('Enter the OTP sent to <strong>' + escapeHtml(maskMobile(communicationMobile)) + '</strong> to update the mobile registered on this ABHA account.');
|
||||
$('#abhaCreateMobileHint').text(response.message || ('OTP sent to ' + maskMobile(communicationMobile) + '.'));
|
||||
$('#abhaCreateMobileOtp').val('');
|
||||
showStep(3);
|
||||
startMobileResendTimer($('#abhaCreateMobileResendBtn'));
|
||||
$('#abhaCreateMobileOtp').trigger('focus');
|
||||
}, 'json').fail(function (xhr) {
|
||||
renderProfile(createdProfile || {});
|
||||
alertBox('warning', 'ABHA verification succeeded, but the communication mobile was not updated: ' + apiMessage(xhr.responseJSON, 'Unable to send the mobile OTP.'));
|
||||
alertBox('warning', 'Aadhaar verification succeeded, but the alternate mobile OTP could not be sent: ' + apiMessage(xhr.responseJSON, 'Unable to send mobile OTP.'));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user