Skip to content

Commit

Permalink
fix: Code cleanup and sandbox_config update
Browse files Browse the repository at this point in the history
  • Loading branch information
Sajinsr authored and akashkrishna619 committed Aug 25, 2022
1 parent f917d6c commit 11d33aa
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 107 deletions.
120 changes: 57 additions & 63 deletions healthcare/regional/india/abdm/js/patient.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ let create_abha = function (frm) {
label: 'Mobile',
fieldname: 'mobile',
fieldtype: 'Int',
default: frm.doc.mobile,
depends_on: "eval:doc.mode == 'Mobile'",
mandatory_depends_on: "eval:doc.mode == 'Mobile'"
},
Expand Down Expand Up @@ -122,12 +123,6 @@ let create_abha = function (frm) {
fieldname: 'verify_user_name',
fieldtype: 'Button'
}
// {
// label: 'Password',
// fieldname: 'password',
// fieldtype: 'Data',
// description: 'Must contain an uppercase, a lowercase, a number, a special character and at least 8 or more characters. It should not contain any sequences (like 123)'
// },
],
primary_action_label: 'Create ABHA ID',
primary_action(values) {
Expand Down Expand Up @@ -240,69 +235,68 @@ let create_abha = function (frm) {
primary_action_label: 'Create ABHA ID',
primary_action(values) {
frappe.call({
method: 'healthcare.regional.india.abdm.utils.auth_cert_and_rsa_encryption',
method: 'healthcare.regional.india.abdm.utils.abdm_request',
args: {
'message': dialog.get_value('otp')
'payload': {
'to_encrypt': dialog.get_value('otp'),
'txnId': txn_id
},
'url_key': 'verify_mobile_otp',
'req_type': 'Health ID',
'to_be_enc': 'otp'
},
callback: function (data) {
let otp_encrypted = data.message['encrypted_msg'];
frappe.call({
method: 'healthcare.regional.india.abdm.utils.abdm_request',
args: {
'payload': {
'otp': otp_encrypted,
'txnId': txn_id
freeze: true,
freeze_message: __('<br><br>Verifying OTP... <br><small>Please note, this may take a while</small>'),
callback: function (r) {
if (!r.message['token']) {
frappe.show_alert({
message:__('Incorrect OTP entered, Please Re-enter OTP'),
indicator:'red'
}, 10);
} else {
frappe.call({
method: 'healthcare.regional.india.abdm.utils.abdm_request',
args: {
'payload': {
"email": frm.doc.email || '',
"firstName": frm.doc.first_name || '',
"lastName": frm.doc.last_name || '',
"middleName": frm.doc.middle_name || '',
"mobile": frm.doc.mobile || '',
"txnId": txn_id,
"gender": (frm.doc.sex == 'Male') ? 'M' : (frm.doc.sex == 'Female') ? 'F' : (frm.doc.sex == 'Prefer not to say') ? 'U' : 'O',
"name": dialog.get_value('name'),
"yearOfBirth": dialog.get_value('yob')
},
'url_key': 'create_abha_w_mobile',
'req_type': 'Health ID',
'rec_headers': {
'T-Token': r.message['token']
}
},
'url_key': 'verify_mobile_otp',
'req_type': 'Health ID'
},
freeze: true,
freeze_message: __('<br><br><br>Creating Health ID <br><small>Please note, this may take a while</small>'),
callback: function (r) {
if (!r.message['token']) {
frappe.show_alert({
message:__('Incorrect OTP entered, Please Re-enter OTP'),
indicator:'red'
}, 10);
} else {
frappe.call({
method: 'healthcare.regional.india.abdm.utils.abdm_request',
args: {
'payload': {
"email": frm.doc.email || '',
"firstName": frm.doc.first_name || '',
"lastName": frm.doc.last_name || '',
"middleName": frm.doc.middle_name || '',
"mobile": frm.doc.mobile || '',
"txnId": txn_id,
"gender": (frm.doc.sex == 'Male') ? 'M' : (frm.doc.sex == 'Female') ? 'F' : (frm.doc.sex == 'Prefer not to say') ? 'U' : 'O',
"name": dialog.get_value('name'),
"yearOfBirth": dialog.get_value('yob')
},
'url_key': 'create_abha_w_mobile',
'req_type': 'Health ID',
'rec_headers': {
'T-Token': r.message['token']
}
},
callback: function (data) {
dialog.hide();
if (data.message['healthIdNumber']) {
frm.set_value('phr_address', data.message['healthId'])
frm.set_value('abha_number', data.message['healthIdNumber'])
frappe.show_alert({ message: __('ABHA ID created successfully'), indicator: 'green' }, 5);
frm.save()
} else {
frappe.throw({ message: __("ABHA ID not Created"), title: __("Not Created") });
}
}
});
freeze: true,
freeze_message: __('Creating Health ID <br><small>Please note, this may take a while</small>'),
callback: function (data) {
dialog.hide();
if (data.message['healthIdNumber']) {
frm.set_value('abha_number', data.message['healthIdNumber'])
frm.save()
frappe.msgprint({
title: __('ABHA ID created successfully'),
indicator: 'green',
message: __('ABHA ID created, Your ABHA Number is ' + data.message['healthIdNumber'] +
` To activate account link Aadhaar is mandatory, please login to https://healthid.ndhm.gov.in/login
and Link Aadhaar.\n Thank you..`)
});
} else {
frappe.throw({ message: __("ABHA ID not Created"), title: __("Not Created") });
}
}
}
})
});
}
}
});
dialog.hide();
dialog.show();
}
});
dialog.fields_dict.resend_otp.input.onclick = function () {
Expand Down
31 changes: 17 additions & 14 deletions healthcare/regional/india/abdm/sandbox_config.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
def get_urls():
return {
"authorization": ['POST', "v0.5/sessions"],
"exists_by_health_id": ['POST', "v1/search/existsByHealthId"],
"verify_health_id": ['POST', "v1/search/searchByHealthId"],
"generate_aadhaar_otp": ['POST', "v1/registration/aadhaar/generateOtp"],
"generate_mobile_otp": ['POST', "v2/registration/mobile/generateOtp"],
"verify_mobile_otp": ['POST', "v2/registration/mobile/verifyOtp"],
"resend_mobile_otp": ['POST', "v2/registration/mobile/resendOtp"],
"resend_aadhaar_otp": ['POST', "v2/registration/aadhaar/resendAadhaarOtp"],
"create_abha_w_aadhaar": ['POST', "v1/registration/aadhaar/createHealthIdWithAadhaarOtp"],
"create_abha_w_mobile": ['POST', "v2/registration/mobile/createHidViaMobile"],
"auth_cert": ['GET', "v2/auth/cert"]
}

config = {
"authorization": {'method':'POST', 'url': 'v0.5/sessions', 'encrypted': False},
"exists_by_health_id": {'method':'POST', 'url': 'v1/search/existsByHealthId', 'encrypted': False},
"verify_health_id": {'method':'POST', 'url': 'v1/search/searchByHealthId', 'encrypted': False},
"generate_aadhaar_otp": {'method':'POST', 'url': 'v1/registration/aadhaar/generateOtp', 'encrypted': False},
"generate_mobile_otp": {'method':'POST', 'url': 'v2/registration/mobile/generateOtp', 'encrypted': False},
"verify_mobile_otp": {'method':'POST', 'url': 'v2/registration/mobile/verifyOtp', 'encrypted': True},
"resend_mobile_otp": {'method':'POST', 'url': 'v2/registration/mobile/resendOtp', 'encrypted': False},
"resend_aadhaar_otp": {'method':'POST', 'url': 'v2/registration/aadhaar/resendAadhaarOtp', 'encrypted': False},
"create_abha_w_aadhaar": {'method':'POST', 'url': 'v1/registration/aadhaar/createHealthIdWithAadhaarOtp', 'encrypted': False},
"create_abha_w_mobile": {'method':'POST', 'url': 'v2/registration/mobile/createHidViaMobile', 'encrypted': False},
"auth_cert": {'method':'GET', 'url': 'v2/auth/cert', 'encrypted': False}
}

def get_url_for(key):
return config.get(key)
80 changes: 50 additions & 30 deletions healthcare/regional/india/abdm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@
import requests
import frappe
from frappe import _
from healthcare.regional.india.abdm.sandbox_config import get_urls
from healthcare.regional.india.abdm.sandbox_config import get_url_for

@frappe.whitelist()
def get_authorization_token():
client_id, client_secret, base_url = frappe.db.get_value('ABDM Integration', \
{'company': frappe.defaults.get_user_default("Company"), 'default': 1},\
['client_id', 'client_secret', 'auth_base_url'])
url = get_urls()

config = get_url_for('authorization')
url = base_url+config.get('url')
payload = {
"clientId": client_id,
"clientSecret": client_secret
}
if base_url:
req = frappe.new_doc('ABDM Request')
req.request = json.dumps(payload, indent=4)
req.url = base_url+url.get('authorization')[1]
req.url = url
req.request_name = 'Authorization Token'
try:
response = requests.request(
method=url.get('authorization')[0],
url=base_url+url.get('authorization')[1],
method=config.get('method'),
url=url,
headers={"Content-Type": "application/json; charset=UTF-8"},
data=json.dumps(payload)
)
Expand All @@ -39,13 +41,13 @@ def get_authorization_token():
req.response = e
req.status = 'Revoked'
req.insert(ignore_permissions=True)
traceback = f"Remote URL {base_url+url.get('authorization')[1]}\nPayload: {payload}\nTraceback: {e}"
traceback = f"Remote URL {url}\nPayload: {payload}\nTraceback: {e}"
frappe.log_error(message=traceback, title='Cant create session')

@frappe.whitelist()
def abdm_request(payload, url_key, req_type, rec_headers=None):
def abdm_request(payload, url_key, req_type, rec_headers=None, to_be_enc=None):
if isinstance(payload, str):
payload = json.dumps(json.loads(payload))
payload = json.loads(payload)

if req_type == 'Health ID':
url_type = 'health_id_base_url'
Expand All @@ -55,88 +57,106 @@ def abdm_request(payload, url_key, req_type, rec_headers=None):
[url_type])
if not base_url:
frappe.throw(title='Not Configured', msg='Base URL not configured in ABDM Integration!')
url = get_urls()

config = get_url_for(url_key)
url = base_url+config.get('url')

# Check the sandbox_config, if the data need to be encypted, encrypts message
# Build payload with encrypted message
if config.get('encrypted') == True:
message = payload.get('to_encrypt')
encrypted = get_encrypted_message(message)
if 'encrypted_msg' in encrypted and encrypted['encrypted_msg']:
payload[to_be_enc] = payload.pop('to_encrypt')
payload[to_be_enc] = encrypted['encrypted_msg']

access_token, tokenType = get_authorization_token()

authorization = ("Bearer " if tokenType == "bearer" else '') + access_token
headers = {'Content-Type': 'application/json', 'Authorization': authorization, 'Accept': 'application/json'}
headers = {'Content-Type': 'application/json', 'Authorization': authorization,
'Accept': 'application/json'}
if rec_headers:
headers.update(json.loads(rec_headers))
if access_token:
req = frappe.new_doc('ABDM Request')
req.status = 'Requested'
#TODO: skip saving or encrypt the data saved
req.request = json.dumps(json.loads(payload), indent=4)
req.url = base_url+url.get(url_key)[1]
req.request = json.dumps(payload, indent=4)
req.url = url
req.request_name = url_key
try:
response=requests.request(
method=url.get(url_key)[0],
url=base_url+url.get(url_key)[1],
response = requests.request(
method=config.get('method'),
url=url,
headers=headers,
data=payload
data=json.dumps(payload)
)

response.raise_for_status()
req.response = json.dumps(response.json(), indent=4)
response=json.loads(json.dumps(response.json()))
response = json.loads(json.dumps(response.json()))
req.status = 'Granted'
req.insert(ignore_permissions=True)
return response

except Exception as e:
req.response = e
req.status = 'Revoked'
req.insert(ignore_permissions=True)
traceback = f"Remote URL {base_url+url.get(url_key)[1]}\nPayload: {payload}\nTraceback: {e}"
traceback = f"Remote URL {url}\nPayload: {payload}\nTraceback: {e}"
frappe.log_error(message=traceback, title='Cant complete API call')
return e
else:
return ''
frappe.throw(title='Authorization Failed', msg='Access token generation for authorization failed, Please try again.')

@frappe.whitelist()
def auth_cert_and_rsa_encryption(message):
def get_encrypted_message(message):
base_url = frappe.db.get_value('ABDM Integration', \
{'company': frappe.defaults.get_user_default("Company"), 'default': 1},\
['health_id_base_url'])
url = get_urls()

config = get_url_for('auth_cert')
url = base_url+config.get('url')
req = frappe.new_doc('ABDM Request')
req.status = 'Requested'
req.url = base_url+url.get('auth_cert')[1]
req.url = url
req.request_name = 'auth_cert'
try:
response = requests.request(
method=url.get('auth_cert')[0],
url=base_url+url.get('auth_cert')[1],
headers={'Content-Type': 'application/json; charset=UTF-8'}
method=config.get('method'),
url=url,
headers={'Content-Type': 'application/json'}
)

response.raise_for_status()
pub_key = response.text
pub_key = pub_key.replace('\n', '').replace('-----BEGIN PUBLIC KEY-----', '').replace('-----END PUBLIC KEY-----', '')
if pub_key:
encrypted_msg = rsa_encryption(message, pub_key)
req.response = encrypted_msg
req.status = 'Granted'
req.insert(ignore_permissions=True)
encrypted = {
'public_key': pub_key,
'encrypted_msg': encrypted_msg
}
return encrypted

except Exception as e:
req.response = e
req.status = 'Revoked'
req.insert(ignore_permissions=True)
traceback = f"Remote URL {base_url+url.get('auth_cert')[1]}\nTraceback: {e}"
traceback = f"Remote URL {url}\nTraceback: {e}"
frappe.log_error(message=traceback, title='Cant complete API call')
return None

@frappe.whitelist()
def rsa_encryption (message, pub_key):
# TODO:- Use cryptography
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
from base64 import b64decode, b64encode

public_key = pub_key
message = bytes(message, 'utf-8')
pubkey = b64decode(public_key)
pubkey = b64decode(pub_key)
rsa_key = RSA.importKey(pubkey)
cipher = PKCS1_v1_5.new(rsa_key)
ciphertext = cipher.encrypt(message)
Expand Down

0 comments on commit 11d33aa

Please sign in to comment.