Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-22 11:52:10 +03:00
parent cb23c1dea3
commit 538757a7ce
54 changed files with 622 additions and 488 deletions

View file

@ -15,7 +15,7 @@ internal class TangemVisa(
private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
environment = ApiEnvironment.PROD,
baseUrl = "https://bff.tangem.com/",
baseUrl = "[REDACTED_ENV_URL]",
headers = createHeaders(),
)

View file

@ -15,7 +15,7 @@ internal class TangemVisaAuth(
private fun createStageEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
environment = ApiEnvironment.STAGE,
baseUrl = "https://api-s.tangem.org/",
baseUrl = "[REDACTED_ENV_URL]",
headers = createHeaders(),
)

View file

@ -1,9 +1,11 @@
package com.tangem.datasource.api.visa
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.utils.ReadTimeout
import com.tangem.datasource.api.visa.models.request.ActivationByCardWalletRequest
import com.tangem.datasource.api.visa.models.request.ActivationByCustomerWalletRequest
import com.tangem.datasource.api.visa.models.request.ActivationStatusRequest
import com.tangem.datasource.api.visa.models.request.GetCardWalletAcceptanceRequest
import com.tangem.datasource.api.visa.models.request.GetCustomerWalletAcceptanceRequest
import com.tangem.datasource.api.visa.models.request.SetPinCodeRequest
import com.tangem.datasource.api.visa.models.response.*
import retrofit2.http.Body
@ -11,60 +13,40 @@ import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
interface TangemVisaApi {
@GET("product_instance/activation_status")
@POST("v1/activation/status")
suspend fun getRemoteActivationStatus(
@Header("Authorization") authHeader: String,
@Query("customer_id") customerId: String,
@Query("product_instance_id") productInstanceId: String,
@Query("card_id") cardId: String,
@Query("card_public_key") cardPublicKey: String,
@Body request: ActivationStatusRequest,
): ApiResponse<CardActivationRemoteStateResponse>
@ReadTimeout(duration = 20, TimeUnit.MINUTES)
@GET("product_instance/activation_status")
suspend fun getRemoteActivationStatusLongPoll(
@Header("Authorization") authHeader: String,
@Query("customer_id") customerId: String,
@Query("product_instance_id") productInstanceId: String,
@Query("card_id") cardId: String,
@Query("card_public_key") cardPublicKey: String,
): ApiResponse<CardActivationRemoteStateResponse>
@GET("product_instance/card_wallet_acceptance")
@POST("v1/activation/acceptance/message")
suspend fun getCardWalletAcceptance(
@Header("Authorization") authHeader: String,
@Query("customer_id") customerId: String,
@Query("product_instance_id") productInstanceId: String,
@Query("activation_order") activationOrderId: String,
@Query("customer_wallet_address") customerWalletAddress: String,
): ApiResponse<CardWalletDataToSignResponse>
@Body request: GetCardWalletAcceptanceRequest,
): ApiResponse<VisaDataToSignResponse>
@GET("product_instance/customer_wallet_acceptance")
@POST("v1/activation/acceptance/message")
suspend fun getCustomerWalletAcceptance(
@Header("Authorization") authHeader: String,
@Query("customer_id") customerId: String,
@Query("product_instance_id") productInstanceId: String,
@Query("activation_order") activationOrderId: String,
@Query("card_wallet_address") cardWalletAddress: String,
): ApiResponse<CustomerWalletDataToSignResponse>
@Body request: GetCustomerWalletAcceptanceRequest,
): ApiResponse<VisaDataToSignResponse>
@POST("product_instance/activation_by_card_wallet")
@POST("v1/activation/data")
suspend fun activateByCardWallet(
@Header("Authorization") authHeader: String,
@Body body: ActivationByCardWalletRequest,
): ApiResponse<Unit>
@POST("product_instance/activation_by_customer_wallet")
@POST("v1/activation/data")
suspend fun activateByCustomerWallet(
@Header("Authorization") authHeader: String,
@Body body: ActivationByCustomerWalletRequest,
): ApiResponse<Unit>
@POST("product_instance/issuer_activation")
@POST("v1/activation/pin")
suspend fun setPinCode(
@Header("Authorization") authHeader: String,
@Body body: SetPinCodeRequest,

View file

@ -1,32 +1,29 @@
package com.tangem.datasource.api.visa
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.visa.models.request.*
import com.tangem.datasource.api.visa.models.response.GenerateNonceResponse
import com.tangem.datasource.api.visa.models.response.JWTResponse
import retrofit2.http.Field
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Query
interface TangemVisaAuthApi {
@POST("auth/card_wallet")
suspend fun generateNonceByWalletAddress(
@Query("card_wallet_address") cardWalletAddress: String,
): GenerateNonceResponse
@POST("v1/auth/challenge")
suspend fun generateNonceByCardId(@Body request: GenerateNoneByCardIdRequest): GenerateNonceResponse
@POST("auth/card_id")
suspend fun generateNonceByCard(
@Query("card_id") cardId: String,
@Query("card_public_key") cardPublicKey: String,
): GenerateNonceResponse
@POST("v1/auth/challenge")
suspend fun generateNonceByCardWallet(@Body request: GenerateNoneByCardWalletRequest): GenerateNonceResponse
@POST("auth/get_token")
suspend fun getAccessToken(
@Query("session_id") sessionId: String,
@Query("signature") signature: String,
@Query("salt") salt: String?,
): JWTResponse
@POST("v1/auth/token")
suspend fun getAccessTokenByCardId(@Body request: GetAccessTokenByCardIdRequest): JWTResponse
@POST("auth/refresh_token")
suspend fun refreshAccessToken(@Field("refresh_token") refreshToken: String): ApiResponse<JWTResponse>
@POST("v1/auth/token")
suspend fun getAccessTokenByCardWallet(@Body request: GetAccessTokenByCardWalletRequest): JWTResponse
@POST("v1/auth/token/refresh")
suspend fun refreshCardIdAccessToken(@Body request: RefreshTokenByCardIdRequest): ApiResponse<JWTResponse>
@POST("v1/auth/token/refresh")
suspend fun refreshCardWalletAccessToken(@Body request: RefreshTokenByCardWalletRequest): ApiResponse<JWTResponse>
}

View file

@ -5,22 +5,15 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ActivationByCardWalletRequest(
@Json(name = "customer_id") val customerId: String,
@Json(name = "product_instance_id") val productInstanceId: String,
@Json(name = "activation_order_id") val activationOrderId: String,
@Json(name = "data") val data: Data,
@Json(name = "order_id") val orderId: String,
@Json(name = "card_wallet") val cardWallet: CardWallet,
@Json(name = "deploy_acceptance_signature") val deployAcceptanceSignature: String,
@Json(name = "otp") val otp: Otp,
) {
@JsonClass(generateAdapter = true)
data class Data(
@Json(name = "card_wallet") val cardWallet: CardWallet,
@Json(name = "otp") val otp: Otp,
)
@JsonClass(generateAdapter = true)
data class CardWallet(
@Json(name = "address") val address: String,
@Json(name = "card_wallet_confirmation") val cardWalletConfirmation: CardWalletConfirmation?,
@Json(name = "deploy_acceptance_signature") val deployAcceptanceSignature: String,
)
@JsonClass(generateAdapter = true)

View file

@ -5,19 +5,12 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ActivationByCustomerWalletRequest(
@Json(name = "customer_id") val customerId: String,
@Json(name = "product_instance_id") val productInstanceId: String,
@Json(name = "activation_order_id") val activationOrderId: String,
@Json(name = "data") val data: Data,
@Json(name = "order_id") val orderId: String,
@Json(name = "customer_wallet") val customerWallet: CustomerWallet,
) {
@JsonClass(generateAdapter = true)
data class Data(
@Json(name = "customer_wallet") val customerWallet: CustomerWallet,
)
@JsonClass(generateAdapter = true)
data class CustomerWallet(
@Json(name = "address") val address: String,
@Json(name = "deploy_acceptance_signature") val deployAcceptanceSignature: String,
@Json(name = "address") val customerWalletAddress: String,
)
}

View file

@ -0,0 +1,10 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ActivationStatusRequest(
@Json(name = "card_id") val cardId: String,
@Json(name = "card_public_key") val cardPublicKey: String,
)

View file

@ -0,0 +1,11 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GenerateNoneByCardIdRequest(
@Json(name = "auth_type") val authType: String = "card_id",
@Json(name = "card_id") val cardId: String,
@Json(name = "card_public_key") val cardPublicKey: String,
)

View file

@ -0,0 +1,10 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GenerateNoneByCardWalletRequest(
@Json(name = "auth_type") val authType: String = "card_wallet",
@Json(name = "card_wallet_address") val cardWalletAddress: String,
)

View file

@ -0,0 +1,12 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GetAccessTokenByCardIdRequest(
@Json(name = "auth_type") val authType: String = "card_id",
@Json(name = "session_id") val sessionId: String,
@Json(name = "signature") val signature: String,
@Json(name = "salt") val salt: String,
)

View file

@ -0,0 +1,11 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GetAccessTokenByCardWalletRequest(
@Json(name = "auth_type") val authType: String = "card_wallet",
@Json(name = "session_id") val sessionId: String,
@Json(name = "signature") val signature: String,
)

View file

@ -0,0 +1,11 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GetCardWalletAcceptanceRequest(
@Json(name = "type") val type: String = "card_wallet",
@Json(name = "customer_wallet_address") val customerWalletAddress: String,
@Json(name = "card_wallet_address") val cardWalletAddress: String,
)

View file

@ -0,0 +1,11 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GetCustomerWalletAcceptanceRequest(
@Json(name = "type") val type: String = "customer_wallet",
@Json(name = "customer_wallet_address") val customerWalletAddress: String,
@Json(name = "card_wallet_address") val cardWalletAddress: String,
)

View file

@ -0,0 +1,10 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class RefreshTokenByCardIdRequest(
@Json(name = "auth_type") val authType: String = "card_id",
@Json(name = "refresh_token") val refreshToken: String,
)

View file

@ -0,0 +1,10 @@
package com.tangem.datasource.api.visa.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class RefreshTokenByCardWalletRequest(
@Json(name = "auth_type") val authType: String = "card_wallet",
@Json(name = "refresh_token") val refreshToken: String,
)

View file

@ -5,14 +5,8 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class SetPinCodeRequest(
@Json(name = "customer_id") val customerId: String,
@Json(name = "activation_order_id") val activationOrderId: String,
@Json(name = "product_instance_id") val productInstanceId: String,
@Json(name = "data") val data: Data,
) {
data class Data(
@Json(name = "session_key") val sessionKey: String,
@Json(name = "iv") val iv: String,
@Json(name = "encrypted_pin") val encryptedPin: String,
)
}
@Json(name = "order_id") val orderId: String,
@Json(name = "session_id") val sessionId: String,
@Json(name = "iv") val iv: String,
@Json(name = "pin") val pin: String,
)

View file

@ -5,15 +5,21 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class CardActivationRemoteStateResponse(
@Json(name = "activation_status") val status: String,
@Json(name = "activation_order") val activationOrder: ActivationOrder?,
@Json(name = "stepChangeCode") val stepChangeCode: Int?,
@Json(name = "updatedAt") val updatedAt: String?,
@Json(name = "result") val result: Result,
) {
@JsonClass(generateAdapter = true)
data class Result(
@Json(name = "status") val status: String,
@Json(name = "order") val activationOrder: ActivationOrder?,
@Json(name = "stepChangeCode") val stepChangeCode: Int?,
@Json(name = "updatedAt") val updatedAt: String?,
)
@JsonClass(generateAdapter = true)
data class ActivationOrder(
@Json(name = "id") val id: String,
@Json(name = "customer_id") val customerId: String,
@Json(name = "customer_wallet_address") val customerWalletAddress: String,
@Json(name = "card_wallet_address") val cardWalletAddress: String,
)
}

View file

@ -1,14 +0,0 @@
package com.tangem.datasource.api.visa.models.response
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class CustomerWalletDataToSignResponse(
@Json(name = "data_for_customer_wallet") val dataForCardWallet: Data,
) {
@JsonClass(generateAdapter = true)
data class Data(
@Json(name = "hash") val hash: String,
)
}

View file

@ -5,6 +5,11 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GenerateNonceResponse(
@Json(name = "nonce") val nonce: String,
@Json(name = "session_id") val sessionId: String,
)
@Json(name = "result") val result: Result,
) {
@JsonClass(generateAdapter = true)
data class Result(
@Json(name = "nonce") val nonce: String,
@Json(name = "session_id") val sessionId: String,
)
}

View file

@ -5,12 +5,17 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class JWTResponse(
@Json(name = "access_token") val accessToken: String,
@Json(name = "expires_in") val expiresIn: Int,
@Json(name = "refresh_expires_in") val refreshExpiresIn: Int,
@Json(name = "refresh_token") val refreshToken: String,
@Json(name = "token_type") val tokenType: String,
@Json(name = "not-before-policy") val notBeforePolicy: Int,
@Json(name = "session_state") val sessionState: String,
@Json(name = "scope") val scope: String,
)
@Json(name = "result") val result: Result,
) {
@JsonClass(generateAdapter = true)
data class Result(
@Json(name = "access_token") val accessToken: String,
@Json(name = "expires_in") val expiresIn: Int,
@Json(name = "refresh_expires_in") val refreshExpiresIn: Int,
@Json(name = "refresh_token") val refreshToken: String,
@Json(name = "token_type") val tokenType: String,
@Json(name = "not-before-policy") val notBeforePolicy: Int,
@Json(name = "session_state") val sessionState: String,
@Json(name = "scope") val scope: String,
)
}

View file

@ -4,11 +4,11 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class CardWalletDataToSignResponse(
@Json(name = "dataForCardWallet") val dataForCardWallet: Data,
data class VisaDataToSignResponse(
@Json(name = "result") val result: Result,
) {
@JsonClass(generateAdapter = true)
data class Data(
data class Result(
@Json(name = "hash") val hash: String,
)
}

View file

@ -186,7 +186,7 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
id = ApiConfig.ID.TangemVisaAuth,
expected = ApiEnvironmentConfig(
environment = ApiEnvironment.STAGE,
baseUrl = "https://api-s.tangem.org/",
baseUrl = "[REDACTED_ENV_URL]",
headers = mapOf(
"version" to ProviderSuspend { VERSION_NAME },
"platform" to ProviderSuspend { "Android" },
@ -200,7 +200,7 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
id = ApiConfig.ID.TangemVisa,
expected = ApiEnvironmentConfig(
environment = ApiEnvironment.PROD,
baseUrl = "https://bff.tangem.com/",
baseUrl = "[REDACTED_ENV_URL]",
headers = mapOf(
"version" to ProviderSuspend { VERSION_NAME },
"platform" to ProviderSuspend { "Android" },