class CafSmartAuthBridgeModule : Module() {
private val context
get() = requireNotNull(appContext.reactContext)
private val activity
get() = requireNotNull(appContext.currentActivity)
// Cada classe de módulo deve implementar a função definition. A definição consiste em componentes
// que descrevem a funcionalidade e o comportamento do módulo.
// Veja https://docs.expo.dev/modules/module-api para mais detalhes sobre os componentes disponíveis.
override fun definition() = ModuleDefinition {
// Define o nome do módulo que o código JavaScript usará para se referir ao módulo. Recebe uma string como argumento.
// Pode ser inferido pelo nome da classe do módulo, mas é recomendável defini-lo explicitamente para maior clareza.
// O módulo ficará acessível a partir de `requireNativeModule('CafSmartAuthBridgeModule')` em JavaScript.
Name(CAF_SMART_AUTH_MODULE_NAME)
// Define os nomes de eventos que o módulo pode enviar ao JavaScript.
Events(
CAF_SMART_AUTH_SUCCESS_EVENT,
CAF_SMART_AUTH_PENDING_EVENT,
CAF_SMART_AUTH_ERROR_EVENT,
CAF_SMART_AUTH_CANCEL_EVENT,
CAF_SMART_AUTH_LOADING_EVENT,
CAF_SMART_AUTH_LOADED_EVENT
)
// Define uma função síncrona JavaScript que executa o código nativo na thread do JavaScript.
Function(CAF_SMART_AUTH_FUNCTION_START_SMART_AUTH) { mfaToken: String, faceAuthToken: String, personId: String, policyId: String, jsonString: String ->
Handler(Looper.getMainLooper()).post {
val smartAuth = build(
mfaToken = mfaToken,
faceAuthToken = faceAuthToken,
settings = jsonString
)
smartAuth.verifyPolicy(personId, policyId, setupListener())
}
}
// Define uma função assíncrona JavaScript que executa o código nativo na thread JavaScript.
AsyncFunction(CAF_SMART_AUTH_FUNCTION_REQUEST_LOCATION_PERMISSIONS) {
Handler(Looper.getMainLooper()).post {
try {
requestPermission(
permission = Manifest.permission.ACCESS_FINE_LOCATION,
activity = activity
)
requestPermission(
permission = Manifest.permission.ACCESS_COARSE_LOCATION,
activity = activity
)
} catch (e: Exception) {
throw IllegalStateException("$PERMISSION_ERROR_DESCRIPTION ${e.message}")
}
}
}
}
private fun build(mfaToken: String, faceAuthToken: String, settings: String): CafSmartAuth {
val smartAuthSettings = CafSmartAuthBridgeSettings(settings = settings)
return CafSmartAuth.CafBuilder(mfaToken, context).apply {
setSdkPlatform(CafSdkPlatform.REACT_NATIVE)
smartAuthSettings.cafStage?.let { setStage(it) }
smartAuthSettings.emailUrl?.let { setEmailUrl(it) }
smartAuthSettings.phoneUrl?.let { setPhoneUrl(it) }
setFaceAuthenticatorSettings(
CafFaceAuthenticatorSettings(
faceAuthToken,
smartAuthSettings.faceAuthenticatorSettings?.loadingScreen,
smartAuthSettings.faceAuthenticatorSettings?.enableScreenCapture,
smartAuthSettings.faceAuthenticatorSettings?.filter
)
)
setThemeConfigurator(
CafThemeConfigurator(
lightTheme = smartAuthSettings.theme?.lightTheme ?: CafTheme(),
darkTheme = smartAuthSettings.theme?.darkTheme ?: CafTheme()
)
)
}.build()
}
private fun setupListener() = object : CafVerifyPolicyListener {
override fun onSuccess(
isAuthorized: Boolean,
attemptId: String?,
attestation: String?
) {
sendEvent(CAF_SMART_AUTH_SUCCESS_EVENT, mapOf(
CAF_MAP_KEY_IS_AUTHORIZED to isAuthorized,
CAF_MAP_KEY_ATTEMPT_ID to (attemptId ?: ""),
CAF_MAP_KEY_ATTESTATION to (attestation ?: "")
))
}
override fun onPending(isAuthorized: Boolean, attestation: String?) {
sendEvent(CAF_SMART_AUTH_PENDING_EVENT, mapOf(
CAF_MAP_KEY_IS_AUTHORIZED to isAuthorized,
CAF_MAP_KEY_ATTESTATION to (attestation ?: "")
))
}
override fun onError(failure: CafFailure, message: String?) {
sendEvent(CAF_SMART_AUTH_ERROR_EVENT, mapOf(
CAF_MAP_KEY_ERROR_MESSAGE to failure.message
))
}
override fun onCancel() {
sendEvent(CAF_SMART_AUTH_CANCEL_EVENT, mapOf(CAF_MAP_KEY_IS_CANCELLED to true))
}
override fun onLoading() {
sendEvent(CAF_SMART_AUTH_LOADING_EVENT, mapOf(CAF_MAP_KEY_IS_LOADING to true))
}
override fun onLoaded() {
sendEvent(CAF_SMART_AUTH_LOADED_EVENT, mapOf(CAF_MAP_KEY_IS_LOADED to true))
}
}
private fun requestPermission(permission: String, activity: Activity) {
if (ContextCompat.checkSelfPermission(
context,
permission
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(activity, arrayOf(permission), REQUEST_CODE)
}
}
companion object {
private const val REQUEST_CODE = 1234
private const val CAF_SMART_AUTH_MODULE_NAME = "CafSmartAuthBridgeModule"
private const val CAF_SMART_AUTH_FUNCTION_START_SMART_AUTH = "startSmartAuth"
private const val CAF_SMART_AUTH_FUNCTION_REQUEST_LOCATION_PERMISSIONS = "requestLocationPermissions"
private const val CAF_SMART_AUTH_SUCCESS_EVENT = "CafSmartAuth_Success"
private const val CAF_SMART_AUTH_PENDING_EVENT = "CafSmartAuth_Pending"
private const val CAF_SMART_AUTH_ERROR_EVENT = "CafSmartAuth_Error"
private const val CAF_SMART_AUTH_CANCEL_EVENT = "CafSmartAuth_Cancel"
private const val CAF_SMART_AUTH_LOADING_EVENT = "CafSmartAuth_Loading"
private const val CAF_SMART_AUTH_LOADED_EVENT = "CafSmartAuth_Loaded"
private const val CAF_MAP_KEY_IS_AUTHORIZED = "isAuthorized"
private const val CAF_MAP_KEY_ATTEMPT_ID = "attemptId"
private const val CAF_MAP_KEY_ATTESTATION = "attestation"
private const val CAF_MAP_KEY_ERROR_MESSAGE = "errorMessage"
private const val CAF_MAP_KEY_IS_CANCELLED = "isCancelled"
private const val CAF_MAP_KEY_IS_LOADING = "isLoading"
private const val CAF_MAP_KEY_IS_LOADED = "isLoaded"
private const val PERMISSION_ERROR_DESCRIPTION = "Erro ao verificar as permissões de localização:"
}
}