Merge pull request #248 from TouchInstinct/add_captcha_module

create captcha module with checking
This commit is contained in:
rinstance 2022-03-17 16:29:59 +03:00 committed by GitHub
commit b7c6d88b0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 262 additions and 0 deletions

1
client-services/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,35 @@
apply from: "../android-configs/lib-config.gradle"
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation "androidx.core:core"
implementation "androidx.annotation:annotation"
implementation "com.google.android.gms:play-services-base"
implementation "com.huawei.hms:base"
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-base") {
version {
require '18.0.1'
}
}
implementation("com.huawei.hms:base") {
version {
require '6.3.0.303'
}
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="ru.touchin.client_services">
</manifest>

View File

@ -0,0 +1,5 @@
package ru.touchin.client_services
enum class MobileService {
HUAWEI_SERVICE, GOOGLE_SERVICE
}

View File

@ -0,0 +1,28 @@
package ru.touchin.client_services
import android.content.Context
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.huawei.hms.api.HuaweiApiAvailability
/**
* A class with utils for interacting with Google, Huawei services
*/
class ServicesUtils {
fun getCurrentService(context: Context): MobileService = when {
checkHuaweiServices(context) -> MobileService.HUAWEI_SERVICE
checkGooglePlayServices(context) -> MobileService.GOOGLE_SERVICE
else -> MobileService.GOOGLE_SERVICE
}
private fun checkHuaweiServices(context: Context): Boolean =
HuaweiApiAvailability.getInstance()
.isHuaweiMobileNoticeAvailable(context) == ConnectionResult.SUCCESS
private fun checkGooglePlayServices(context: Context): Boolean =
GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
}

1
recaptcha/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

33
recaptcha/README.md Normal file
View File

@ -0,0 +1,33 @@
recaptcha
=====
### Общее описание
Модуль содержит класс `CaptchaManager` - служит для проверки используемого сервиса (Huawei или Google) и показа диалога с каптчёй
В конструктуре `CaptchaManager` принимает два callback:
`onNewTokenReceived` - успешная проверка, возвращает токен
`processThrowable` - ошибка, возвращает `Throwable`
### Требования
Для использования модуля нужно добавить json файл с сервисами в корневую папку проекта:
1. Для Google - google-services.json
2. Для Huawei - agconnect-services.json
### Пример
Во `Fragment`
```kotlin
val manager = CaptchaManager(onNewTokenReceived = { token ->
viewModel.sendRequest(token)
}, processThrowable = { error ->
showError(error)
})
manager.showRecaptchaAlert(
activity = activity,
captchaKey = BuildConfig.CAPTCHA_TOKEN
)
```

44
recaptcha/build.gradle Normal file
View File

@ -0,0 +1,44 @@
apply from: "../android-configs/lib-config.gradle"
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation project(':client-services')
implementation "androidx.core:core"
implementation "androidx.annotation:annotation"
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 '18.0.1'
}
}
implementation("com.google.android.gms:play-services-base") {
version {
require '18.0.1'
}
}
implementation("com.huawei.hms:safetydetect") {
version {
require '4.0.3.300'
}
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="ru.touchin.recaptcha">
</manifest>

View File

@ -0,0 +1,24 @@
package ru.touchin.recaptcha
import android.app.Activity
abstract class CaptchaClient(
private val onNewTokenReceived: (String) -> Unit = {},
private val processThrowable: (Throwable) -> Unit = {}
) {
abstract fun showCaptcha(activity: Activity, captchaKey: String)
protected fun onServiceTokenResponse(newToken: String?) {
if (!newToken.isNullOrBlank()) {
onNewTokenReceived.invoke(newToken)
} else {
processThrowable.invoke(EmptyCaptchaTokenException())
}
}
}
class EmptyCaptchaKeyException : Throwable("Captcha key is empty")
class EmptyCaptchaTokenException : Throwable("Captcha token is empty")

View File

@ -0,0 +1,34 @@
package ru.touchin.recaptcha
import android.app.Activity
import ru.touchin.client_services.MobileService
import ru.touchin.client_services.ServicesUtils
/**
* A class for displaying a dialog with a captcha
* with a check on the current service of the application
*
* @param onNewTokenReceived - callback for a successful captcha check, return token
* @param processThrowable - callback for a captcha check error, return throwable
*/
class CaptchaManager(
private val onNewTokenReceived: (String) -> Unit,
private val processThrowable: (Throwable) -> Unit
) {
private val clientsMap = mapOf(
MobileService.GOOGLE_SERVICE to GoogleCaptchaClient(onNewTokenReceived, processThrowable),
MobileService.HUAWEI_SERVICE to HuaweiCaptchaClient(onNewTokenReceived, processThrowable)
)
fun showRecaptchaAlert(activity: Activity, captchaKey: String) {
if (captchaKey.isBlank()) {
processThrowable.invoke(EmptyCaptchaKeyException())
} else {
val service = ServicesUtils().getCurrentService(activity)
clientsMap[service]?.showCaptcha(activity, captchaKey)
}
}
}

View File

@ -0,0 +1,20 @@
package ru.touchin.recaptcha
import android.app.Activity
import com.google.android.gms.safetynet.SafetyNet
class GoogleCaptchaClient(
onNewTokenReceived: (String) -> Unit,
private val processThrowable: (Throwable) -> Unit
) : CaptchaClient(onNewTokenReceived, processThrowable) {
override fun showCaptcha(activity: Activity, captchaKey: String) {
SafetyNet.getClient(activity)
.verifyWithRecaptcha(captchaKey)
.addOnSuccessListener(activity) { response ->
onServiceTokenResponse(response?.tokenResult)
}
.addOnFailureListener(activity, processThrowable)
}
}

View File

@ -0,0 +1,25 @@
package ru.touchin.recaptcha
import android.app.Activity
import com.huawei.hms.support.api.safetydetect.SafetyDetect
class HuaweiCaptchaClient(
onNewTokenReceived: (String) -> Unit,
private val processThrowable: (Throwable) -> Unit
) : CaptchaClient(onNewTokenReceived, processThrowable) {
override fun showCaptcha(activity: Activity, captchaKey: String) {
val huaweiSafetyDetectClient = SafetyDetect.getClient(activity)
huaweiSafetyDetectClient.initUserDetect()
.addOnSuccessListener {
huaweiSafetyDetectClient.userDetection(captchaKey)
.addOnSuccessListener { response ->
onServiceTokenResponse(response?.responseToken)
}
.addOnFailureListener(activity, processThrowable)
}
.addOnFailureListener(activity, processThrowable)
}
}