diff --git a/recaptcha/.gitignore b/recaptcha/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/recaptcha/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/recaptcha/README.md b/recaptcha/README.md new file mode 100644 index 0000000..ca78bde --- /dev/null +++ b/recaptcha/README.md @@ -0,0 +1,12 @@ +recaptcha +===== + +Модуль содержит класс `RecaptchaController` - служит для проверки используемого сервиса (Huawei или Google) и показа диалога с каптчёй + +Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта + +### Конструктор +`googleRecaptchaKey` - ключ для google recaptcha +`huaweiAppId` - `id` приложения для huawei captcha +`onNewTokenReceived` - callback на успешную проверку каптчи +`processThrowable` - callback на ошибку проверки каптчи diff --git a/recaptcha/build.gradle b/recaptcha/build.gradle new file mode 100644 index 0000000..42c941e --- /dev/null +++ b/recaptcha/build.gradle @@ -0,0 +1,50 @@ +apply from: "../android-configs/lib-config.gradle" +apply plugin: 'com.huawei.agconnect' + +dependencies { + implementation project(':kotlin-extensions') + implementation "androidx.core:core" + implementation "androidx.annotation:annotation" + implementation "com.google.android.material:material" + implementation "com.google.android.gms:play-services-safetynet" + implementation "com.google.android.gms:play-services-base" + implementation "com.huawei.hms:safetydetect" + + constraints { + implementation("androidx.core:core") { + version { + require '1.0.0' + } + } + + implementation("androidx.annotation:annotation") { + version { + require '1.1.0' + } + } + + implementation("com.google.android.gms:play-services-safetynet") { + version { + require '17.0.0' + } + } + + implementation("com.google.android.gms:play-services-base") { + version { + require '18.0.1' + } + } + + implementation("com.huawei.hms:safetydetect") { + version { + require '4.0.3.300' + } + } + + implementation("com.google.android.material:material") { + version { + require '1.2.0-rc01' + } + } + } +} diff --git a/recaptcha/src/main/AndroidManifest.xml b/recaptcha/src/main/AndroidManifest.xml new file mode 100644 index 0000000..17ef42a --- /dev/null +++ b/recaptcha/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt new file mode 100644 index 0000000..d3720ee --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/RecaptchaController.kt @@ -0,0 +1,60 @@ +package ru.touchin.recaptcha + +import android.app.Activity +import com.google.android.gms.safetynet.SafetyNet +import com.huawei.hms.support.api.safetydetect.SafetyDetect +import ru.touchin.recaptcha.ServicesUtils.checkGooglePlayServices +import ru.touchin.recaptcha.ServicesUtils.checkHuaweiServices + +class RecaptchaController( + private val activity: Activity, + private val googleRecaptchaKey: String? = null, + private val huaweiAppId: String? = null, + private val onNewTokenReceived: (String) -> Unit, + private val processThrowable: (Throwable) -> Unit +) { + + fun showRecaptchaAlert() { + when { + checkHuaweiServices(activity) -> showHuaweiCaptcha() + checkGooglePlayServices(activity) -> showGoogleCaptcha() + } + } + + private fun showGoogleCaptcha() { + if (googleRecaptchaKey != null) { + SafetyNet.getClient(activity) + .verifyWithRecaptcha(googleRecaptchaKey) + .addOnSuccessListener(activity) { response -> + onServiceTokenResponse(response?.tokenResult) + } + .addOnFailureListener(activity, processThrowable) + } + } + + private fun showHuaweiCaptcha() { + if (huaweiAppId != null) { + val huaweiSafetyDetectClient = SafetyDetect.getClient(activity) + huaweiSafetyDetectClient.initUserDetect() + .addOnSuccessListener { + huaweiSafetyDetectClient.userDetection(huaweiAppId) + .addOnSuccessListener { response -> + onServiceTokenResponse(response?.responseToken) + } + .addOnFailureListener(activity, processThrowable) + } + .addOnFailureListener(activity, processThrowable) + } + } + + private fun onServiceTokenResponse(newToken: String?) { + if (!newToken.isNullOrBlank()) { + onNewTokenReceived.invoke(newToken) + } else { + processThrowable.invoke(EmptyCaptchaTokenException()) + } + } + +} + +class EmptyCaptchaTokenException : Throwable("Captcha token is empty") diff --git a/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt b/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt new file mode 100644 index 0000000..502a731 --- /dev/null +++ b/recaptcha/src/main/java/ru/touchin/recaptcha/ServicesUtils.kt @@ -0,0 +1,19 @@ +package ru.touchin.recaptcha + +import android.content.Context +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailability +import com.huawei.hms.api.HuaweiApiAvailability + +//TODO: in the future move to a module with services +object ServicesUtils { + + fun checkHuaweiServices(context: Context): Boolean = + HuaweiApiAvailability.getInstance() + .isHuaweiMobileNoticeAvailable(context) == ConnectionResult.SUCCESS + + fun checkGooglePlayServices(context: Context): Boolean = + GoogleApiAvailability.getInstance() + .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS + +}