From f6fdb0c8d40f434e9074eb6f0dd27098cfd70ddd Mon Sep 17 00:00:00 2001 From: "i.khafizov" Date: Mon, 15 Aug 2022 15:26:07 +0300 Subject: [PATCH 1/3] Add 3DS app-based flow via 3DS SDK --- build.gradle | 5 +- cardio/build.gradle | 10 +- changelog.md | 8 + .../ru/tinkoff/acquiring/sdk/AcquiringSdk.kt | 13 +- .../acquiring/sdk/models/ThreeDsData.kt | 20 +- .../acquiring/sdk/network/NetworkClient.kt | 72 +----- .../sdk/requests/AcquiringRequest.kt | 43 ++++ .../sdk/requests/FinishAuthorizeRequest.kt | 2 +- .../requests/Submit3DSAuthorizationRequest.kt | 61 +++++ .../sdk/responses/Check3dsVersionResponse.kt | 7 +- .../sdk/responses/FinishAuthorizeResponse.kt | 23 +- .../Submit3DSAuthorizationResponse.kt | 24 ++ gradle.properties | 2 +- gradle/dokka.gradle | 5 +- gradle/publish.gradle | 5 +- gradle/versions.gradle | 16 +- gradle/wrapper/gradle-wrapper.properties | 2 +- migration.md | 13 + readme.md | 12 +- sample/build.gradle | 12 +- .../acquiring/sample/SampleApplication.kt | 2 +- .../acquiring/sample/ui/PayableActivity.kt | 10 +- settings.gradle | 7 +- threeds-sdk/.gitignore | 3 + threeds-sdk/build.gradle | 75 ++++++ threeds-sdk/emv-3ds-sdk-release.aar | Bin 0 -> 158911 bytes threeds-wrapper/.gitignore | 3 + threeds-wrapper/build.gradle | 75 ++++++ threeds-wrapper/threeds-wrapper-release.aar | Bin 0 -> 39834 bytes ui/build.gradle | 26 +- .../tinkoff/acquiring/sdk/TinkoffAcquiring.kt | 49 ++-- .../tinkoff/acquiring/sdk/models/AsdkState.kt | 4 +- .../tinkoff/acquiring/sdk/models/ViewState.kt | 4 +- .../acquiring/sdk/payment/PaymentProcess.kt | 226 +++++++++++------- .../sdk/threeds/ThreeDsCertsConfig.kt | 51 ++++ .../acquiring/sdk/threeds/ThreeDsHelper.kt | 139 +++++++++++ .../sdk/ui/activities/AttachCardActivity.kt | 2 +- .../ui/activities/BaseAcquiringActivity.kt | 12 +- .../activities/NotificationPaymentActivity.kt | 2 +- .../sdk/ui/activities/PaymentActivity.kt | 2 +- .../sdk/ui/activities/ThreeDsActivity.kt | 10 +- .../sdk/ui/activities/TransparentActivity.kt | 40 +++- .../sdk/ui/customview/editcard/EditCard.kt | 4 +- .../acquiring/sdk/utils/CoroutineManager.kt | 10 +- .../sdk/viewmodel/AttachCardViewModel.kt | 9 +- .../sdk/viewmodel/BaseAcquiringViewModel.kt | 11 +- .../viewmodel/NotificationPaymentViewModel.kt | 10 +- .../sdk/viewmodel/PaymentViewModel.kt | 69 +++--- .../acquiring/sdk/viewmodel/QrViewModel.kt | 9 +- .../sdk/viewmodel/SavedCardsViewModel.kt | 65 ++--- .../sdk/viewmodel/ThreeDsViewModel.kt | 139 +++++++++-- .../sdk/viewmodel/ViewModelProviderFactory.kt | 19 +- 52 files changed, 1092 insertions(+), 350 deletions(-) create mode 100644 core/src/main/java/ru/tinkoff/acquiring/sdk/requests/Submit3DSAuthorizationRequest.kt create mode 100644 core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Submit3DSAuthorizationResponse.kt create mode 100644 migration.md create mode 100644 threeds-sdk/.gitignore create mode 100644 threeds-sdk/build.gradle create mode 100644 threeds-sdk/emv-3ds-sdk-release.aar create mode 100644 threeds-wrapper/.gitignore create mode 100644 threeds-wrapper/build.gradle create mode 100644 threeds-wrapper/threeds-wrapper-release.aar create mode 100644 ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsCertsConfig.kt create mode 100644 ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt diff --git a/build.gradle b/build.gradle index 73cf87c6..8a7176f2 100644 --- a/build.gradle +++ b/build.gradle @@ -21,9 +21,8 @@ allprojects { repositories { jcenter() google() - maven { - url "https://maven.google.com" - } + mavenCentral() + maven { url "https://maven.google.com" } tasks.withType(Javadoc) { options.addStringOption('encoding', 'UTF-8') } diff --git a/cardio/build.gradle b/cardio/build.gradle index b5e9865b..74ab112a 100644 --- a/cardio/build.gradle +++ b/cardio/build.gradle @@ -2,16 +2,16 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply from: '../gradle/dokka.gradle' -apply from: '../gradle/versions.gradle' +apply from: rootProject.file('gradle/versions.gradle') apply from: '../gradle/publish.gradle' android { - compileSdkVersion compileSdk - buildToolsVersion buildTools + compileSdkVersion rootProject.compileSdk + buildToolsVersion rootProject.buildTools defaultConfig { - minSdkVersion minSdk - targetSdkVersion targetSdk + minSdkVersion rootProject.minSdk + targetSdkVersion rootProject.targetSdk versionCode Integer.parseInt(VERSION_CODE) versionName VERSION_NAME } diff --git a/changelog.md b/changelog.md index 981706a5..b1cf176c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +## 2.6.0 + +#### Fixed +#### Changes +`TinkoffAcquiring` constructor should accept `applicationContext` parameter now +#### Additions +Added app-based 3DS flow for payments ([migration](/migration.md)) + ## 2.5.11 #### Fixed diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/AcquiringSdk.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/AcquiringSdk.kt index f16b67bc..c9cae919 100644 --- a/core/src/main/java/ru/tinkoff/acquiring/sdk/AcquiringSdk.kt +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/AcquiringSdk.kt @@ -222,9 +222,18 @@ class AcquiringSdk( } } + fun submit3DSAuthorization(threeDSServerTransID: String, transStatus: String, request: (Submit3DSAuthorizationRequest.() -> Unit)? = null): Submit3DSAuthorizationRequest { + return Submit3DSAuthorizationRequest().apply { + terminalKey = this@AcquiringSdk.terminalKey + this.threeDSServerTransID = threeDSServerTransID + this.transStatus = transStatus + request?.invoke(this) + } + } + class TinkoffPayStatusCache( - val status: TinkoffPayStatusResponse, - val time: Long) { + val status: TinkoffPayStatusResponse, + val time: Long) { fun isExpired() = System.currentTimeMillis() - time > CACHE_EXPIRE_TIME_MS diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/models/ThreeDsData.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/models/ThreeDsData.kt index 4b33d489..a3dff951 100644 --- a/core/src/main/java/ru/tinkoff/acquiring/sdk/models/ThreeDsData.kt +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/models/ThreeDsData.kt @@ -36,25 +36,36 @@ class ThreeDsData( ) : Serializable { /** - * Уникальный номер заказа в системе платежного шлюза, для проверки 3DS + * Уникальный номер заказа в системе платежного шлюза, для проверки 3DS (3DS 1.x) */ var md: String? = null /** - * Параметр из ответа на запрос оплаты, для проверки 3DS + * Параметр из ответа на запрос оплаты, для проверки 3DS (3DS 1.x) */ var paReq: String? = null /** - * Идентификатор транзакции из ответа метода + * Идентификатор транзакции из ответа метода (3DS 2.x) */ var tdsServerTransId: String? = null /** - * Идентификатор транзакции, присвоенный ACS + * Идентификатор транзакции, присвоенный ACS (3DS 2.x) */ var acsTransId: String? = null + /** + * Идентификатор ACS (3DS 2.1, app-based) + */ + var acsRefNumber: String? = null + + /** + * JWT-токен, сфоримарованный ACS для проеведения транзацкии; содержит ACS URL, ACS ephemeral + * public key и SDK ephemeral public key (3DS 2.1, app-based) + */ + var acsSignedContent: String? = null + /** * Версия протокола 3DS */ @@ -90,6 +101,7 @@ class ThreeDsData( "paReq = $paReq, " + "tdsServerTransId = $tdsServerTransId, " + "acsTransId = $acsTransId, " + + "acsRefNumber = $acsRefNumber, " + "isThreeDsNeed = $isThreeDsNeed, " + "version = $version;" } diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/network/NetworkClient.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/network/NetworkClient.kt index d3d4dc49..3ae946f9 100644 --- a/core/src/main/java/ru/tinkoff/acquiring/sdk/network/NetworkClient.kt +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/network/NetworkClient.kt @@ -34,7 +34,6 @@ import ru.tinkoff.acquiring.sdk.requests.AcquiringRequest import ru.tinkoff.acquiring.sdk.requests.FinishAuthorizeRequest import ru.tinkoff.acquiring.sdk.responses.AcquiringResponse import ru.tinkoff.acquiring.sdk.responses.GetCardListResponse -import ru.tinkoff.acquiring.sdk.utils.CryptoUtils.sha256 import ru.tinkoff.acquiring.sdk.utils.serialization.* import java.io.* import java.lang.reflect.Modifier @@ -145,7 +144,7 @@ internal class NetworkClient { AcquiringApi.API_REQUEST_METHOD_GET -> false else -> true } - setRequestProperty("Content-type", if (AcquiringApi.useV1Api(request.apiMethod)) FORM_URL_ENCODED else JSON) + setRequestProperty("Content-type", request.contentType) if (request is FinishAuthorizeRequest && request.is3DsVersionV2()) { setRequestProperty("User-Agent", System.getProperty("http.agent")) @@ -157,7 +156,7 @@ internal class NetworkClient { } private fun prepareBody(request: AcquiringRequest, onReady: (ByteArray) -> Unit) { - val requestBody = formatRequestBody(request) + val requestBody = request.getRequestBody() AcquiringSdk.log("=== Parameters: $requestBody") onReady(requestBody.toByteArray()) @@ -186,66 +185,6 @@ internal class NetworkClient { return URL(builder.toString()) } - private fun formatRequestBody(request: AcquiringRequest): String { - val params = if (request.password != null) - enrichWithToken(request) - else - request.asMap() - - if (params.isEmpty()) { - return "" - } - - return if (AcquiringApi.useV1Api(request.apiMethod)) { - encodeRequestBody(params) - } else { - jsonRequestBody(params) - } - } - - private fun jsonRequestBody(params: Map): String { - return gson.toJson(params) - } - - private fun enrichWithToken(request: AcquiringRequest): MutableMap { - val token = StringBuilder() - - val params = request.asMap() - val sortedKeys = params.keys.sorted() - val ignore = request.tokenIgnoreFields - - sortedKeys.forEach { - if (ignore.contains(it)) - return@forEach - - token.append(params[it]) - } - - params[AcquiringRequest.TOKEN] = token.toString().sha256() - params.remove(AcquiringRequest.PASSWORD) - - return params - } - - private fun encodeRequestBody(params: Map): String { - val builder = StringBuilder() - for ((key, value1) in params) { - try { - val value = URLEncoder.encode(value1.toString(), "UTF-8") - builder.append(key) - builder.append('=') - builder.append(value) - builder.append('&') - } catch (e: UnsupportedEncodingException) { - AcquiringSdk.log(e) - } - } - - builder.setLength(builder.length - 1) - - return builder.toString() - } - @Throws(IOException::class) private fun read(reader: InputStreamReader): String { val buffer = CharArray(STREAM_BUFFER_SIZE) @@ -271,8 +210,10 @@ internal class NetworkClient { } } - private fun createGson(): Gson { - return GsonBuilder() + companion object { + + fun createGson(): Gson { + return GsonBuilder() .excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC) .setExclusionStrategies(SerializableExclusionStrategy()) .registerTypeAdapter(CardStatus::class.java, CardStatusSerializer()) @@ -281,5 +222,6 @@ internal class NetworkClient { .registerTypeAdapter(Tax::class.java, TaxSerializer()) .registerTypeAdapter(Taxation::class.java, TaxationSerializer()) .create() + } } } \ No newline at end of file diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/AcquiringRequest.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/AcquiringRequest.kt index 88b86931..c3e9b8fc 100644 --- a/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/AcquiringRequest.kt +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/AcquiringRequest.kt @@ -16,10 +16,14 @@ package ru.tinkoff.acquiring.sdk.requests +import com.google.gson.Gson +import ru.tinkoff.acquiring.sdk.AcquiringSdk import ru.tinkoff.acquiring.sdk.network.AcquiringApi import ru.tinkoff.acquiring.sdk.network.NetworkClient import ru.tinkoff.acquiring.sdk.responses.AcquiringResponse import ru.tinkoff.acquiring.sdk.utils.Request +import java.io.UnsupportedEncodingException +import java.net.URLEncoder import java.security.PublicKey /** @@ -29,7 +33,10 @@ import java.security.PublicKey */ abstract class AcquiringRequest(internal val apiMethod: String) : Request { + protected val gson: Gson = NetworkClient.createGson() + open val httpRequestMethod: String = AcquiringApi.API_REQUEST_METHOD_POST + open val contentType: String = AcquiringApi.JSON internal lateinit var terminalKey: String internal lateinit var publicKey: PublicKey @@ -88,6 +95,39 @@ abstract class AcquiringRequest(internal val apiMethod: S } } + open fun getRequestBody(): String { + val params = asMap() + if (params.isEmpty()) return "" + + return when (contentType) { + AcquiringApi.FORM_URL_ENCODED -> encodeRequestBody(params) + else -> jsonRequestBody(params) + } + } + + protected open fun jsonRequestBody(params: Map): String { + return gson.toJson(params) + } + + protected fun encodeRequestBody(params: Map): String { + val builder = StringBuilder() + for ((key, value1) in params) { + try { + val value = URLEncoder.encode(value1.toString(), "UTF-8") + builder.append(key) + builder.append('=') + builder.append(value) + builder.append('&') + } catch (e: UnsupportedEncodingException) { + AcquiringSdk.log(e) + } + } + + builder.setLength(builder.length - 1) + + return builder.toString() + } + internal companion object { const val TERMINAL_KEY = "TerminalKey" @@ -125,5 +165,8 @@ abstract class AcquiringRequest(internal val apiMethod: S const val IP = "IP" const val CONNECTION_TYPE = "connection_type" const val SDK_VERSION = "sdk_version" + const val THREE_DS_SERVER_TRANS_ID = "threeDSServerTransID" + const val TRANS_STATUS = "transStatus" + const val CRES = "cres" } } diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/FinishAuthorizeRequest.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/FinishAuthorizeRequest.kt index 7de8f566..095b72d7 100644 --- a/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/FinishAuthorizeRequest.kt +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/FinishAuthorizeRequest.kt @@ -152,7 +152,7 @@ class FinishAuthorizeRequest : AcquiringRequest(FINISH_ } private fun MutableMap.putDataIfNonNull(data: Map?) { - if (data != null) { + if (!data.isNullOrEmpty()) { this[DATA] = data.toMutableMap() } } diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/Submit3DSAuthorizationRequest.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/Submit3DSAuthorizationRequest.kt new file mode 100644 index 00000000..10f0fdd1 --- /dev/null +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/requests/Submit3DSAuthorizationRequest.kt @@ -0,0 +1,61 @@ +/* + * Copyright © 2020 Tinkoff Bank + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ru.tinkoff.acquiring.sdk.requests + +import ru.tinkoff.acquiring.sdk.network.AcquiringApi +import ru.tinkoff.acquiring.sdk.responses.Submit3DSAuthorizationResponse +import ru.tinkoff.acquiring.sdk.utils.Base64 + +/** + * Подтверждает прохождение app-based 3DS версии 2.1 + */ +class Submit3DSAuthorizationRequest : AcquiringRequest( + AcquiringApi.SUBMIT_3DS_AUTHORIZATION_V2) { + + override val contentType: String = AcquiringApi.FORM_URL_ENCODED + + /** + * Уникальный идентификатор транзакции, генерируемый 3DS-Server + */ + var threeDSServerTransID: String? = null + + /** + * Статус транзакции + */ + var transStatus: String? = null + + override fun asMap(): MutableMap { + val cres = gson.toJson(buildMap { + this[THREE_DS_SERVER_TRANS_ID] = threeDSServerTransID!! + this[TRANS_STATUS] = transStatus!! + }) + val encodedCres = Base64.encodeToString(cres.toByteArray(), Base64.NO_WRAP) + return mutableMapOf(CRES to encodedCres) + } + + override fun validate() { + threeDSServerTransID.validate(THREE_DS_SERVER_TRANS_ID) + transStatus.validate(TRANS_STATUS) + } + + /** + * Синхронный вызов метода API + */ + override fun execute(onSuccess: (Submit3DSAuthorizationResponse) -> Unit, onFailure: (Exception) -> Unit) { + super.performRequest(this, Submit3DSAuthorizationResponse::class.java, onSuccess, onFailure) + } +} diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Check3dsVersionResponse.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Check3dsVersionResponse.kt index 7aa5405e..054e0672 100644 --- a/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Check3dsVersionResponse.kt +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Check3dsVersionResponse.kt @@ -26,6 +26,8 @@ import com.google.gson.annotations.SerializedName * обязательный параметр для 3DS второй версии * @param threeDsMethodUrl дополнительный параметр для 3DS второй версии, который позволяет * пройти этап по сбору данных браузера ACS-ом + * @param paymentSystem платежная система, через которую будет проводится оплата, участвует + * в прохождении 3DS по app-based flow * * @author Mariya Chernyadieva */ @@ -37,6 +39,9 @@ class Check3dsVersionResponse( val serverTransId: String? = null, @SerializedName("ThreeDSMethodURL") - val threeDsMethodUrl: String? = null + val threeDsMethodUrl: String? = null, + + @SerializedName("PaymentSystem") + val paymentSystem: String? = null ) : AcquiringResponse() \ No newline at end of file diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/FinishAuthorizeResponse.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/FinishAuthorizeResponse.kt index eb0ff9c2..1121e6d4 100644 --- a/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/FinishAuthorizeResponse.kt +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/FinishAuthorizeResponse.kt @@ -28,10 +28,13 @@ import ru.tinkoff.acquiring.sdk.models.enums.ResponseStatus * @param orderId номер заказа в системе продавца * @param amount сумма списания в копейках * @param acsUrl адрес сервера управления доступом, для проверки 3DS - * @param md уникальный номер заказа в системе платежного шлюза, для проверки 3DS - * @param paReq параметр из ответа на запрос оплаты, для проверки 3DS - * @param tdsServerTransId идентификатор транзакции 3DS - * @param acsTransId идентификатор транзакции 3DS, присвоенный ACS + * @param md уникальный номер заказа в системе платежного шлюза, для проверки 3DS (3DS 1.x) + * @param paReq параметр из ответа на запрос оплаты, для проверки 3DS (3DS 1.x) + * @param tdsServerTransId идентификатор транзакции 3DS (3DS 2.x) + * @param acsTransId идентификатор транзакции 3DS, присвоенный ACS (3DS 2.x) + * @param acsRefNumber идентификатор ACS (3DS 2.1, app-based) + * @param acsSignedContent JWT-токен, сфоримарованный ACS для проеведения транзацкии; содержит ACS URL, ACS ephemeral + * public key и SDK ephemeral public key (3DS 2.1, app-based) * @param status статус транзакции * * @author Mariya Chernyadieva @@ -64,6 +67,12 @@ class FinishAuthorizeResponse( @SerializedName("AcsTransId") val acsTransId: String? = null, + @SerializedName("AcsReferenceNumber") + val acsRefNumber: String? = null, + + @SerializedName("AcsSignedContent") + val acsSignedContent: String? = null, + @SerializedName("Status") val status: ResponseStatus? = null @@ -72,7 +81,7 @@ class FinishAuthorizeResponse( @Transient private lateinit var threeDsData: ThreeDsData - fun getThreeDsData(): ThreeDsData { + fun getThreeDsData(threeDsVersion: String?): ThreeDsData { threeDsData = when (status) { ResponseStatus.CONFIRMED, ResponseStatus.AUTHORIZED -> ThreeDsData.EMPTY_THREE_DS_DATA ResponseStatus.THREE_DS_CHECKING -> { @@ -80,11 +89,15 @@ class FinishAuthorizeResponse( ThreeDsData(paymentId, acsUrl).apply { md = this@FinishAuthorizeResponse.md paReq = this@FinishAuthorizeResponse.paReq + version = threeDsVersion } } else if (tdsServerTransId != null && acsTransId != null) { ThreeDsData(paymentId, acsUrl).apply { tdsServerTransId = this@FinishAuthorizeResponse.tdsServerTransId acsTransId = this@FinishAuthorizeResponse.acsTransId + acsRefNumber = this@FinishAuthorizeResponse.acsRefNumber + acsSignedContent = this@FinishAuthorizeResponse.acsSignedContent + version = threeDsVersion } } else throw AcquiringSdkException(IllegalStateException("Invalid 3DS params")) } diff --git a/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Submit3DSAuthorizationResponse.kt b/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Submit3DSAuthorizationResponse.kt new file mode 100644 index 00000000..e3e82b21 --- /dev/null +++ b/core/src/main/java/ru/tinkoff/acquiring/sdk/responses/Submit3DSAuthorizationResponse.kt @@ -0,0 +1,24 @@ +/* + * Copyright © 2020 Tinkoff Bank + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ru.tinkoff.acquiring.sdk.responses + +/** + * Ответ на запрос Submit3DSAuthorization + * + * @author Mariya Chernyadieva + */ +class Submit3DSAuthorizationResponse() : AcquiringResponse() diff --git a/gradle.properties b/gradle.properties index c0a2726b..fc404d43 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=2.5.11 +VERSION_NAME=2.6.0 VERSION_CODE=15 GROUP=ru.tinkoff.acquiring diff --git a/gradle/dokka.gradle b/gradle/dokka.gradle index ed545a9f..7d134940 100644 --- a/gradle/dokka.gradle +++ b/gradle/dokka.gradle @@ -1,6 +1,5 @@ apply plugin: 'org.jetbrains.dokka' -dokka { - outputFormat = 'html' - outputDirectory = "$buildDir/dokka" +tasks.dokkaHtml.configure { + outputDirectory = file("$buildDir/dokka") } \ No newline at end of file diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 6f158bdb..61f3b033 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -71,9 +71,8 @@ afterEvaluate { } } - task dokkaJavadoc(type: dokka.getClass()) { - outputFormat = 'javadoc' - outputDirectory = "$buildDir/dokka" + tasks.dokkaJavadoc.configure { + outputDirectory = file("$buildDir/dokka") } task javadocJar(type: Jar, dependsOn: dokkaJavadoc) { diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 18320ae0..64e3f146 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -7,9 +7,9 @@ ext { targetSdk = 31 buildTools = '29.0.2' - kotlinVersion = '1.3.72' - gradlePluginVersion = '3.6.3' - dokkaVersion = '0.9.17' + kotlinVersion = '1.6.10' + gradlePluginVersion = '7.1.2' + dokkaVersion = '1.7.10' appCompatVersion = '1.1.0' preferenceVersion = '1.1.1' @@ -19,4 +19,14 @@ ext { coreNfcVersion = '1.0.2' coroutinesVersion = '1.3.7' googleWalletVersion = '18.0.0' + + constraintLayoutVersion = '1.1.3' + okHttpVersion = '4.9.3' + rxJavaVersion = '2.2.21' + cryptoVersion = '1.1.0-alpha03' + jacksonVersion = '2.13.0' + nimbusVersion = '8.22' + blurryVersion = '4.0.0' + bouncyCastleVersion = '1.65' + rootBeerVersion = '0.1.0' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c43f3f0b..7681c968 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip diff --git a/migration.md b/migration.md new file mode 100644 index 00000000..e7cd3021 --- /dev/null +++ b/migration.md @@ -0,0 +1,13 @@ +2.6.0 + +Добавление подтверждение 3DS по app-based flow при проведении платежа. + +Конструктор `TinkoffAcquiring` теперь первым параметром принимает `applicationContext`. + +Кроме того, для корректной работы SDK, при использовании зависимости от `ui` модуля в +Android-приложениях, также следует добавить дополнительные зависимости: + +```groovy +implementation 'ru.tinkoff.acquiring:threeds-sdk:$latestVersion' +implementation 'ru.tinkoff.acquiring:threeds-wrapper:$latestVersion' +``` \ No newline at end of file diff --git a/readme.md b/readme.md index 5cd56295..2b2c540f 100644 --- a/readme.md +++ b/readme.md @@ -23,9 +23,11 @@ Acquiring SDK позволяет интегрировать [Интернет-Э Для работы Tinkoff Acquiring SDK необходим Android версии 4.4 и выше (API level 19). ### Подключение -Для подключения SDK добавьте в [_build.gradle_][build-config] вашего проекта следующую зависимость: +Для подключения SDK добавьте в [_build.gradle_][build-config] вашего проекта следующие зависимости: ```groovy implementation 'ru.tinkoff.acquiring:ui:$latestVersion' +implementation 'ru.tinkoff.acquiring:threeds-sdk:$latestVersion' +implementation 'ru.tinkoff.acquiring:threeds-wrapper:$latestVersion' ``` Если вы хотите внедрить сканирование с помощью библиотеки Card-IO, то необходимо добавить в [_build.gradle_][build-config] ```groovy @@ -72,7 +74,7 @@ val paymentOptions = } } -val tinkoffAcquiring = TinkoffAcquiring("TERMINAL_KEY", "PUBLIC_KEY") // создание объекта для взаимодействия с SDK и передача данных продавца +val tinkoffAcquiring = TinkoffAcquiring(applicationContext, "TERMINAL_KEY", "PUBLIC_KEY") // создание объекта для взаимодействия с SDK и передача данных продавца tinkoffAcquiring.openPaymentScreen(this@MainActivity, paymentOptions, PAYMENT_REQUEST_CODE) ``` Результат вызова метода вернется в **onActivityResult**: @@ -97,7 +99,7 @@ val paymentOptions = } } -val tinkoffAcquiring = TinkoffAcquiring("TERMINAL_KEY", "PUBLIC_KEY") +val tinkoffAcquiring = TinkoffAcquiring(applicationContext, "TERMINAL_KEY", "PUBLIC_KEY") tinkoffAcquiring.openPaymentScreen(this@MainActivity, paymentOptions, PAYMENT_REQUEST_CODE) ``` [1] _Рекуррентный платеж_ может производиться для дальнейшего списания средств с сохраненной карты, без ввода ее реквизитов. Эта возможность, например, может использоваться для осуществления платежей по подписке. @@ -122,7 +124,7 @@ val attachCardOptions = } } -val tinkoffAcquiring = TinkoffAcquiring("TERMINAL_KEY", "PUBLIC_KEY") +val tinkoffAcquiring = TinkoffAcquiring(applicationContext, "TERMINAL_KEY", "PUBLIC_KEY") tinkoffAcquiring.openAttachCardScreen(this@MainActivity, attachCardOptions, ATTACH_CARD_REQUEST_CODE) ``` Результат вызова метода вернется в **onActivityResult**: @@ -180,7 +182,7 @@ fun handleGooglePayResult(resultCode: Int, data: Intent?) { val token = GooglePayHelper.getGooglePayToken(data) // получаем токен Google Pay из Intent - val tinkoffAcquiring = TinkoffAcquiring("TERMINAL_KEY", "PUBLIC_KEY") + val tinkoffAcquiring = TinkoffAcquiring(applicationContext, "TERMINAL_KEY", "PUBLIC_KEY") tinkoffAcquiring.initPayment(token, paymentOptions) // вызывов метода совершения платежа .subscribe(paymentListener) // подписываемся на события в процессе оплаты .start() // запуск процесса оплаты diff --git a/sample/build.gradle b/sample/build.gradle index e6b3f68d..39e79d63 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,16 +1,16 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' -apply from: '../gradle/versions.gradle' +apply from: rootProject.file('gradle/versions.gradle') android { - compileSdkVersion compileSdk - buildToolsVersion buildTools + compileSdkVersion rootProject.compileSdk + buildToolsVersion rootProject.buildTools defaultConfig { applicationId "ru.tinkoff.acquiring.sample" - minSdkVersion minSdk - targetSdkVersion compileSdk + minSdkVersion rootProject.minSdk + targetSdkVersion rootProject.compileSdk versionCode Integer.parseInt(VERSION_CODE) versionName VERSION_NAME } @@ -39,4 +39,6 @@ dependencies { implementation project(':ui') implementation project(':cardio') + implementation project(':threeds-sdk') + implementation project(':threeds-wrapper') } diff --git a/sample/src/main/java/ru/tinkoff/acquiring/sample/SampleApplication.kt b/sample/src/main/java/ru/tinkoff/acquiring/sample/SampleApplication.kt index 84dc94b2..179b8e84 100644 --- a/sample/src/main/java/ru/tinkoff/acquiring/sample/SampleApplication.kt +++ b/sample/src/main/java/ru/tinkoff/acquiring/sample/SampleApplication.kt @@ -33,7 +33,7 @@ class SampleApplication : Application() { val settings = SettingsSdkManager(this) val params = SessionParams[settings.terminalKey] - tinkoffAcquiring = TinkoffAcquiring(params.terminalKey, params.publicKey) + tinkoffAcquiring = TinkoffAcquiring(this, params.terminalKey, params.publicKey) AcquiringSdk.isDeveloperMode = true AcquiringSdk.isDebug = true } diff --git a/sample/src/main/java/ru/tinkoff/acquiring/sample/ui/PayableActivity.kt b/sample/src/main/java/ru/tinkoff/acquiring/sample/ui/PayableActivity.kt index 88f3576a..0da8497d 100644 --- a/sample/src/main/java/ru/tinkoff/acquiring/sample/ui/PayableActivity.kt +++ b/sample/src/main/java/ru/tinkoff/acquiring/sample/ui/PayableActivity.kt @@ -29,6 +29,7 @@ import ru.tinkoff.acquiring.sample.R import ru.tinkoff.acquiring.sample.SampleApplication import ru.tinkoff.acquiring.sample.utils.SessionParams import ru.tinkoff.acquiring.sample.utils.SettingsSdkManager +import ru.tinkoff.acquiring.sdk.TinkoffAcquiring import ru.tinkoff.acquiring.sdk.TinkoffAcquiring.Companion.RESULT_ERROR import ru.tinkoff.acquiring.sdk.localization.AsdkSource import ru.tinkoff.acquiring.sdk.localization.Language @@ -93,7 +94,7 @@ open class PayableActivity : AppCompatActivity() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { - PAYMENT_REQUEST_CODE, DYNAMIC_QR_PAYMENT_REQUEST_CODE -> handlePaymentResult(resultCode) + PAYMENT_REQUEST_CODE, DYNAMIC_QR_PAYMENT_REQUEST_CODE -> handlePaymentResult(resultCode, data) GOOGLE_PAY_REQUEST_CODE -> handleGooglePayResult(resultCode, data) else -> super.onActivityResult(requestCode, resultCode, data) } @@ -237,11 +238,14 @@ open class PayableActivity : AppCompatActivity() { } } - private fun handlePaymentResult(resultCode: Int) { + private fun handlePaymentResult(resultCode: Int, data: Intent?) { when (resultCode) { RESULT_OK -> onSuccessPayment() RESULT_CANCELED -> Toast.makeText(this, R.string.payment_cancelled, Toast.LENGTH_SHORT).show() - RESULT_ERROR -> Toast.makeText(this, R.string.payment_failed, Toast.LENGTH_SHORT).show() + RESULT_ERROR -> { + Toast.makeText(this, R.string.payment_failed, Toast.LENGTH_SHORT).show() + (data?.getSerializableExtra(TinkoffAcquiring.EXTRA_ERROR) as? Throwable)?.printStackTrace() + } } } diff --git a/settings.gradle b/settings.gradle index 274881f9..4d82b5db 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,6 @@ -include ':sample', ':ui', ':core', ':cardio' +include ':sample', + ':core', + ':cardio', + ':ui', + ':threeds-sdk', + ':threeds-wrapper' diff --git a/threeds-sdk/.gitignore b/threeds-sdk/.gitignore new file mode 100644 index 00000000..4e8b84b6 --- /dev/null +++ b/threeds-sdk/.gitignore @@ -0,0 +1,3 @@ +/build + +*.asc \ No newline at end of file diff --git a/threeds-sdk/build.gradle b/threeds-sdk/build.gradle new file mode 100644 index 00000000..a623efbb --- /dev/null +++ b/threeds-sdk/build.gradle @@ -0,0 +1,75 @@ +apply plugin: 'maven-publish' +apply plugin: 'signing' +apply from: rootProject.file('gradle/versions.gradle') + +def getReleaseRepositoryUrl() { + return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL + : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +def getSnapshotRepositoryUrl() { + return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL + : "https://oss.sonatype.org/content/repositories/snapshots/" +} + +def getRepositoryUsername() { + return hasProperty('ossrhUsername') ? ossrhUsername : '' +} + +def getRepositoryPassword() { + return hasProperty('ossrhPassword') ? ossrhPassword : '' +} + +afterEvaluate { + publishing { + publications { + release(MavenPublication) { + groupId GROUP + version versionName + artifactId "threeds-sdk" + artifact("emv-3ds-sdk-release.aar") + pom { + name = "threeds-sdk" + packaging = "aar" + description = POM_DESCRIPTION + url = POM_URL + scm { + url = POM_SCM_URL + connection = POM_SCM_CONNECTION + developerConnection = POM_SCM_DEV_CONNECTION + } + licenses { + license { + name = POM_LICENCE_NAME + url = POM_LICENCE_URL + distribution = POM_LICENCE_DIST + } + } + developers { + developer { + id = POM_DEVELOPER_ID + name = POM_DEVELOPER_NAME + } + } + } + } + } + repositories { + maven { + url isRelease ? getReleaseRepositoryUrl() : getSnapshotRepositoryUrl() + credentials { + username = getRepositoryUsername() + password = getRepositoryPassword() + } + } + } + } + + signing { + required { isRelease } + sign publishing.publications.release + } +} + +configurations.maybeCreate("default") +artifacts.add("default", file('emv-3ds-sdk-release.aar')) \ No newline at end of file diff --git a/threeds-sdk/emv-3ds-sdk-release.aar b/threeds-sdk/emv-3ds-sdk-release.aar new file mode 100644 index 0000000000000000000000000000000000000000..f171bb7e6d66ab71a94cbb63b13c462634d9ad98 GIT binary patch literal 158911 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 literal 0 HcmV?d00001 diff --git a/threeds-wrapper/.gitignore b/threeds-wrapper/.gitignore new file mode 100644 index 00000000..4e8b84b6 --- /dev/null +++ b/threeds-wrapper/.gitignore @@ -0,0 +1,3 @@ +/build + +*.asc \ No newline at end of file diff --git a/threeds-wrapper/build.gradle b/threeds-wrapper/build.gradle new file mode 100644 index 00000000..6ca604e5 --- /dev/null +++ b/threeds-wrapper/build.gradle @@ -0,0 +1,75 @@ +apply plugin: 'maven-publish' +apply plugin: 'signing' +apply from: rootProject.file('gradle/versions.gradle') + +def getReleaseRepositoryUrl() { + return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL + : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +def getSnapshotRepositoryUrl() { + return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL + : "https://oss.sonatype.org/content/repositories/snapshots/" +} + +def getRepositoryUsername() { + return hasProperty('ossrhUsername') ? ossrhUsername : '' +} + +def getRepositoryPassword() { + return hasProperty('ossrhPassword') ? ossrhPassword : '' +} + +afterEvaluate { + publishing { + publications { + release(MavenPublication) { + groupId GROUP + version versionName + artifactId "threeds-wrapper" + artifact("threeds-wrapper-release.aar") + pom { + name = "threeds-wrapper" + packaging = "aar" + description = POM_DESCRIPTION + url = POM_URL + scm { + url = POM_SCM_URL + connection = POM_SCM_CONNECTION + developerConnection = POM_SCM_DEV_CONNECTION + } + licenses { + license { + name = POM_LICENCE_NAME + url = POM_LICENCE_URL + distribution = POM_LICENCE_DIST + } + } + developers { + developer { + id = POM_DEVELOPER_ID + name = POM_DEVELOPER_NAME + } + } + } + } + } + repositories { + maven { + url isRelease ? getReleaseRepositoryUrl() : getSnapshotRepositoryUrl() + credentials { + username = getRepositoryUsername() + password = getRepositoryPassword() + } + } + } + } + + signing { + required { isRelease } + sign publishing.publications.release + } +} + +configurations.maybeCreate("default") +artifacts.add("default", file('threeds-wrapper-release.aar')) \ No newline at end of file diff --git a/threeds-wrapper/threeds-wrapper-release.aar b/threeds-wrapper/threeds-wrapper-release.aar new file mode 100644 index 0000000000000000000000000000000000000000..4efe5d6699224bf4102cafcf431e3a715c0fce87 GIT binary patch literal 39834 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 literal 0 HcmV?d00001 diff --git a/ui/build.gradle b/ui/build.gradle index ce1d8e7e..df72650a 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -2,18 +2,19 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply from: '../gradle/dokka.gradle' -apply from: '../gradle/versions.gradle' +apply from: rootProject.file('gradle/versions.gradle') apply from: '../gradle/publish.gradle' android { - compileSdkVersion compileSdk - buildToolsVersion buildTools + compileSdkVersion rootProject.compileSdk + buildToolsVersion rootProject.buildTools defaultConfig { - minSdkVersion minSdk - targetSdkVersion targetSdk + minSdkVersion rootProject.minSdk + targetSdkVersion rootProject.targetSdk versionCode Integer.parseInt(VERSION_CODE) versionName VERSION_NAME + buildConfigField("String", "ASDK_VERSION_NAME", "\"$VERSION_NAME\"") } buildTypes { @@ -39,6 +40,21 @@ dependencies { api("com.google.android.gms:play-services-wallet:$googleWalletVersion") api project(':core') + implementation project(':threeds-sdk') + implementation project(':threeds-wrapper') + implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion" + implementation "com.squareup.okhttp3:okhttp:${okHttpVersion}" + implementation "androidx.security:security-crypto:${cryptoVersion}" + + // threeds dependencies + implementation "androidx.appcompat:appcompat:${appCompatVersion}" + implementation "androidx.constraintlayout:constraintlayout:${constraintLayoutVersion}" + implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" + implementation "com.nimbusds:nimbus-jose-jwt:${nimbusVersion}" + implementation "org.bouncycastle:bcprov-jdk15on:${bouncyCastleVersion}" + implementation "jp.wasabeef:blurry:${blurryVersion}" + implementation "com.scottyab:rootbeer-lib:${rootBeerVersion}" + testImplementation 'junit:junit:4.13' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/TinkoffAcquiring.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/TinkoffAcquiring.kt index 677e98e6..69b04f72 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/TinkoffAcquiring.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/TinkoffAcquiring.kt @@ -59,8 +59,9 @@ import ru.tinkoff.acquiring.sdk.ui.activities.ThreeDsActivity * @author Mariya Chernyadieva */ class TinkoffAcquiring( - private val terminalKey: String, - private val publicKey: String + private val applicationContext: Context, + private val terminalKey: String, + private val publicKey: String ) { val sdk = AcquiringSdk(terminalKey, publicKey) @@ -75,7 +76,7 @@ class TinkoffAcquiring( */ fun initPayment(attachedCard: AttachedCard, paymentOptions: PaymentOptions): PaymentProcess { paymentOptions.setTerminalParams(terminalKey, publicKey) - return PaymentProcess(sdk).createPaymentProcess(attachedCard, paymentOptions) + return PaymentProcess(sdk, applicationContext).createPaymentProcess(attachedCard, paymentOptions) } /** @@ -89,7 +90,7 @@ class TinkoffAcquiring( */ fun initPayment(cardData: CardData, paymentOptions: PaymentOptions): PaymentProcess { paymentOptions.setTerminalParams(terminalKey, publicKey) - return PaymentProcess(sdk).createPaymentProcess(cardData, paymentOptions) + return PaymentProcess(sdk, applicationContext).createPaymentProcess(cardData, paymentOptions) } /** @@ -103,7 +104,7 @@ class TinkoffAcquiring( */ fun initPayment(googlePayToken: String, paymentOptions: PaymentOptions): PaymentProcess { paymentOptions.setTerminalParams(terminalKey, publicKey) - return PaymentProcess(sdk).createPaymentProcess(GooglePay(googlePayToken), paymentOptions) + return PaymentProcess(sdk, applicationContext).createPaymentProcess(GooglePay(googlePayToken), paymentOptions) } /** @@ -117,7 +118,7 @@ class TinkoffAcquiring( * @return объект для проведения оплаты */ fun finishPayment(paymentId: Long, paymentSource: PaymentSource): PaymentProcess { - return PaymentProcess(sdk).createFinishProcess(paymentId, paymentSource) + return PaymentProcess(sdk, applicationContext).createFinishProcess(paymentId, paymentSource) } /** @@ -189,15 +190,15 @@ class TinkoffAcquiring( * полученный после проведения инициации платежа */ fun payWithSbp(paymentId: Long): PaymentProcess { - return PaymentProcess(sdk).createInitializedSbpPaymentProcess(paymentId) + return PaymentProcess(sdk, applicationContext).createInitializedSbpPaymentProcess(paymentId) } /** * Проверка статуса возможности оплата с помощью Tinkoff Pay */ fun checkTinkoffPayStatus( - onSuccess: (TinkoffPayStatusResponse) -> Unit, - onFailure: ((Throwable) -> Unit)? = null + onSuccess: (TinkoffPayStatusResponse) -> Unit, + onFailure: ((Throwable) -> Unit)? = null ) { CoroutineScope(Dispatchers.IO).launch { sdk.tinkoffPayStatus().execute({ @@ -217,7 +218,7 @@ class TinkoffAcquiring( * @param version версия Tinkoff Pay */ fun payWithTinkoffPay(options: PaymentOptions, version: String): PaymentProcess { - return PaymentProcess(sdk).createTinkoffPayPaymentProcess(options, version) + return PaymentProcess(sdk, applicationContext).createTinkoffPayPaymentProcess(options, version) } /** @@ -338,7 +339,7 @@ class TinkoffAcquiring( * @param requestCode код для получения результата, по завершению работы экрана Acquiring SDK */ @Deprecated("Replaced with expanded method", - ReplaceWith("openStaticQrScreen(activity, FeaturesOptions().apply { localizationSource = localization }, requestCode)")) + ReplaceWith("openStaticQrScreen(activity, FeaturesOptions().apply { localizationSource = localization }, requestCode)")) fun openStaticQrScreen(activity: Activity, localization: LocalizationSource, requestCode: Int) { openStaticQrScreen(activity, FeaturesOptions().apply { localizationSource = localization }, requestCode) } @@ -361,11 +362,11 @@ class TinkoffAcquiring( notificationId: Int? = null): PendingIntent { options.setTerminalParams(terminalKey, publicKey) return NotificationPaymentActivity.createPendingIntent(context, - options, - null, - NotificationPaymentActivity.PaymentMethod.GPAY, - notificationId, - googlePayParams) + options, + null, + NotificationPaymentActivity.PaymentMethod.GPAY, + notificationId, + googlePayParams) } /** @@ -382,10 +383,10 @@ class TinkoffAcquiring( fun createTinkoffPaymentPendingIntent(context: Context, options: PaymentOptions, notificationId: Int? = null): PendingIntent { options.setTerminalParams(terminalKey, publicKey) return NotificationPaymentActivity.createPendingIntent(context, - options, - null, - NotificationPaymentActivity.PaymentMethod.TINKOFF, - notificationId) + options, + null, + NotificationPaymentActivity.PaymentMethod.TINKOFF, + notificationId) } /** @@ -432,10 +433,10 @@ class TinkoffAcquiring( notificationId: Int? = null): PendingIntent { options.setTerminalParams(terminalKey, publicKey) return NotificationPaymentActivity.createPendingIntent(activity, - options, - requestCode, - NotificationPaymentActivity.PaymentMethod.TINKOFF, - notificationId) + options, + requestCode, + NotificationPaymentActivity.PaymentMethod.TINKOFF, + notificationId) } private fun prepareIntent(context: Context, options: BaseAcquiringOptions, cls: Class<*>): Intent { diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/AsdkState.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/AsdkState.kt index 5701dc6c..7d0cbcc6 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/AsdkState.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/AsdkState.kt @@ -16,8 +16,10 @@ package ru.tinkoff.acquiring.sdk.models +import com.emvco3ds.sdk.spec.Transaction import ru.tinkoff.acquiring.sdk.AcquiringSdk import ru.tinkoff.acquiring.sdk.responses.Check3dsVersionResponse +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper import java.io.Serializable /** @@ -54,7 +56,7 @@ object FpsState : AsdkState() * Состояние проверки 3DS. На экране пользователю будет предложено пройти подтверждение платежа * по технологии 3D-Secure */ -class ThreeDsState(val data: ThreeDsData) : AsdkState() +class ThreeDsState(val data: ThreeDsData, val threeDSWrapper: ThreeDSWrapper?, val transaction: Transaction?) : AsdkState() /** * Состояние, когда необходимо собрать информацию об устройстве для прохождения 3DS diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/ViewState.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/ViewState.kt index 25d39084..54c941e4 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/ViewState.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/models/ViewState.kt @@ -16,7 +16,9 @@ package ru.tinkoff.acquiring.sdk.models +import com.emvco3ds.sdk.spec.Transaction import ru.tinkoff.acquiring.sdk.responses.Check3dsVersionResponse +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper /** * @author Mariya Chernyadieva @@ -34,7 +36,7 @@ internal object FpsScreenState: Screen() internal class BrowseFpsBankScreenState(val paymentId: Long, val deepLink: String, val banks: Set?) : Screen() internal class OpenTinkoffPayBankScreenState(val paymentId: Long, val deepLink: String) : Screen() internal class RejectedCardScreenState(val cardId: String, val rejectedPaymentId: Long) : Screen() -internal class ThreeDsScreenState(val data: ThreeDsData) : Screen() +internal class ThreeDsScreenState(val data: ThreeDsData, val wrapper: ThreeDSWrapper?, val transaction: Transaction?) : Screen() internal class ThreeDsDataCollectScreenState(val response: Check3dsVersionResponse) : Screen() internal class LoopConfirmationScreenState(val requestKey: String) : Screen() diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/payment/PaymentProcess.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/payment/PaymentProcess.kt index d3c78fb7..fc904cfe 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/payment/PaymentProcess.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/payment/PaymentProcess.kt @@ -16,15 +16,17 @@ package ru.tinkoff.acquiring.sdk.payment +import android.content.Context +import android.util.Base64 +import com.emvco3ds.sdk.spec.Transaction import ru.tinkoff.acquiring.sdk.AcquiringSdk import ru.tinkoff.acquiring.sdk.BuildConfig import ru.tinkoff.acquiring.sdk.exceptions.AcquiringApiException +import ru.tinkoff.acquiring.sdk.exceptions.AcquiringSdkException import ru.tinkoff.acquiring.sdk.localization.AsdkLocalization import ru.tinkoff.acquiring.sdk.models.AsdkState -import ru.tinkoff.acquiring.sdk.models.BrowseFpsBankScreenState import ru.tinkoff.acquiring.sdk.models.BrowseFpsBankState import ru.tinkoff.acquiring.sdk.models.CollectDataState -import ru.tinkoff.acquiring.sdk.models.LoadedState import ru.tinkoff.acquiring.sdk.models.NspkRequest import ru.tinkoff.acquiring.sdk.models.OpenTinkoffPayBankState import ru.tinkoff.acquiring.sdk.models.PaymentSource @@ -41,19 +43,24 @@ import ru.tinkoff.acquiring.sdk.network.AcquiringApi.FAIL_MAPI_SESSION_ID import ru.tinkoff.acquiring.sdk.network.AcquiringApi.RECURRING_TYPE_KEY import ru.tinkoff.acquiring.sdk.network.AcquiringApi.RECURRING_TYPE_VALUE import ru.tinkoff.acquiring.sdk.requests.InitRequest -import ru.tinkoff.acquiring.sdk.requests.TinkoffPayLinkRequest import ru.tinkoff.acquiring.sdk.responses.ChargeResponse import ru.tinkoff.acquiring.sdk.responses.Check3dsVersionResponse +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper import ru.tinkoff.acquiring.sdk.utils.CoroutineManager import ru.tinkoff.acquiring.sdk.utils.getIpAddress -import java.util.* +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper.Companion.closeSafe /** * Позволяет создавать и управлять процессом оплаты * * @author Mariya Chernyadieva */ -class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { +class PaymentProcess +internal constructor( + private val sdk: AcquiringSdk, + private val context: Context +) { /** * Возвращает текущее состояние процесса оплаты @@ -78,6 +85,7 @@ class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { private var isChargeWasRejected = false private var rejectedPaymentId: Long? = null + /** * Версия Tinkoff Pay использующаяся в запросе TinkoffPayLink для получения дилплинка * в приложение Tinkoff. Приходит в ответе TinkoffPayStatus. @@ -241,13 +249,13 @@ class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { } coroutine.call(request, - onSuccess = { - when (paymentType) { - CardPaymentType -> finishPayment(it.paymentId!!, paymentSource, email) - SbpPaymentType -> callGetQr(it.paymentId!!) - TinkoffPayPaymentType -> callTinkoffPayLinkRequest(it.paymentId!!, tinkoffPayVersion!!) - } - }) + onSuccess = { + when (paymentType) { + CardPaymentType -> finishPayment(it.paymentId!!, paymentSource, email) + SbpPaymentType -> callGetQr(it.paymentId!!) + TinkoffPayPaymentType -> callTinkoffPayLinkRequest(it.paymentId!!, tinkoffPayVersion!!) + } + }) } private fun callGetQr(paymentId: Long) { @@ -257,18 +265,18 @@ class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { } coroutine.call(request, - onSuccess = { response -> - coroutine.call(NspkRequest(), - onSuccess = { nspk -> - sdkState = BrowseFpsBankState(paymentId, response.data!!, nspk.banks) - sendToListener(PaymentState.BROWSE_SBP_BANK) - }, - onFailure = { - sdkState = BrowseFpsBankState(paymentId, response.data!!, null) - sendToListener(PaymentState.BROWSE_SBP_BANK) - }) + onSuccess = { response -> + coroutine.call(NspkRequest(), + onSuccess = { nspk -> + sdkState = BrowseFpsBankState(paymentId, response.data!!, nspk.banks) + sendToListener(PaymentState.BROWSE_SBP_BANK) + }, + onFailure = { + sdkState = BrowseFpsBankState(paymentId, response.data!!, null) + sendToListener(PaymentState.BROWSE_SBP_BANK) + }) - } + } ) } @@ -279,28 +287,81 @@ class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { } coroutine.call(check3DsRequest, - onSuccess = { response -> - var data: MutableMap? = null - if (response.serverTransId != null) { - if (!response.threeDsMethodUrl.isNullOrEmpty()) { - this.check3dsVersionResponse = response - } - sdkState = CollectDataState(response) - sendToListener(PaymentState.THREE_DS_DATA_COLLECTING) - data = mutableMapOf() - this.collectedDeviceData?.let { data.putAll(it) } + onSuccess = { response -> + val data = mutableMapOf() + if (response.serverTransId != null) { + if (!response.threeDsMethodUrl.isNullOrEmpty()) { + this.check3dsVersionResponse = response } + sdkState = CollectDataState(response) + sendToListener(PaymentState.THREE_DS_DATA_COLLECTING) + this.collectedDeviceData?.let { data.putAll(it) } + } - callFinishAuthorizeRequest(paymentId, paymentSource, email, data, response.version) - }) + coroutine.launchOnBackground { + val threeDsVersion = response.version + var threeDSWrapper: ThreeDSWrapper? = null + var threeDsTransaction: Transaction? = null + + if (ThreeDsHelper.isAppBasedFlow(threeDsVersion)) { + threeDSWrapper = ThreeDsHelper.initWrapper(context) + threeDsTransaction = handleThreeDsAppBased( + threeDSWrapper, threeDsVersion!!, response.paymentSystem!!, data) ?: return@launchOnBackground + } + + callFinishAuthorizeRequest(paymentId, paymentSource, email, data, + threeDsVersion, threeDSWrapper, threeDsTransaction) + } + }) + } + + private fun handleThreeDsAppBased( + threeDSWrapper: ThreeDSWrapper, + threeDsVersion: String, + paymentSystem: String, + data: MutableMap + ): Transaction? { + val dsId = ThreeDsHelper.getDsId(paymentSystem) + if (dsId == null) { + threeDSWrapper.cleanup(context) + handleException(AcquiringSdkException(IllegalArgumentException( + "Directory server ID for payment system \"$paymentSystem\" can't be found"))) + return null + } + var transaction: Transaction? = null + + try { + transaction = threeDSWrapper.createTransaction(dsId, threeDsVersion) + val authParams = transaction.authenticationRequestParameters + + data["sdkAppID"] = authParams.sdkAppID + data["sdkEncData"] = Base64.encodeToString( + authParams.deviceData.toByteArray(Charsets.UTF_8), Base64.NO_WRAP) + data["sdkEphemPubKey"] = Base64.encodeToString( + authParams.sdkEphemeralPublicKey.toByteArray(Charsets.UTF_8), Base64.NO_WRAP) + data["sdkMaxTimeout"] = ThreeDsHelper.maxTimeout.toString() + data["sdkReferenceNumber"] = authParams.sdkReferenceNumber + data["sdkTransID"] = authParams.sdkTransactionID + data["sdkInterface"] = "03" + data["sdkUiType"] = "01,02,03,04,05" + + } catch (e: Throwable) { + transaction?.closeSafe() + threeDSWrapper.cleanup(context) + handleException(e) + return null + } + return transaction } private fun callFinishAuthorizeRequest( - paymentId: Long, - paymentSource: PaymentSource, - email: String? = null, - data: Map? = null, - threeDsVersion: String? = null + paymentId: Long, + paymentSource: PaymentSource, + email: String? = null, + data: Map? = null, + threeDsVersion: String? = null, + threeDSWrapper: ThreeDSWrapper? = null, + threeDsTransaction: Transaction? = null ) { val ipAddress = if (data != null) getIpAddress() else null @@ -314,19 +375,18 @@ class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { } coroutine.call(finishRequest, - onSuccess = { response -> - val threeDsData = response.getThreeDsData() - val cardId = if (paymentSource is AttachedCard) paymentSource.cardId else null - - if (threeDsData.isThreeDsNeed) { - threeDsData.version = threeDsVersion - sdkState = ThreeDsState(threeDsData) - sendToListener(PaymentState.THREE_DS_NEEDED) - } else { - paymentResult = PaymentResult(response.paymentId, cardId, response.rebillId) - sendToListener(PaymentState.SUCCESS) - } - }) + onSuccess = { response -> + val threeDsData = response.getThreeDsData(threeDsVersion) + val cardId = if (paymentSource is AttachedCard) paymentSource.cardId else null + + if (threeDsData.isThreeDsNeed) { + sdkState = ThreeDsState(threeDsData, threeDSWrapper, threeDsTransaction) + sendToListener(PaymentState.THREE_DS_NEEDED) + } else { + paymentResult = PaymentResult(response.paymentId, cardId, response.rebillId) + sendToListener(PaymentState.SUCCESS) + } + }) } private fun callChargeRequest(paymentId: Long, paymentSource: AttachedCard) { @@ -336,48 +396,48 @@ class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { } coroutine.call(chargeRequest, - onSuccess = { - val payInfo = it.getPaymentInfo() - if (payInfo.isSuccess) { - paymentResult = PaymentResult(it.paymentId, paymentSource.cardId, chargeRequest.rebillId) - sendToListener(PaymentState.SUCCESS) - } else { - error = IllegalStateException("Unknown charge state with error code: ${payInfo.errorCode}") + onSuccess = { + val payInfo = it.getPaymentInfo() + if (payInfo.isSuccess) { + paymentResult = PaymentResult(it.paymentId, paymentSource.cardId, chargeRequest.rebillId) + sendToListener(PaymentState.SUCCESS) + } else { + error = IllegalStateException("Unknown charge state with error code: ${payInfo.errorCode}") + sendToListener(PaymentState.ERROR) + } + }, + onFailure = { + if (it is AcquiringApiException && it.response != null && + it.response!!.errorCode == AcquiringApi.API_ERROR_CODE_CHARGE_REJECTED) { + val payInfo = (it.response as ChargeResponse).getPaymentInfo() + if (payInfo.cardId == null && rejectedPaymentId == null) { + error = IllegalStateException("Unknown cardId or paymentId") sendToListener(PaymentState.ERROR) - } - }, - onFailure = { - if (it is AcquiringApiException && it.response != null && - it.response!!.errorCode == AcquiringApi.API_ERROR_CODE_CHARGE_REJECTED) { - val payInfo = (it.response as ChargeResponse).getPaymentInfo() - if (payInfo.cardId == null && rejectedPaymentId == null) { - error = IllegalStateException("Unknown cardId or paymentId") - sendToListener(PaymentState.ERROR) - } else { - isChargeWasRejected = true - rejectedPaymentId = payInfo.paymentId - sdkState = RejectedState(payInfo.cardId!!, rejectedPaymentId!!) - sendToListener(PaymentState.CHARGE_REJECTED) - } } else { - handleException(it) + isChargeWasRejected = true + rejectedPaymentId = payInfo.paymentId + sdkState = RejectedState(payInfo.cardId!!, rejectedPaymentId!!) + sendToListener(PaymentState.CHARGE_REJECTED) } - }) + } else { + handleException(it) + } + }) } private fun callTinkoffPayLinkRequest(paymentId: Long, version: String) { val request = sdk.tinkoffPayLink(paymentId, version) coroutine.call(request, - onSuccess = { response -> - sdkState = OpenTinkoffPayBankState(paymentId, response.params!!.redirectUrl) - sendToListener(PaymentState.OPEN_TINKOFF_PAY_BANK) - }) + onSuccess = { response -> + sdkState = OpenTinkoffPayBankState(paymentId, response.params!!.redirectUrl) + sendToListener(PaymentState.OPEN_TINKOFF_PAY_BANK) + }) } private fun handleException(throwable: Throwable) { if (throwable is AcquiringApiException && throwable.response != null && - throwable.response!!.errorCode == AcquiringApi.API_ERROR_CODE_3DSV2_NOT_SUPPORTED) { + throwable.response!!.errorCode == AcquiringApi.API_ERROR_CODE_3DSV2_NOT_SUPPORTED) { sendToListener(PaymentState.THREE_DS_V2_REJECTED) callInitRequest(initRequest!!) } else { @@ -401,7 +461,7 @@ class PaymentProcess internal constructor(private val sdk: AcquiringSdk) { data = order.additionalData customerKey = paymentOptions.customer.customerKey language = AsdkLocalization.language.name - sdkVersion = BuildConfig.VERSION_NAME + sdkVersion = BuildConfig.ASDK_VERSION_NAME } } diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsCertsConfig.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsCertsConfig.kt new file mode 100644 index 00000000..11581a8d --- /dev/null +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsCertsConfig.kt @@ -0,0 +1,51 @@ +package ru.tinkoff.acquiring.sdk.threeds + +import com.google.gson.annotations.SerializedName +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper + +class ThreeDsCertsConfig( + @SerializedName("paymentSystem") + val certsInfo: List?, + @SerializedName("certCheckInterval") + val certCheckInterval: String? +) + +class ThreeDsCertInfo( + @SerializedName("paymentSystem") + val paymentSystem: String, + @SerializedName("directoryServerID") + val dsId: String, + @SerializedName("type") + val type: CertType, + @SerializedName("url") + val url: String, + @SerializedName("SHA256Fingerprint") + val sha256Fingerprint: String, + @SerializedName("forceUpdateFlag") + val forceUpdate: Boolean +) { + + enum class CertType { + @SerializedName("dsPublicKey") + DS, + @SerializedName("dsRootCA") + CA; + + companion object { + + fun CertType.isDs() = this == DS + + fun CertType.isCa() = this == CA + + fun fromWrapperType(type: ThreeDSWrapper.CertType) = when (type) { + ThreeDSWrapper.CertType.DS -> DS + ThreeDSWrapper.CertType.CA -> CA + } + + fun CertType.toWrapperType() = when (this) { + DS -> ThreeDSWrapper.CertType.DS + CA -> ThreeDSWrapper.CertType.CA + } + } + } +} \ No newline at end of file diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt new file mode 100644 index 00000000..9b8f2df3 --- /dev/null +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt @@ -0,0 +1,139 @@ +package ru.tinkoff.acquiring.sdk.threeds + +import android.content.Context +import com.google.gson.Gson +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.OkHttpClient +import okhttp3.Request +import ru.tinkoff.acquiring.sdk.AcquiringSdk +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsCertInfo.CertType.Companion.toWrapperType +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper.Companion.setSdkAppId +import java.util.UUID +import java.util.concurrent.TimeUnit + +object ThreeDsHelper { + + private const val CERTS_CONFIG_URL_TEST = "https://asdk-config-test.s3-msk.tinkoff.ru/certs-configs/asdk-certs-config.json" + private const val CERTS_CONFIG_URL_PROD = "https://asdk-config-prod.s3-msk.tinkoff.ru/certs-configs/asdk-certs-config.json" + + private const val PREFS_NAME = "tinkoff_asdk_prefs" + private const val SDK_APP_ID_KEY = "sdk_app_id" + + /** + * Максимальное время, в течение которого пользователь может подтвердить проведение транзакции + * через 3DS app-based flow; задается в минутах, минимальное допустимое значение - 5 минут. + */ + var maxTimeout = 5 + set(value) { + field = value.coerceAtLeast(5) + } + + /** + * Минимальное время, через которое ASDK попытается снова обновить конфиг с актуальными + * сертификатами для использования в 3DS SDK; задается в минутах. + */ + var certConfigUpdateInterval = 240L + + private var certsConfig: ThreeDsCertsConfig? = null + + /** + * Map of Payment System to Directory Server ID values. + */ + private var psToDsIdMap = mapOf( + "visa" to "A000000003", + "mir" to "A000000658", + "mc" to "A000000004", + "upi" to "A000000333") + + private var lastCertConfigUpdate = 0L + + private val okHttpClient = OkHttpClient() + private val gson = Gson() + + suspend fun initWrapper(context: Context): ThreeDSWrapper { + val wrapper = ThreeDSWrapper(when (AcquiringSdk.isDeveloperMode) { + true -> ThreeDSWrapper.EmbeddedCertsInfo.TEST + else -> ThreeDSWrapper.EmbeddedCertsInfo.PROD + }).init(context, ThreeDSWrapper.newConfigParameters { + setSdkAppId(getSdkAppId(context).toString()) + }) + val config = updateCertsConfigIfNeeded() + wrapper.updateCertsIfNeeded(config) + config?.certsInfo?.let { psToDsIdMap = it.mapPsToDsId() } + config?.certCheckInterval?.toLongOrNull()?.let { certConfigUpdateInterval = it } + return wrapper + } + + fun getDsId(paymentSystem: String): String? = psToDsIdMap[paymentSystem] + + fun isAppBasedFlow(threeDsVersion: String?) = when (threeDsVersion) { + "2.1.0" -> true + else -> false + } + + @Suppress("BlockingMethodInNonBlockingContext") + private suspend fun updateCertsConfigIfNeeded(): ThreeDsCertsConfig? { + if (certsConfig != null && (System.currentTimeMillis() - lastCertConfigUpdate) < + TimeUnit.MINUTES.toMillis(certConfigUpdateInterval)) { + return certsConfig + } + return withContext(Dispatchers.IO) { + try { + val request = Request.Builder().url(getCertsConfigUrl()).build() + val response = okHttpClient.newCall(request).execute() + val newConfig = gson.fromJson(response.body?.charStream(), ThreeDsCertsConfig::class.java) + lastCertConfigUpdate = System.currentTimeMillis() + if (newConfig != null) { + certsConfig = newConfig + } + } catch (ignored: Throwable) { + // ignore + } + certsConfig + } + } + + private suspend fun ThreeDSWrapper.updateCertsIfNeeded(config: ThreeDsCertsConfig?) { + val checkCerts = checkCerts() + val certsUpdate = mutableListOf() + config?.certsInfo?.forEach { certInfo -> + val existing = checkCerts.find { it.dsId == certInfo.dsId }?.let { + when (certInfo.type) { + ThreeDsCertInfo.CertType.DS -> it.dsCertInfo + ThreeDsCertInfo.CertType.CA -> it.caCertInfo + } + } + if (existing?.certHash != certInfo.sha256Fingerprint || certInfo.forceUpdate) { + certsUpdate.add(ThreeDSWrapper.DsCertsUpdate( + certInfo.dsId, certInfo.type.toWrapperType(), certInfo.url)) + } + } + updateCerts(certsUpdate) + } + + private fun List.mapPsToDsId() = mutableMapOf().apply { + this@mapPsToDsId.forEach { this[it.paymentSystem] = it.dsId } + } + + private fun getSdkAppId(context: Context): UUID { + val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + val sdkAppIdString = prefs.getString(SDK_APP_ID_KEY, null) + var sdkAppId = try { + sdkAppIdString?.let { UUID.fromString(it) } + } catch (ignored: IllegalArgumentException) { + null + } + if (sdkAppId == null) { + sdkAppId = UUID.randomUUID() + prefs.edit().putString(SDK_APP_ID_KEY, sdkAppId.toString()).apply() + } + return sdkAppId!! + } + + private fun getCertsConfigUrl() = when (AcquiringSdk.isDeveloperMode) { + true -> CERTS_CONFIG_URL_TEST + else -> CERTS_CONFIG_URL_PROD + } +} \ No newline at end of file diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/AttachCardActivity.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/AttachCardActivity.kt index c51bcfe0..4129cad7 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/AttachCardActivity.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/AttachCardActivity.kt @@ -80,7 +80,7 @@ internal class AttachCardActivity : TransparentActivity() { private fun handleScreenChangeEvent(screenChangeEvent: SingleEvent) { screenChangeEvent.getValueIfNotHandled()?.let { screen -> when (screen) { - is ThreeDsScreenState -> openThreeDs(screen.data) + is ThreeDsScreenState -> openThreeDs(screen) is LoopConfirmationScreenState -> showFragment(LoopConfirmationFragment.newInstance(screen.requestKey)) } } diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/BaseAcquiringActivity.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/BaseAcquiringActivity.kt index 06ed0665..b749fa43 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/BaseAcquiringActivity.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/BaseAcquiringActivity.kt @@ -69,7 +69,9 @@ internal open class BaseAcquiringActivity : AppCompatActivity() { options.validateRequiredFields() val intent = Intent(context, cls) - intent.putExtra(EXTRA_OPTIONS, options) + intent.putExtras(Bundle().apply { + putParcelable(EXTRA_OPTIONS, options) + }) return intent } } @@ -140,7 +142,7 @@ internal open class BaseAcquiringActivity : AppCompatActivity() { } protected fun provideViewModel(clazz: Class): ViewModel { - return ViewModelProvider(this, ViewModelProviderFactory(options.features.handleErrorsInSdk, sdk))[clazz] + return ViewModelProvider(this, ViewModelProviderFactory(application, options.features.handleErrorsInSdk, sdk))[clazz] } protected open fun setSuccessResult(result: AsdkResult) { @@ -165,17 +167,17 @@ internal open class BaseAcquiringActivity : AppCompatActivity() { setResult(TinkoffAcquiring.RESULT_ERROR, intent) } - protected open fun finishWithSuccess(result: AsdkResult) { + open fun finishWithSuccess(result: AsdkResult) { setSuccessResult(result) finish() } - protected open fun finishWithError(throwable: Throwable) { + open fun finishWithError(throwable: Throwable) { setErrorResult(throwable) finish() } - protected fun finishWithCancel() { + fun finishWithCancel() { setResult(Activity.RESULT_CANCELED) finish() } diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/NotificationPaymentActivity.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/NotificationPaymentActivity.kt index a03b35b3..097f4c34 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/NotificationPaymentActivity.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/NotificationPaymentActivity.kt @@ -147,7 +147,7 @@ internal class NotificationPaymentActivity : AppCompatActivity() { val sdk = AcquiringSdk(paymentOptions.terminalKey, paymentOptions.publicKey) viewModel = ViewModelProvider(this, - ViewModelProviderFactory(paymentOptions.features.handleErrorsInSdk, + ViewModelProviderFactory(application, paymentOptions.features.handleErrorsInSdk, sdk))[NotificationPaymentViewModel::class.java] if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/PaymentActivity.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/PaymentActivity.kt index b56cc2bd..fd6a79da 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/PaymentActivity.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/PaymentActivity.kt @@ -155,7 +155,7 @@ internal class PaymentActivity : TransparentActivity() { val state = RejectedState(screen.cardId, screen.rejectedPaymentId) showFragment(PaymentFragment.newInstance(paymentOptions.customer.customerKey, state)) } - is ThreeDsScreenState -> openThreeDs(screen.data) + is ThreeDsScreenState -> openThreeDs(screen) is ThreeDsDataCollectScreenState -> { paymentViewModel.collectedDeviceData = ThreeDsActivity.collectData(this, screen.response) } diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/ThreeDsActivity.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/ThreeDsActivity.kt index cc37650a..962e79b0 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/ThreeDsActivity.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/ThreeDsActivity.kt @@ -195,14 +195,6 @@ internal class ThreeDsActivity : BaseAcquiringActivity() { return Base64.encodeToString(creqData.toString().toByteArray(), Base64.NO_PADDING).trim() } - private fun requestState() { - if (data.isPayment) { - viewModel.requestPaymentState(data.paymentId) - } else if (data.isAttaching) { - viewModel.requestAddCardState(data.requestKey) - } - } - private inner class ThreeDsWebViewClient : WebViewClient() { private var canceled = false @@ -222,7 +214,7 @@ internal class ThreeDsActivity : BaseAcquiringActivity() { if (termUrl == url) { view.visibility = View.INVISIBLE if (!canceled) { - requestState() + viewModel.requestState(data) } } } diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt index 14168b3b..8a063f56 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt @@ -26,13 +26,19 @@ import android.view.View import android.view.WindowManager import androidx.appcompat.widget.Toolbar import ru.tinkoff.acquiring.sdk.R +import ru.tinkoff.acquiring.sdk.exceptions.AcquiringSdkException import ru.tinkoff.acquiring.sdk.localization.AsdkLocalization import ru.tinkoff.acquiring.sdk.localization.LocalizationResources +import ru.tinkoff.acquiring.sdk.models.ErrorScreenState +import ru.tinkoff.acquiring.sdk.models.FinishWithErrorScreenState import ru.tinkoff.acquiring.sdk.models.LoadState import ru.tinkoff.acquiring.sdk.models.LoadedState -import ru.tinkoff.acquiring.sdk.models.ThreeDsData +import ru.tinkoff.acquiring.sdk.models.ScreenState +import ru.tinkoff.acquiring.sdk.models.ThreeDsScreenState import ru.tinkoff.acquiring.sdk.models.result.AsdkResult +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper import ru.tinkoff.acquiring.sdk.ui.customview.BottomContainer +import ru.tinkoff.acquiring.sdk.viewmodel.ThreeDsViewModel /** * @author Mariya Chernyadieva @@ -46,6 +52,8 @@ internal open class TransparentActivity : BaseAcquiringActivity() { private var orientation: Int = 0 private var viewType: Int = 0 + lateinit var threeDsViewModel: ThreeDsViewModel + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -55,6 +63,20 @@ internal open class TransparentActivity : BaseAcquiringActivity() { savedInstanceState?.let { showBottomView = it.getBoolean(STATE_SHOW_BOTTOM) } + + threeDsViewModel = provideViewModel(ThreeDsViewModel::class.java) as ThreeDsViewModel + threeDsViewModel.run { + loadStateLiveData.observe(this@TransparentActivity) { handleLoadState(it) } + screenStateLiveData.observe(this@TransparentActivity) { handleThreeDsScreenState(it) } + resultLiveData.observe(this@TransparentActivity) { finishWithSuccess(it) } + } + } + + private fun handleThreeDsScreenState(screenState: ScreenState) { + when (screenState) { + is ErrorScreenState -> finishWithError(AcquiringSdkException(IllegalStateException(screenState.message))) + is FinishWithErrorScreenState -> finishWithError(screenState.error) + } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -69,7 +91,7 @@ internal open class TransparentActivity : BaseAcquiringActivity() { } } else { supportFragmentManager - .findFragmentById(R.id.acq_activity_fl_container)?.onActivityResult(requestCode, resultCode, data) + .findFragmentById(R.id.acq_activity_fl_container)?.onActivityResult(requestCode, resultCode, data) } super.onActivityResult(requestCode, resultCode, data) } @@ -140,7 +162,7 @@ internal open class TransparentActivity : BaseAcquiringActivity() { showBottomView = showBottomView && (viewType == EXPANDED_INDEX && !fullScreenMode) && orientation == Configuration.ORIENTATION_PORTRAIT if (orientation == Configuration.ORIENTATION_PORTRAIT) { - when { + when { viewType == EXPANDED_INDEX && !fullScreenMode -> { window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN setupTranslucentStatusBar() @@ -157,9 +179,15 @@ internal open class TransparentActivity : BaseAcquiringActivity() { bottomContainer.showInitAnimation = showBottomView } - protected fun openThreeDs(data: ThreeDsData) { - val intent = ThreeDsActivity.createIntent(this, options, data) - startActivityForResult(intent, THREE_DS_REQUEST_CODE) + protected fun openThreeDs(screenState: ThreeDsScreenState) { + val threeDsData = screenState.data + if (ThreeDsHelper.isAppBasedFlow(threeDsData.version)) { + threeDsViewModel.launchThreeDsAppBased(this, + screenState.data, screenState.wrapper!!, screenState.transaction!!) + } else { + val intent = ThreeDsActivity.createIntent(this, options, threeDsData) + startActivityForResult(intent, THREE_DS_REQUEST_CODE) + } } private fun setupTranslucentStatusBar() { diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/customview/editcard/EditCard.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/customview/editcard/EditCard.kt index 88a57760..8b344e5c 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/customview/editcard/EditCard.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/customview/editcard/EditCard.kt @@ -334,7 +334,7 @@ internal class EditCard @JvmOverloads constructor( selectionPaint.color = cursorColor selectionPaint.alpha = 100 - cardNumberMask = "0".repeat(CardPaymentSystem.getLengthRanges(MAESTRO).max()!!) + cardNumberMask = "0".repeat(CardPaymentSystem.getLengthRanges(MAESTRO).maxOrNull()!!) scanButton?.isVisible = isScanButtonVisible @@ -1528,7 +1528,7 @@ internal class EditCard @JvmOverloads constructor( private fun updateCardInputFilter() { val paymentSystem = CardPaymentSystem.resolvePaymentSystem(cardNumber) - cardNumberEditable.filters = arrayOf(InputFilter.LengthFilter(CardPaymentSystem.getLengthRanges(paymentSystem).max()!!)) + cardNumberEditable.filters = arrayOf(InputFilter.LengthFilter(CardPaymentSystem.getLengthRanges(paymentSystem).maxOrNull()!!)) } private fun switchEditable(newEditableField: EditCardField) { diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/utils/CoroutineManager.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/utils/CoroutineManager.kt index 438afd8b..25cef90a 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/utils/CoroutineManager.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/utils/CoroutineManager.kt @@ -95,13 +95,19 @@ internal class CoroutineManager(private val exceptionHandler: (Throwable) -> Uni } } - private fun doOnMain(block: () -> Unit) { + fun doOnMain(block: () -> Unit) { coroutineScope.launch(Dispatchers.Main) { block.invoke() } } - private fun doOnBackground(block: () -> Unit) { + fun launchOnBackground(block: suspend CoroutineScope.() -> Unit) { + coroutineScope.launch(IO) { + block.invoke(this) + } + } + + fun doOnBackground(block: () -> Unit) { coroutineScope.launch(IO) { block.invoke() } diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/AttachCardViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/AttachCardViewModel.kt index 963389c5..2a36add4 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/AttachCardViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/AttachCardViewModel.kt @@ -16,6 +16,7 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import ru.tinkoff.acquiring.sdk.AcquiringSdk @@ -36,7 +37,11 @@ import ru.tinkoff.acquiring.sdk.network.AcquiringApi /** * @author Mariya Chernyadieva */ -internal class AttachCardViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : BaseAcquiringViewModel(handleErrorsInSdk, sdk) { +internal class AttachCardViewModel( + application: Application, + handleErrorsInSdk: Boolean, + sdk: AcquiringSdk +) : BaseAcquiringViewModel(application, handleErrorsInSdk, sdk) { private lateinit var cardData: CardData private val attachCardResult: MutableLiveData = MutableLiveData() @@ -86,7 +91,7 @@ internal class AttachCardViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk coroutine.call(attachCardRequest, onSuccess = { when (it.status) { - ResponseStatus.THREE_DS_CHECKING -> changeScreenState(ThreeDsScreenState(it.getThreeDsData())) + ResponseStatus.THREE_DS_CHECKING -> changeScreenState(ThreeDsScreenState(it.getThreeDsData(), null, null)) ResponseStatus.LOOP_CHECKING -> changeScreenState(LoopConfirmationScreenState(it.requestKey!!)) null -> attachCardResult.value = CardResult(it.cardId) else -> { diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/BaseAcquiringViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/BaseAcquiringViewModel.kt index 8ac6e65f..ff9459aa 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/BaseAcquiringViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/BaseAcquiringViewModel.kt @@ -16,6 +16,9 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application +import android.content.Context +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -30,7 +33,11 @@ import ru.tinkoff.acquiring.sdk.utils.CoroutineManager /** * @author Mariya Chernyadieva */ -internal open class BaseAcquiringViewModel(val handleErrorsInSdk: Boolean, val sdk: AcquiringSdk) : ViewModel() { +internal open class BaseAcquiringViewModel( + application: Application, + val handleErrorsInSdk: Boolean, + val sdk: AcquiringSdk +) : AndroidViewModel(application) { protected val coroutine = CoroutineManager(exceptionHandler = { handleException(it) }) private val loadState: MutableLiveData = MutableLiveData() @@ -41,6 +48,8 @@ internal open class BaseAcquiringViewModel(val handleErrorsInSdk: Boolean, val s val screenStateLiveData: LiveData = screenState val loadStateLiveData: LiveData = loadState + val context: Context get() = getApplication().applicationContext + override fun onCleared() { super.onCleared() coroutine.cancelAll() diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/NotificationPaymentViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/NotificationPaymentViewModel.kt index 61064942..bfd20a9f 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/NotificationPaymentViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/NotificationPaymentViewModel.kt @@ -1,5 +1,6 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import ru.tinkoff.acquiring.sdk.AcquiringSdk @@ -16,8 +17,11 @@ import ru.tinkoff.acquiring.sdk.payment.PaymentProcess /** * @author Mariya Chernyadieva */ -internal class NotificationPaymentViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : - BaseAcquiringViewModel(handleErrorsInSdk, sdk) { +internal class NotificationPaymentViewModel( + application: Application, + handleErrorsInSdk: Boolean, + sdk: AcquiringSdk +) : BaseAcquiringViewModel(application, handleErrorsInSdk, sdk) { private var paymentProcess: PaymentProcess? = null @@ -38,7 +42,7 @@ internal class NotificationPaymentViewModel(handleErrorsInSdk: Boolean, sdk: Acq fun initPayment(token: String, paymentOptions: PaymentOptions) { changeScreenState(LoadingState) - paymentProcess = PaymentProcess(sdk).createPaymentProcess(GooglePay(token), paymentOptions) + paymentProcess = PaymentProcess(sdk, context).createPaymentProcess(GooglePay(token), paymentOptions) .subscribe(object : PaymentListenerAdapter() { override fun onSuccess(paymentId: Long, cardId: String?, rebillId: String?) { changeScreenState(LoadedState) diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/PaymentViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/PaymentViewModel.kt index fea471b3..e6f5ac93 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/PaymentViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/PaymentViewModel.kt @@ -16,6 +16,7 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import kotlinx.coroutines.launch @@ -54,14 +55,18 @@ import ru.tinkoff.acquiring.sdk.responses.TinkoffPayStatusResponse /** * @author Mariya Chernyadieva */ -internal class PaymentViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : BaseAcquiringViewModel(handleErrorsInSdk, sdk) { +internal class PaymentViewModel( + application: Application, + handleErrorsInSdk: Boolean, + sdk: AcquiringSdk +) : BaseAcquiringViewModel(application, handleErrorsInSdk, sdk) { private val paymentResult: MutableLiveData = MutableLiveData() private var cardsResult: MutableLiveData> = MutableLiveData() private var tinkoffPayStatusResult: MutableLiveData = MutableLiveData() private val paymentListener: PaymentListener = createPaymentListener() - private val paymentProcess: PaymentProcess = PaymentProcess(sdk) + private val paymentProcess: PaymentProcess = PaymentProcess(sdk, context) private var requestPaymentStateCount = 0 @@ -78,7 +83,7 @@ internal class PaymentViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : fun checkoutAsdkState(state: AsdkState) { when (state) { - is ThreeDsState -> changeScreenState(ThreeDsScreenState(state.data)) + is ThreeDsState -> changeScreenState(ThreeDsScreenState(state.data, state.threeDSWrapper, state.transaction)) is RejectedState -> changeScreenState(RejectedCardScreenState(state.cardId, state.rejectedPaymentId)) is BrowseFpsBankState -> changeScreenState(BrowseFpsBankScreenState(state.paymentId, state.deepLink, state.banks)) is FpsState -> changeScreenState(FpsScreenState) @@ -178,37 +183,37 @@ internal class PaymentViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : } coroutine.call(request, - onSuccess = { response -> - requestPaymentStateCount++ - when (response.status) { - ResponseStatus.CONFIRMED, ResponseStatus.AUTHORIZED -> { - paymentResult.value = PaymentResult(response.paymentId) - requestPaymentStateCount = 0 - changeScreenState(LoadedState) - } - ResponseStatus.FORM_SHOWED -> { - requestPaymentStateCount = 0 - changeScreenState(LoadedState) - changeScreenState(FpsBankFormShowedScreenState(paymentId)) - } - else -> { - if (requestPaymentStateCount == 1) { - changeScreenState(LoadingState) - coroutine.runWithDelay(1000) { - requestPaymentState(paymentId) - } - } else { - changeScreenState(LoadedState) - val throwable = AcquiringSdkException(IllegalStateException("PaymentState = ${response.status}")) - handleException(throwable) + onSuccess = { response -> + requestPaymentStateCount++ + when (response.status) { + ResponseStatus.CONFIRMED, ResponseStatus.AUTHORIZED -> { + paymentResult.value = PaymentResult(response.paymentId) + requestPaymentStateCount = 0 + changeScreenState(LoadedState) + } + ResponseStatus.FORM_SHOWED -> { + requestPaymentStateCount = 0 + changeScreenState(LoadedState) + changeScreenState(FpsBankFormShowedScreenState(paymentId)) + } + else -> { + if (requestPaymentStateCount == 1) { + changeScreenState(LoadingState) + coroutine.runWithDelay(1000) { + requestPaymentState(paymentId) } + } else { + changeScreenState(LoadedState) + val throwable = AcquiringSdkException(IllegalStateException("PaymentState = ${response.status}")) + handleException(throwable) } } - }, - onFailure = { - requestPaymentStateCount = 0 - handleException(it) - }) + } + }, + onFailure = { + requestPaymentStateCount = 0 + handleException(it) + }) } private fun createPaymentListener(): PaymentListener { @@ -222,7 +227,7 @@ internal class PaymentViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : override fun onUiNeeded(state: AsdkState) { when (state) { is ThreeDsState -> { - changeScreenState(ThreeDsScreenState(state.data)) + changeScreenState(ThreeDsScreenState(state.data, state.threeDSWrapper, state.transaction)) coroutine.runWithDelay(500) { changeScreenState(LoadedState) } diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/QrViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/QrViewModel.kt index 95f522c6..0701bd91 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/QrViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/QrViewModel.kt @@ -16,6 +16,7 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import ru.tinkoff.acquiring.sdk.AcquiringSdk @@ -30,7 +31,11 @@ import ru.tinkoff.acquiring.sdk.models.enums.ResponseStatus import ru.tinkoff.acquiring.sdk.models.options.screen.PaymentOptions import ru.tinkoff.acquiring.sdk.requests.InitRequest -internal class QrViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : BaseAcquiringViewModel(handleErrorsInSdk, sdk) { +internal class QrViewModel( + application: Application, + handleErrorsInSdk: Boolean, + sdk: AcquiringSdk +) : BaseAcquiringViewModel(application, handleErrorsInSdk, sdk) { private val qrLinkResult: MutableLiveData> = MutableLiveData() private val qrImageResult: MutableLiveData = MutableLiveData() @@ -135,7 +140,7 @@ internal class QrViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : Base data = order.additionalData customerKey = paymentOptions.customer.customerKey language = AsdkLocalization.language.name - sdkVersion = BuildConfig.VERSION_NAME + sdkVersion = BuildConfig.ASDK_VERSION_NAME } } } \ No newline at end of file diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/SavedCardsViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/SavedCardsViewModel.kt index d316aa90..96f443a6 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/SavedCardsViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/SavedCardsViewModel.kt @@ -16,6 +16,7 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import ru.tinkoff.acquiring.sdk.AcquiringSdk @@ -30,7 +31,11 @@ import ru.tinkoff.acquiring.sdk.network.AcquiringApi /** * @author Mariya Chernyadieva */ -internal class SavedCardsViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : BaseAcquiringViewModel(handleErrorsInSdk, sdk) { +internal class SavedCardsViewModel( + application: Application, + handleErrorsInSdk: Boolean, + sdk: AcquiringSdk +) : BaseAcquiringViewModel(application, handleErrorsInSdk, sdk) { private val needHandleErrorsInSdk = handleErrorsInSdk private val deleteCardEvent: MutableLiveData> = MutableLiveData() @@ -48,26 +53,26 @@ internal class SavedCardsViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk } coroutine.call(request, - onSuccess = { - var activeCards = it.cards.filter { card -> - card.status == CardStatus.ACTIVE - } - if (recurrentOnly) { - activeCards = activeCards.filter { card -> !card.rebillId.isNullOrBlank() } - } - cardsResult.value = activeCards + onSuccess = { + var activeCards = it.cards.filter { card -> + card.status == CardStatus.ACTIVE + } + if (recurrentOnly) { + activeCards = activeCards.filter { card -> !card.rebillId.isNullOrBlank() } + } + cardsResult.value = activeCards + changeScreenState(LoadedState) + }, + onFailure = { + val apiError = it as? AcquiringApiException + if (needHandleErrorsInSdk && apiError != null && it.response != null && + it.response!!.errorCode == AcquiringApi.API_ERROR_CODE_CUSTOMER_NOT_FOUND) { changeScreenState(LoadedState) - }, - onFailure = { - val apiError = it as? AcquiringApiException - if (needHandleErrorsInSdk && apiError != null && it.response != null && - it.response!!.errorCode == AcquiringApi.API_ERROR_CODE_CUSTOMER_NOT_FOUND) { - changeScreenState(LoadedState) - changeScreenState(ErrorScreenState(AsdkLocalization.resources.cardListEmptyList ?: "")) - } else { - handleException(it) - } - }) + changeScreenState(ErrorScreenState(AsdkLocalization.resources.cardListEmptyList ?: "")) + } else { + handleException(it) + } + }) } fun deleteCard(cardId: String, customerKey: String) { @@ -77,16 +82,16 @@ internal class SavedCardsViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk } coroutine.call(request, - onSuccess = { response -> - when (response.status) { - CardStatus.DELETED -> { - deleteCardEvent.value = SingleEvent(response.status!!) - } - else -> { - changeScreenState(ErrorScreenState(AsdkLocalization.resources.payDialogErrorFallbackMessage!!)) - } + onSuccess = { response -> + when (response.status) { + CardStatus.DELETED -> { + deleteCardEvent.value = SingleEvent(response.status!!) } - changeScreenState(LoadedState) - }) + else -> { + changeScreenState(ErrorScreenState(AsdkLocalization.resources.payDialogErrorFallbackMessage!!)) + } + } + changeScreenState(LoadedState) + }) } } \ No newline at end of file diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt index abd363a1..e4970683 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt @@ -16,22 +16,123 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import com.emvco3ds.sdk.spec.CompletionEvent +import com.emvco3ds.sdk.spec.ProtocolErrorEvent +import com.emvco3ds.sdk.spec.RuntimeErrorEvent +import com.emvco3ds.sdk.spec.Transaction import ru.tinkoff.acquiring.sdk.AcquiringSdk import ru.tinkoff.acquiring.sdk.exceptions.AcquiringSdkException +import ru.tinkoff.acquiring.sdk.models.ErrorScreenState +import ru.tinkoff.acquiring.sdk.models.FinishWithErrorScreenState +import ru.tinkoff.acquiring.sdk.models.LoadState import ru.tinkoff.acquiring.sdk.models.LoadedState import ru.tinkoff.acquiring.sdk.models.LoadingState +import ru.tinkoff.acquiring.sdk.models.ThreeDsData import ru.tinkoff.acquiring.sdk.models.enums.ResponseStatus import ru.tinkoff.acquiring.sdk.models.result.AsdkResult import ru.tinkoff.acquiring.sdk.models.result.CardResult import ru.tinkoff.acquiring.sdk.models.result.PaymentResult +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper +import ru.tinkoff.acquiring.sdk.ui.activities.BaseAcquiringActivity +import ru.tinkoff.core.components.threedswrapper.ChallengeStatusReceiverAdapter +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper.Companion.closeSafe -internal class ThreeDsViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : BaseAcquiringViewModel(handleErrorsInSdk, sdk) { +internal class ThreeDsViewModel( + application: Application, + handleErrorsInSdk: Boolean, + sdk: AcquiringSdk +) : BaseAcquiringViewModel(application, handleErrorsInSdk, sdk) { private val asdkResult: MutableLiveData = MutableLiveData() val resultLiveData: LiveData = asdkResult + fun launchThreeDsAppBased(activity: BaseAcquiringActivity, threeDsData: ThreeDsData, + wrapper: ThreeDSWrapper, transaction: Transaction) { + val challengeParameters = ThreeDSWrapper.newChallengeParameters { + set3DSServerTransactionID(threeDsData.tdsServerTransId) + acsTransactionID = threeDsData.acsTransId + acsRefNumber = threeDsData.acsRefNumber + acsSignedContent = threeDsData.acsSignedContent + } + val progressDialog = try { + transaction.getProgressView(activity) + } catch (e: Throwable) { + transaction.closeSafe() + activity.finishWithError(e) + return + } + coroutine.doOnBackground { + transaction.doChallenge(activity, challengeParameters, + object : ChallengeStatusReceiverAdapter(transaction, progressDialog) { + override fun completed(event: CompletionEvent?) { + super.completed(event) + wrapper.cleanup(activity) + coroutine.doOnMain { + changeScreenState(LoadingState) + submitAuthorization(threeDsData, event!!.transactionStatus) + } + } + + override fun cancelled() { + super.cancelled() + wrapper.cleanup(activity) + coroutine.doOnMain { + activity.finishWithCancel() + } + } + + override fun timedout() { + super.timedout() + wrapper.cleanup(activity) + coroutine.doOnMain { + changeScreenState(ErrorScreenState("3DS SDK transaction timeout")) + } + } + + override fun protocolError(event: ProtocolErrorEvent?) { + super.protocolError(event) + wrapper.cleanup(activity) + val errorMessage = "3DS SDK protocol error: sdkTransactionID - ${event?.sdkTransactionID}, message - ${event?.errorMessage}" + coroutine.doOnMain { + changeScreenState(FinishWithErrorScreenState(RuntimeException(errorMessage))) + } + } + + override fun runtimeError(event: RuntimeErrorEvent?) { + super.runtimeError(event) + wrapper.cleanup(activity) + val errorMessage = "3DS SDK runtime error: code - ${event?.errorCode}, message - ${event?.errorMessage}" + coroutine.doOnMain { + changeScreenState(FinishWithErrorScreenState(AcquiringSdkException(RuntimeException(errorMessage)))) + } + } + }, ThreeDsHelper.maxTimeout) + } + } + + private fun submitAuthorization(threeDsData: ThreeDsData, transStatus: String) { + val request = sdk.submit3DSAuthorization(threeDsData.tdsServerTransId!!, transStatus) + + coroutine.call(request, + onSuccess = { + requestState(threeDsData) + }, onFailure = { + requestState(threeDsData) + }) + } + + fun requestState(threeDsData: ThreeDsData) { + if (threeDsData.isPayment) { + requestPaymentState(threeDsData.paymentId) + } else if (threeDsData.isAttaching) { + requestAddCardState(threeDsData.requestKey) + } + } + fun requestPaymentState(paymentId: Long?) { changeScreenState(LoadingState) @@ -40,15 +141,15 @@ internal class ThreeDsViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : } coroutine.call(request, - onSuccess = { response -> - if (response.status == ResponseStatus.CONFIRMED || response.status == ResponseStatus.AUTHORIZED) { - asdkResult.value = PaymentResult(response.paymentId) - } else { - val throwable = AcquiringSdkException(IllegalStateException("PaymentState = ${response.status}")) - handleException(throwable) - } - changeScreenState(LoadedState) - }) + onSuccess = { response -> + if (response.status == ResponseStatus.CONFIRMED || response.status == ResponseStatus.AUTHORIZED) { + asdkResult.value = PaymentResult(response.paymentId) + } else { + val throwable = AcquiringSdkException(IllegalStateException("PaymentState = ${response.status}")) + handleException(throwable) + } + changeScreenState(LoadedState) + }) } fun requestAddCardState(requestKey: String?) { @@ -59,14 +160,14 @@ internal class ThreeDsViewModel(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : } coroutine.call(request, - onSuccess = { response -> - if (response.status == ResponseStatus.COMPLETED) { - asdkResult.value = CardResult(response.cardId) - } else { - val throwable = AcquiringSdkException(IllegalStateException("AsdkState = ${response.status}")) - handleException(throwable) - } - changeScreenState(LoadedState) - }) + onSuccess = { response -> + if (response.status == ResponseStatus.COMPLETED) { + asdkResult.value = CardResult(response.cardId) + } else { + val throwable = AcquiringSdkException(IllegalStateException("AsdkState = ${response.status}")) + handleException(throwable) + } + changeScreenState(LoadedState) + }) } } \ No newline at end of file diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ViewModelProviderFactory.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ViewModelProviderFactory.kt index b0b1df64..110ec9ad 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ViewModelProviderFactory.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ViewModelProviderFactory.kt @@ -16,6 +16,7 @@ package ru.tinkoff.acquiring.sdk.viewmodel +import android.app.Application import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import ru.tinkoff.acquiring.sdk.AcquiringSdk @@ -23,16 +24,18 @@ import ru.tinkoff.acquiring.sdk.AcquiringSdk /** * @author Mariya Chernyadieva */ -internal class ViewModelProviderFactory(handleErrorsInSdk: Boolean, sdk: AcquiringSdk) : ViewModelProvider.NewInstanceFactory() { +internal class ViewModelProviderFactory( + application: Application, handleErrorsInSdk: Boolean, sdk: AcquiringSdk +) : ViewModelProvider.AndroidViewModelFactory(application) { private val viewModelCollection: Map, BaseAcquiringViewModel> = mapOf( - BaseAcquiringViewModel::class.java to BaseAcquiringViewModel(handleErrorsInSdk, sdk), - PaymentViewModel::class.java to PaymentViewModel(handleErrorsInSdk, sdk), - AttachCardViewModel::class.java to AttachCardViewModel(handleErrorsInSdk, sdk), - QrViewModel::class.java to QrViewModel(handleErrorsInSdk, sdk), - ThreeDsViewModel::class.java to ThreeDsViewModel(handleErrorsInSdk, sdk), - SavedCardsViewModel::class.java to SavedCardsViewModel(handleErrorsInSdk, sdk), - NotificationPaymentViewModel::class.java to NotificationPaymentViewModel(handleErrorsInSdk, sdk)) + BaseAcquiringViewModel::class.java to BaseAcquiringViewModel(application, handleErrorsInSdk, sdk), + PaymentViewModel::class.java to PaymentViewModel(application, handleErrorsInSdk, sdk), + AttachCardViewModel::class.java to AttachCardViewModel(application, handleErrorsInSdk, sdk), + QrViewModel::class.java to QrViewModel(application, handleErrorsInSdk, sdk), + ThreeDsViewModel::class.java to ThreeDsViewModel(application, handleErrorsInSdk, sdk), + SavedCardsViewModel::class.java to SavedCardsViewModel(application, handleErrorsInSdk, sdk), + NotificationPaymentViewModel::class.java to NotificationPaymentViewModel(application, handleErrorsInSdk, sdk)) @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { From 170447d2d6d2945b1d92ef60a29f768da78ba17c Mon Sep 17 00:00:00 2001 From: "i.khafizov" Date: Wed, 17 Aug 2022 15:23:06 +0300 Subject: [PATCH 2/3] Fix lint --- readme.md | 2 +- ui/build.gradle | 4 ++++ .../res/layout-land/acq_fragment_attach_card.xml | 3 ++- .../main/res/layout-land/acq_fragment_dynamic_qr.xml | 3 ++- ui/src/main/res/layout-land/acq_fragment_payment.xml | 3 ++- .../main/res/layout-land/acq_fragment_static_qr.xml | 3 ++- ui/src/main/res/layout/acq_activity.xml | 4 +++- ui/src/main/res/layout/acq_activity_nfc.xml | 12 +++++++----- ui/src/main/res/layout/acq_item_card_list.xml | 3 ++- 9 files changed, 25 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index 2b2c540f..c56377ea 100644 --- a/readme.md +++ b/readme.md @@ -20,7 +20,7 @@ Acquiring SDK позволяет интегрировать [Интернет-Э - Совершение оплаты из уведомления ### Требования -Для работы Tinkoff Acquiring SDK необходим Android версии 4.4 и выше (API level 19). +Для работы Tinkoff Acquiring SDK необходим Android версии 5.0 и выше (API level 21). ### Подключение Для подключения SDK добавьте в [_build.gradle_][build-config] вашего проекта следующие зависимости: diff --git a/ui/build.gradle b/ui/build.gradle index df72650a..425436b1 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -23,6 +23,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + + lintOptions { + disable 'VectorRaster', 'UseRequireDrawableLoadingForDrawables', 'ObsoleteSdkInt', 'UnusedResources', 'IconDipSize', 'IconLocation' + } } dependencies { diff --git a/ui/src/main/res/layout-land/acq_fragment_attach_card.xml b/ui/src/main/res/layout-land/acq_fragment_attach_card.xml index 7297915a..d87638ed 100644 --- a/ui/src/main/res/layout-land/acq_fragment_attach_card.xml +++ b/ui/src/main/res/layout-land/acq_fragment_attach_card.xml @@ -22,7 +22,8 @@ + android:layout_height="match_parent" + tools:ignore="ScrollViewSize"> + android:layout_height="match_parent" + tools:ignore="ScrollViewSize"> + android:layout_height="match_parent" + tools:ignore="ScrollViewSize"> + android:layout_height="match_parent" + tools:ignore="ScrollViewSize"> @@ -26,7 +27,8 @@ android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:visibility="gone" - app:titleTextAppearance="@style/AcqToolbarTitleStyle" /> + app:titleTextAppearance="@style/AcqToolbarTitleStyle" + tools:ignore="InconsistentLayout" /> - + android:padding="@dimen/acq_nfs_padding_large" + tools:ignore="Overdraw"> + android:textSize="@dimen/acq_large_text_size" + app:drawableTopCompat="@drawable/acq_nfc" /> diff --git a/ui/src/main/res/layout/acq_item_card_list.xml b/ui/src/main/res/layout/acq_item_card_list.xml index bb04d0cc..fd5f53f3 100644 --- a/ui/src/main/res/layout/acq_item_card_list.xml +++ b/ui/src/main/res/layout/acq_item_card_list.xml @@ -15,6 +15,7 @@ --> \ No newline at end of file From b3a07247eec3691b3ebf5960741720ca5093dd54 Mon Sep 17 00:00:00 2001 From: "i.khafizov" Date: Fri, 19 Aug 2022 18:47:00 +0300 Subject: [PATCH 3/3] Fix for DKA --- .../sdk/localization/AsdkLocalization.kt | 2 ++ .../sdk/localization/LocalizationResources.kt | 6 ++++ .../acquiring/sdk/threeds/ThreeDsHelper.kt | 20 +++++++++++ .../acquiring/sdk/threeds/ThreeDsStatus.kt | 16 +++++++++ .../sdk/ui/activities/TransparentActivity.kt | 19 ++++++++++ .../sdk/viewmodel/ThreeDsViewModel.kt | 36 ++++++++----------- ui/src/main/res/raw/acq_localization_en.json | 4 ++- ui/src/main/res/raw/acq_localization_ru.json | 4 ++- 8 files changed, 83 insertions(+), 24 deletions(-) create mode 100644 ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsStatus.kt diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/AsdkLocalization.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/AsdkLocalization.kt index 90aa9e96..a7846f45 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/AsdkLocalization.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/AsdkLocalization.kt @@ -48,6 +48,8 @@ internal object AsdkLocalization { resources = parser.parse() } + fun isInitialized() = this::resources.isInitialized + private fun resolveLanguage(language: Language?): Language { return language ?: when (Locale.getDefault().language) { "ru", "ua", "kz", "by", "az", "os", "hy", "tg", "tk" -> Language.RU //страны СНГ diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/LocalizationResources.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/LocalizationResources.kt index ecb824a2..08c9ab99 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/LocalizationResources.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/localization/LocalizationResources.kt @@ -192,4 +192,10 @@ internal class LocalizationResources { @SerializedName("SbpWidget.AppsNotFound.ButtonBrowser") var sbpWidgetAppsNotFoundButtonBrowser: String? = null + + @SerializedName("ThreeDs.Confirmation") + var threeDsConfirmation: String? = null + + @SerializedName("ThreeDs.Cancel") + var threeDsCancel: String? = null } \ No newline at end of file diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt index 9b8f2df3..5fd5aad3 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsHelper.kt @@ -7,9 +7,13 @@ import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import okhttp3.Request import ru.tinkoff.acquiring.sdk.AcquiringSdk +import ru.tinkoff.acquiring.sdk.localization.AsdkLocalization import ru.tinkoff.acquiring.sdk.threeds.ThreeDsCertInfo.CertType.Companion.toWrapperType import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper.Companion.cancelButtonCustomization import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper.Companion.setSdkAppId +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper.Companion.submitButtonCustomization +import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper.Companion.toolbarCustomization import java.util.UUID import java.util.concurrent.TimeUnit @@ -52,12 +56,28 @@ object ThreeDsHelper { private val okHttpClient = OkHttpClient() private val gson = Gson() + internal var threeDsStatus: ThreeDsStatus? = null + suspend fun initWrapper(context: Context): ThreeDSWrapper { + val localisation = if (AsdkLocalization.isInitialized()) AsdkLocalization.resources else null + val wrapper = ThreeDSWrapper(when (AcquiringSdk.isDeveloperMode) { true -> ThreeDSWrapper.EmbeddedCertsInfo.TEST else -> ThreeDSWrapper.EmbeddedCertsInfo.PROD }).init(context, ThreeDSWrapper.newConfigParameters { setSdkAppId(getSdkAppId(context).toString()) + }, null, ThreeDSWrapper.newUiCustomization { + toolbarCustomization { + headerText = localisation?.threeDsConfirmation ?: "Confirmation" + buttonText = localisation?.threeDsCancel ?: "Cancel" + backgroundColor = "#888888" + } + submitButtonCustomization { + backgroundColor = "#ffdd2d" + } + cancelButtonCustomization { + textColor = "#ffffff" + } }) val config = updateCertsConfigIfNeeded() wrapper.updateCertsIfNeeded(config) diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsStatus.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsStatus.kt new file mode 100644 index 00000000..2b473a82 --- /dev/null +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/threeds/ThreeDsStatus.kt @@ -0,0 +1,16 @@ +package ru.tinkoff.acquiring.sdk.threeds + +import ru.tinkoff.acquiring.sdk.models.ThreeDsData + +sealed class ThreeDsStatus + +class ThreeDsStatusSuccess( + val threeDsData: ThreeDsData, + val transStatus: String +): ThreeDsStatus() + +class ThreeDsStatusCanceled(): ThreeDsStatus() + +class ThreeDsStatusError( + val error: Throwable +): ThreeDsStatus() \ No newline at end of file diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt index 8a063f56..a179ca61 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/ui/activities/TransparentActivity.kt @@ -37,6 +37,9 @@ import ru.tinkoff.acquiring.sdk.models.ScreenState import ru.tinkoff.acquiring.sdk.models.ThreeDsScreenState import ru.tinkoff.acquiring.sdk.models.result.AsdkResult import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsStatusCanceled +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsStatusError +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsStatusSuccess import ru.tinkoff.acquiring.sdk.ui.customview.BottomContainer import ru.tinkoff.acquiring.sdk.viewmodel.ThreeDsViewModel @@ -64,6 +67,10 @@ internal open class TransparentActivity : BaseAcquiringActivity() { showBottomView = it.getBoolean(STATE_SHOW_BOTTOM) } + initThreeDs() + } + + private fun initThreeDs() { threeDsViewModel = provideViewModel(ThreeDsViewModel::class.java) as ThreeDsViewModel threeDsViewModel.run { loadStateLiveData.observe(this@TransparentActivity) { handleLoadState(it) } @@ -79,6 +86,18 @@ internal open class TransparentActivity : BaseAcquiringActivity() { } } + override fun onResume() { + super.onResume() + + when (val threeDsStatus = ThreeDsHelper.threeDsStatus) { + is ThreeDsStatusSuccess -> threeDsViewModel.submitAuthorization(threeDsStatus.threeDsData, threeDsStatus.transStatus) + is ThreeDsStatusCanceled -> finishWithCancel() + is ThreeDsStatusError -> finishWithError(threeDsStatus.error) + else -> Unit + } + ThreeDsHelper.threeDsStatus = null + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == THREE_DS_REQUEST_CODE) { if (resultCode == Activity.RESULT_OK && data != null) { diff --git a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt index e4970683..5ccbb1ee 100644 --- a/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt +++ b/ui/src/main/java/ru/tinkoff/acquiring/sdk/viewmodel/ThreeDsViewModel.kt @@ -25,9 +25,6 @@ import com.emvco3ds.sdk.spec.RuntimeErrorEvent import com.emvco3ds.sdk.spec.Transaction import ru.tinkoff.acquiring.sdk.AcquiringSdk import ru.tinkoff.acquiring.sdk.exceptions.AcquiringSdkException -import ru.tinkoff.acquiring.sdk.models.ErrorScreenState -import ru.tinkoff.acquiring.sdk.models.FinishWithErrorScreenState -import ru.tinkoff.acquiring.sdk.models.LoadState import ru.tinkoff.acquiring.sdk.models.LoadedState import ru.tinkoff.acquiring.sdk.models.LoadingState import ru.tinkoff.acquiring.sdk.models.ThreeDsData @@ -36,6 +33,9 @@ import ru.tinkoff.acquiring.sdk.models.result.AsdkResult import ru.tinkoff.acquiring.sdk.models.result.CardResult import ru.tinkoff.acquiring.sdk.models.result.PaymentResult import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsStatusCanceled +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsStatusError +import ru.tinkoff.acquiring.sdk.threeds.ThreeDsStatusSuccess import ru.tinkoff.acquiring.sdk.ui.activities.BaseAcquiringActivity import ru.tinkoff.core.components.threedswrapper.ChallengeStatusReceiverAdapter import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper @@ -71,50 +71,42 @@ internal class ThreeDsViewModel( override fun completed(event: CompletionEvent?) { super.completed(event) wrapper.cleanup(activity) - coroutine.doOnMain { - changeScreenState(LoadingState) - submitAuthorization(threeDsData, event!!.transactionStatus) - } + ThreeDsHelper.threeDsStatus = ThreeDsStatusSuccess(threeDsData, event!!.transactionStatus) } override fun cancelled() { super.cancelled() wrapper.cleanup(activity) - coroutine.doOnMain { - activity.finishWithCancel() - } + ThreeDsHelper.threeDsStatus = ThreeDsStatusCanceled() } override fun timedout() { super.timedout() wrapper.cleanup(activity) - coroutine.doOnMain { - changeScreenState(ErrorScreenState("3DS SDK transaction timeout")) - } + val error = RuntimeException("3DS SDK transaction timeout") + ThreeDsHelper.threeDsStatus = ThreeDsStatusError(error) } override fun protocolError(event: ProtocolErrorEvent?) { super.protocolError(event) wrapper.cleanup(activity) - val errorMessage = "3DS SDK protocol error: sdkTransactionID - ${event?.sdkTransactionID}, message - ${event?.errorMessage}" - coroutine.doOnMain { - changeScreenState(FinishWithErrorScreenState(RuntimeException(errorMessage))) - } + val error = RuntimeException("3DS SDK protocol error: sdkTransactionID - ${event?.sdkTransactionID}, message - ${event?.errorMessage}") + ThreeDsHelper.threeDsStatus = ThreeDsStatusError(error) } override fun runtimeError(event: RuntimeErrorEvent?) { super.runtimeError(event) wrapper.cleanup(activity) - val errorMessage = "3DS SDK runtime error: code - ${event?.errorCode}, message - ${event?.errorMessage}" - coroutine.doOnMain { - changeScreenState(FinishWithErrorScreenState(AcquiringSdkException(RuntimeException(errorMessage)))) - } + val error = RuntimeException("3DS SDK runtime error: code - ${event?.errorCode}, message - ${event?.errorMessage}") + ThreeDsHelper.threeDsStatus = ThreeDsStatusError(error) } }, ThreeDsHelper.maxTimeout) } } - private fun submitAuthorization(threeDsData: ThreeDsData, transStatus: String) { + fun submitAuthorization(threeDsData: ThreeDsData, transStatus: String) { + changeScreenState(LoadingState) + val request = sdk.submit3DSAuthorization(threeDsData.tdsServerTransId!!, transStatus) coroutine.call(request, diff --git a/ui/src/main/res/raw/acq_localization_en.json b/ui/src/main/res/raw/acq_localization_en.json index 303f0579..353c0d19 100644 --- a/ui/src/main/res/raw/acq_localization_en.json +++ b/ui/src/main/res/raw/acq_localization_en.json @@ -54,5 +54,7 @@ "SbpWidget.AppsNotFound.Title": "Banking applications not found", "SbpWidget.AppsNotFound.Description": "To pay via FPS, you must have installed banking application", "SbpWidget.AppsNotFound.Button": "OK", - "SbpWidget.AppsNotFound.ButtonBrowser": "Information on the FPS website" + "SbpWidget.AppsNotFound.ButtonBrowser": "Information on the FPS website", + "ThreeDs.Confirmation": "Confirmation", + "ThreeDs.Cancel": "Cancel" } \ No newline at end of file diff --git a/ui/src/main/res/raw/acq_localization_ru.json b/ui/src/main/res/raw/acq_localization_ru.json index e9e2b4f5..0108404a 100644 --- a/ui/src/main/res/raw/acq_localization_ru.json +++ b/ui/src/main/res/raw/acq_localization_ru.json @@ -54,5 +54,7 @@ "SbpWidget.AppsNotFound.Title": "Не найдено ни одного банковского приложения", "SbpWidget.AppsNotFound.Description": "Для оплаты через СБП необходимо иметь установленными банковские приложения", "SbpWidget.AppsNotFound.Button": "Понятно", - "SbpWidget.AppsNotFound.ButtonBrowser": "Информация на сайте сбп" + "SbpWidget.AppsNotFound.ButtonBrowser": "Информация на сайте сбп", + "ThreeDs.Confirmation": "Подтверждение", + "ThreeDs.Cancel": "Отмена" } \ No newline at end of file