Updated on 2026-08-14
This commit is contained in:
parent
8cff4c1bba
commit
ab6072e12d
18 changed files with 219 additions and 57 deletions
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.data.pay.datasource
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.pay.datasource.TangemPayAuthDataSource
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaDataToSignByCustomerWallet
|
||||
import com.tangem.domain.visa.datasource.VisaAuthRemoteDataSource
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultTangemPayAuthDataSource @Inject constructor(
|
||||
private val visaAuthRemoteDataSource: VisaAuthRemoteDataSource,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
) : TangemPayAuthDataSource {
|
||||
|
||||
override suspend fun generateNewAuthHeader(address: String, cardId: String): Either<Throwable, String> = either {
|
||||
val challenge = visaAuthRemoteDataSource
|
||||
.getCustomerWalletAuthChallenge(address)
|
||||
.mapLeft { IllegalStateException("TangemPay challenge failed. Error code: ${it.errorCode}") }
|
||||
.bind()
|
||||
|
||||
val signed = tangemSdkManager.visaCustomerWalletApprove(
|
||||
VisaDataForApprove(
|
||||
customerWalletCardId = cardId,
|
||||
targetAddress = address,
|
||||
dataToSign = VisaDataToSignByCustomerWallet(hashToSign = challenge.challenge),
|
||||
),
|
||||
).toEither { IllegalStateException("TangemPay signing failed: $it") }.bind()
|
||||
|
||||
visaAuthRemoteDataSource.getTokenWithCustomerWallet(
|
||||
sessionId = challenge.session.sessionId,
|
||||
signature = signed.signature,
|
||||
nonce = signed.dataToSign.hashToSign,
|
||||
)
|
||||
.mapLeft { IllegalStateException("TangemPay token fetch failed. Error code: ${it.errorCode}") }
|
||||
.bind()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> CompletionResult<T>.toEither(map: (Throwable) -> Throwable) = when (this) {
|
||||
is CompletionResult.Success -> Either.Right(data)
|
||||
is CompletionResult.Failure -> Either.Left(map(error))
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.data.pay.di
|
||||
|
||||
import com.tangem.data.pay.DefaultKycRepository
|
||||
import com.tangem.data.pay.repository.DefaultKycRepository
|
||||
import com.tangem.domain.pay.repository.KycRepository
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
|
|
|||
|
|
@ -1,58 +1,48 @@
|
|||
package com.tangem.data.pay
|
||||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.common.map
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.models.response.VisaErrorResponseJsonAdapter
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.pay.KycStartInfo
|
||||
import com.tangem.domain.pay.datasource.TangemPayAuthDataSource
|
||||
import com.tangem.domain.pay.repository.KycRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.domain.visa.model.VisaDataForApprove
|
||||
import com.tangem.domain.visa.model.VisaDataToSignByCustomerWallet
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
class DefaultKycRepository @AssistedInject constructor(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val visaAuthRepository: VisaAuthRepository,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val authDataSource: TangemPayAuthDataSource,
|
||||
private val tangemPayStorage: TangemPayStorage,
|
||||
) : KycRepository {
|
||||
|
||||
private val visaErrorAdapter = VisaErrorResponseJsonAdapter(moshi)
|
||||
|
||||
override suspend fun getKycStartInfo(address: String, cardId: String): Either<UniversalError, KycStartInfo> {
|
||||
var authHeader = ""
|
||||
visaAuthRepository.getCustomerWalletAuthChallenge(address).getOrNull()?.let { result ->
|
||||
tangemSdkManager.visaCustomerWalletApprove(
|
||||
VisaDataForApprove(
|
||||
customerWalletCardId = cardId,
|
||||
targetAddress = address,
|
||||
dataToSign = VisaDataToSignByCustomerWallet(hashToSign = result.challenge),
|
||||
),
|
||||
).map { signResult ->
|
||||
visaAuthRepository.getTokenWithCustomerWallet(
|
||||
sessionId = result.session.sessionId,
|
||||
signature = signResult.signature,
|
||||
nonce = signResult.dataToSign.hashToSign,
|
||||
).getOrNull()?.let { authHeader = it }
|
||||
}
|
||||
}
|
||||
val authHeader = authDataSource.generateNewAuthHeader(address, cardId)
|
||||
.getOrNull()
|
||||
.takeIf { !it.isNullOrEmpty() }
|
||||
?: return Either.Left(VisaApiError.UnknownWithoutCode)
|
||||
tangemPayStorage.store(authHeader)
|
||||
return getKycInfo(authHeader)
|
||||
}
|
||||
|
||||
override suspend fun getKycStartInfo(authHeader: String): Either<UniversalError, KycStartInfo> {
|
||||
return getKycInfo(authHeader)
|
||||
}
|
||||
|
||||
private suspend fun getKycInfo(authHeader: String): Either<UniversalError, KycStartInfo> {
|
||||
return request {
|
||||
authHeader.ifEmpty { error("Cannot get auth header for KYC") }
|
||||
tangemPayApi.getKycAccess(authHeader = authHeader).getOrThrow().result
|
||||
}.map {
|
||||
KycStartInfo(
|
||||
token = it.token,
|
||||
locale = it.locale,
|
||||
)
|
||||
KycStartInfo(token = it.token, locale = it.locale)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
|||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.domain.visa.model.*
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.domain.visa.datasource.VisaAuthRemoteDataSource
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -32,7 +32,7 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor(
|
|||
private val visaApi: TangemPayApi,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
private val visaAuthTokenStorage: VisaAuthTokenStorage,
|
||||
private val visaAuthRepository: VisaAuthRepository,
|
||||
private val visaAuthRemoteDataSource: VisaAuthRemoteDataSource,
|
||||
private val visaLibLoader: VisaLibLoader,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
) : VisaActivationRepository {
|
||||
|
|
@ -194,7 +194,7 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor(
|
|||
}
|
||||
|
||||
val authTokens = visaAuthTokenStorage.get(visaCardId.cardId) ?: error("Auth tokens are not stored")
|
||||
val newTokens = visaAuthRepository.refreshAccessTokens(authTokens.refreshToken).getOrElse {
|
||||
val newTokens = visaAuthRemoteDataSource.refreshAccessTokens(authTokens.refreshToken).getOrElse {
|
||||
return Either.Left(VisaApiError.RefreshTokenExpired)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,17 +13,16 @@ import com.tangem.domain.visa.model.VisaAuthChallenge
|
|||
import com.tangem.domain.visa.model.VisaAuthSession
|
||||
import com.tangem.domain.visa.model.VisaAuthSignedChallenge
|
||||
import com.tangem.domain.visa.model.VisaAuthTokens
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.domain.visa.datasource.VisaAuthRemoteDataSource
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class DefaultVisaAuthRepository @Inject constructor(
|
||||
internal class DefaultVisaAuthRemoteDataSource @Inject constructor(
|
||||
@NetworkMoshi private val moshi: Moshi,
|
||||
private val visaAuthApi: TangemPayApi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : VisaAuthRepository {
|
||||
) : VisaAuthRemoteDataSource {
|
||||
|
||||
private val visaErrorAdapter = VisaErrorResponseJsonAdapter(moshi)
|
||||
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.data.visa.di
|
||||
|
||||
import com.tangem.data.pay.datasource.DefaultTangemPayAuthDataSource
|
||||
import com.tangem.data.visa.DefaultVisaActivationRepository
|
||||
import com.tangem.data.visa.DefaultVisaAuthRepository
|
||||
import com.tangem.data.visa.DefaultVisaAuthRemoteDataSource
|
||||
import com.tangem.data.visa.MockVisaRepository
|
||||
import com.tangem.domain.pay.datasource.TangemPayAuthDataSource
|
||||
import com.tangem.domain.visa.repository.VisaActivationRepository
|
||||
import com.tangem.domain.visa.repository.VisaAuthRepository
|
||||
import com.tangem.domain.visa.datasource.VisaAuthRemoteDataSource
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
|
@ -18,7 +20,7 @@ internal interface VisaDataModule {
|
|||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindVisaAuthRepository(repository: DefaultVisaAuthRepository): VisaAuthRepository
|
||||
fun bindVisaAuthRemoteDataSource(repository: DefaultVisaAuthRemoteDataSource): VisaAuthRemoteDataSource
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
|
|
@ -39,4 +41,8 @@ internal interface VisaDataModule {
|
|||
// Mocked
|
||||
@Binds
|
||||
fun bindVisaRepository(repository: MockVisaRepository): VisaRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemPayAuthDataSource(repository: DefaultTangemPayAuthDataSource): TangemPayAuthDataSource
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue