package com.instantpayrdservice
import android.app.Activity
import android.content.Intent
import android.util.Base64
import android.util.Log
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.BaseActivityEventListener
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.WritableMap
import java.security.MessageDigest
import kotlin.random.Random
class InstantpayRdServiceModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
val SUCCESS: String = "SUCCESS"
val FAILED: String = "FAILED"
lateinit var DATA: String
private var responsePromise: Promise? = null
private var packageNameParam = ""
private var pidOptionParam = ""
override fun getName(): String {
return NAME
}
companion object {
const val NAME = "InstantpayRdService"
const val RDINFO_CODE = 1
const val RDCAPTURE_CODE = 2
const val RDFACECAPTURE_CODE = 3
const val RDEYEINFO_CODE = 4
const val RDEYECAPTURE_CODE = 5
}
private val activityEventListener = object : BaseActivityEventListener(){
override fun onActivityResult(
activity: Activity?,
requestCode: Int,
resultCode: Int,
data: Intent?
) {
super.onActivityResult(activity, requestCode, resultCode, data)
if(data == null){
return resolve("No action taken")
}
if(requestCode == RDINFO_CODE){
val requiredValue = data.getStringExtra("RD_SERVICE_INFO")
if(requiredValue == null){
return resolve("Device not ready")
}
if(requiredValue.length <= 10){
return resolve("Device not ready" , FAILED, "", "", requiredValue+" #RDRES1")
}
if(requiredValue.lowercase().contains("notready" , true)){
return resolve("Device not ready" , FAILED, "", "", requiredValue+" #RDRES3")
}
captureData()
return
}
if(requestCode == RDEYEINFO_CODE){
val requiredValue = data.getStringExtra("RD_SERVICE_INFO")
if(requiredValue == null){
return resolve("Device not ready")
}
if(requiredValue.length <= 10){
return resolve("Device not ready" , FAILED, "", "", requiredValue+" #RDRES6")
}
if(requiredValue.lowercase().contains("notready" , true)){
return resolve("Device not ready" , FAILED, "", "", requiredValue+" #RDRES7")
}
eyeCaptureData()
return
}
if(requestCode == RDCAPTURE_CODE){
val captureXML = data.getStringExtra("PID_DATA")
if (captureXML == null || captureXML.length <= 10) {
return resolve("Device not ready" , FAILED, "", "", captureXML+" #RDRES4")
}
if (captureXML.lowercase().contains("device not ready", true)) {
return resolve("Device not ready" , FAILED, "", "", captureXML+" #RDRES5")
}
val sanitizeXml = parseBioMetricData(captureXML)
return resolve("Successfully Captured the data",SUCCESS, sanitizeXml)
}
if(requestCode == RDFACECAPTURE_CODE){
/*val resultData = StringBuilder("Request Code: $requestCode, Result Code: $resultCode\n")
data.extras?.let { bundle ->
for (key in bundle.keySet()) {
val value = bundle.get(key)
logPrint("Key: ${key}, Value: $value")
resultData.append("Key: $key, Value: $value; ")
}
}*/
val captureXML = data.getStringExtra("response")
val sanitizeXml = parseBioMetricData(captureXML!!)
return resolve("Successfully Captured the data",SUCCESS, sanitizeXml)
}
if(requestCode == RDEYECAPTURE_CODE){
/*val resultData = StringBuilder("Request Code: $requestCode, Result Code: $resultCode\n")
data.extras?.let { bundle ->
for (key in bundle.keySet()) {
val value = bundle.get(key)
logPrint("Key: ${key}, Value: $value")
resultData.append("Key: $key, Value: $value; ")
}
}*/
val captureXML = data.getStringExtra("PID_DATA")
if (captureXML == null || captureXML.length <= 10) {
return resolve("Device not ready" , FAILED, "", "", captureXML+" #RDRES4")
}
if (captureXML.lowercase().contains("device not ready", true)) {
return resolve("Device not ready" , FAILED, "", "", captureXML+" #RDRES5")
}
val sanitizeXml = parseBioMetricData(captureXML)
return resolve("Successfully Captured the data",SUCCESS, sanitizeXml)
}
}
}
init {
reactContext.addActivityEventListener(activityEventListener)
}
private fun deviceInfo(){
try {
val activity = currentActivity ?: return resolve("Activity doesn't exist "+"#DVIRD3")
val intent = Intent()
intent.setAction("in.gov.uidai.rdservice.fp.INFO")
activity.startActivityForResult(intent, RDINFO_CODE)
}
catch (e: Exception){
resolve("RD services not available" , FAILED, "", "", e.message.toString()+" #DVIRD1")
}
}
private fun captureData(){
try {
val activity = currentActivity ?: return resolve("Activity doesn't exist "+"#CPDRD3")
var pidOption = ""
if (pidOptionParam.length >= 10 ) {
pidOption = pidOptionParam
}
val intent = Intent()
intent.setAction("in.gov.uidai.rdservice.fp.CAPTURE")
intent.putExtra("PID_OPTIONS", pidOption)
intent.setPackage(packageNameParam)
activity.startActivityForResult(intent, RDCAPTURE_CODE)
}
catch (e:Exception){
resolve("Selected device not found" , FAILED, "", "", e.message.toString()+" #CPDRD1")
}
}
private fun parseBioMetricData(xmlData: String): String {
var bioxml = xmlData
bioxml = bioxml.replace("\\n ", " ")
bioxml = bioxml.replace("\\n ", " ")
bioxml = bioxml.replace("\\n ", " ")
return bioxml
}
@ReactMethod
fun getFingerPrint(deviceName: String, pidOption: String, prm: Promise) {
try {
responsePromise = prm
packageNameParam = deviceName
pidOptionParam = pidOption
deviceInfo()
}
catch (e: Exception) {
resolve("RD services not available" , FAILED, "", "", e.message.toString()+" #GFPRD1")
}
}
@ReactMethod
fun openFaceAuth(pidOption: String, prm: Promise){
try {
responsePromise = prm
//pidOptionParam = pidOption
val activity = currentActivity ?: return resolve("Activity doesn't exist "+"#CPDRD4")
val CAPTURE_INTENT = "in.gov.uidai.rdservice.face.CAPTURE"
val CAPTURE_INTENT_REQUEST = "request"
val intent = Intent(CAPTURE_INTENT)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
//intent.putExtra(CAPTURE_INTENT_REQUEST, createFacePidOptionForAuth(getRandomNumber(), "P"))
//intent.putExtra(CAPTURE_INTENT_REQUEST,createFacePidOptionForKUA(getRandomNumber(), "P"))
intent.putExtra(CAPTURE_INTENT_REQUEST, pidOption)
activity.startActivityForResult(intent, RDFACECAPTURE_CODE)
}
catch (e: Exception) {
resolve("Face Auth services not available, Please install AadhaarFaceRD from play store." , FAILED, "", "", e.message.toString()+" #GFPRD2")
}
}
private fun getRandomNumber(): String {
val start = 10000000
val end = 99999999
val number = Random(System.nanoTime()).nextInt(end - start + 1) + start
return number.toString()
}
fun createFacePidOptionForAuth(txnId: String, buildType:String): String {
return createFacePidOptions(txnId, "auth", buildType)
}
private fun createFacePidOptions(txnId: String, purpose: String, buildType:String): String {
return "\n" +
"\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
""
}
fun createFacePidOptionForKUA(txnId: String, buildType:String): String {
return createFacePidOptionsKUA(txnId, "auth", getWADHForFace(), buildType)
}
fun getWADHForFace(): String {
val VERSION = "2.5"
val RESIDENT_AUTHENTICATION_TYPE = "P"
val RESIDENT_CONSENT = "Y"
var LOCAL_LANGUAGE_IR = "N"
val DECRYPTION = "N"
val PRINT_FORMAT="N"
return getWADHValueForFace(VERSION + RESIDENT_AUTHENTICATION_TYPE + RESIDENT_CONSENT + LOCAL_LANGUAGE_IR + DECRYPTION + PRINT_FORMAT)
}
private fun getWADHValueForFace(plainWADH: String): String {
val hash = MessageDigest.getInstance("SHA-256").digest(plainWADH.toByteArray())
return Base64.encodeToString(hash, Base64.NO_WRAP)
}
private fun createFacePidOptionsKUA(txnId: String, purpose: String, wadh:String, buildType:String): String {
return "\n" +
"\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
""
}
@ReactMethod
fun openEyeAuth(deviceName: String, pidOption: String, prm: Promise){
try {
responsePromise = prm
packageNameParam = deviceName
pidOptionParam = pidOption
eyeDeviceInfo()
}
catch (e: Exception) {
resolve("Iris Eye Auth services not available" , FAILED, "", "", e.message.toString()+" #OEARD1")
}
}
private fun eyeDeviceInfo(){
try {
val activity = currentActivity ?: return resolve("Activity doesn't exist "+"#EDVIRD1")
val intent = Intent()
intent.setAction("in.gov.uidai.rdservice.iris.INFO")
activity.startActivityForResult(intent, RDEYEINFO_CODE)
}
catch (e: Exception){
resolve("RD services not available" , FAILED, "", "", e.message.toString()+" #DVIRD1")
}
}
private fun eyeCaptureData(){
try {
val activity = currentActivity ?: return resolve("Activity doesn't exist "+"#ECPDRD1")
var pidOption = " "
if (pidOptionParam.length >= 10 ) {
pidOption = pidOptionParam
}
val intent = Intent()
intent.setAction("in.gov.uidai.rdservice.iris.CAPTURE")
intent.putExtra("PID_OPTIONS", pidOption)
intent.setPackage(packageNameParam)
activity.startActivityForResult(intent, RDEYECAPTURE_CODE)
}
catch (e:Exception){
resolve("Selected device not found" , FAILED, "", "", e.message.toString()+" #CPDRD1")
}
}
private fun resolve(message: String, status: String = FAILED ,data: String = "", actCode: String = "", exceptionMessage: String = "" ){
if(responsePromise == null){
return
}
val map: WritableMap = Arguments.createMap()
map.putString("status",status)
map.putString("message",message)
map.putString("data",data)
map.putString("actCode",actCode)
if(exceptionMessage.isNotEmpty()){
map.putString("exceptionMessage",exceptionMessage)
}
responsePromise!!.resolve(map)
responsePromise = null
}
private fun logPrint(value: String?) {
if (value == null) {
return
}
Log.i("InstantpayRdService*", value)
}
}