Updated on 2026-08-14
This commit is contained in:
parent
c9fca04205
commit
80ca0095f1
11 changed files with 83 additions and 46 deletions
|
|
@ -15,6 +15,7 @@ import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
|||
import com.tangem.crypto.bip39.Wordlist
|
||||
import com.tangem.data.card.sdk.CardSdkOwner
|
||||
import com.tangem.data.card.sdk.CardSdkProvider
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironmentConfig
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
|
|
@ -28,6 +29,7 @@ import com.tangem.sdk.nfc.AndroidNfcAvailabilityProvider
|
|||
import com.tangem.sdk.nfc.NfcManager
|
||||
import com.tangem.sdk.storage.create
|
||||
import com.tangem.tap.foregroundActivityObserver
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
|
|
@ -48,6 +50,7 @@ internal class DefaultCardSdkProvider @Inject constructor(
|
|||
private val apiConfigsManager: ApiConfigsManager,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
appInfoProvider: AppInfoProvider,
|
||||
authProvider: AuthProvider,
|
||||
) : CardSdkProvider, CardSdkOwner {
|
||||
|
||||
private val observer = Observer()
|
||||
|
|
@ -68,13 +71,16 @@ internal class DefaultCardSdkProvider @Inject constructor(
|
|||
},
|
||||
)
|
||||
|
||||
val apiEnvironment = Provider {
|
||||
apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemTech).environment
|
||||
}
|
||||
val platformHeaders = RequestHeader.AppVersionPlatformHeaders(
|
||||
appVersionProvider = appVersionProvider,
|
||||
appInfoProvider = appInfoProvider,
|
||||
)
|
||||
val apiKeyHeader = RequestHeader.TangemApiKeyHeader(authProvider, apiEnvironment)
|
||||
TangemApiServiceSettings.addInterceptors(
|
||||
AddHeadersInterceptor(
|
||||
requestHeader = RequestHeader.AppVersionPlatformHeaders(
|
||||
appVersionProvider = appVersionProvider,
|
||||
appInfoProvider = appInfoProvider,
|
||||
),
|
||||
),
|
||||
AddHeadersInterceptor(platformHeaders.values + apiKeyHeader.values),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,19 @@ package com.tangem.tap.network.auth
|
|||
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
|
||||
internal class DefaultAuthProvider(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val shouldUseNewListRepository: Boolean = false,
|
||||
private val environmentConfigStorage: EnvironmentConfigStorage,
|
||||
) : AuthProvider {
|
||||
|
||||
override suspend fun getCardPublicKey(): String {
|
||||
|
|
@ -38,6 +43,20 @@ internal class DefaultAuthProvider(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getApiKey(apiEnvironment: Provider<ApiEnvironment>): ProviderSuspend<String> {
|
||||
return ProviderSuspend {
|
||||
when (apiEnvironment.invoke()) {
|
||||
ApiEnvironment.MOCK,
|
||||
ApiEnvironment.DEV,
|
||||
ApiEnvironment.DEV_2,
|
||||
ApiEnvironment.DEV_3,
|
||||
-> environmentConfigStorage.getConfigSync().tangemApiKeyDev
|
||||
ApiEnvironment.STAGE -> environmentConfigStorage.getConfigSync().tangemApiKeyStage
|
||||
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().tangemApiKey
|
||||
} ?: error("No tangem tech api config provided")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getWallets(): List<UserWallet> {
|
||||
return if (shouldUseNewListRepository) {
|
||||
userWalletsListRepository.userWalletsSync()
|
||||
|
|
|
|||
|
|
@ -28,11 +28,13 @@ internal class AuthModule {
|
|||
userWalletsListManager: UserWalletsListManager,
|
||||
userWalletsListRepository: UserWalletsListRepository,
|
||||
hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
environmentConfigStorage: EnvironmentConfigStorage,
|
||||
): AuthProvider {
|
||||
return DefaultAuthProvider(
|
||||
userWalletsListManager = userWalletsListManager,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
shouldUseNewListRepository = hotWalletFeatureToggles.isHotWalletEnabled,
|
||||
environmentConfigStorage = environmentConfigStorage,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package com.tangem.datasource.api.common
|
||||
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
|
||||
/**
|
||||
* Provides auth for tangemTech API
|
||||
*/
|
||||
|
|
@ -12,6 +16,8 @@ interface AuthProvider {
|
|||
|
||||
suspend fun getCardId(): String
|
||||
|
||||
fun getApiKey(apiEnvironment: Provider<ApiEnvironment>): ProviderSuspend<String>
|
||||
|
||||
/**
|
||||
* Returns map where keys(cardId) associated with cardPublicKey
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2,15 +2,13 @@ package com.tangem.datasource.api.common.config
|
|||
|
||||
import com.tangem.datasource.BuildConfig
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
|
||||
import com.tangem.datasource.utils.RequestHeader
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
|
||||
/** TangemTech [ApiConfig] */
|
||||
internal class TangemTech(
|
||||
private val environmentConfigStorage: EnvironmentConfigStorage,
|
||||
private val appVersionProvider: AppVersionProvider,
|
||||
private val authProvider: AuthProvider,
|
||||
private val appInfoProvider: AppInfoProvider,
|
||||
|
|
@ -63,20 +61,8 @@ internal class TangemTech(
|
|||
)
|
||||
|
||||
private fun createHeaders(apiEnvironment: ApiEnvironment) = buildMap {
|
||||
put(key = "api-key", value = ProviderSuspend { getApiKey(apiEnvironment) })
|
||||
putAll(from = RequestHeader.TangemApiKeyHeader(authProvider, Provider { apiEnvironment }).values)
|
||||
putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values)
|
||||
putAll(from = RequestHeader.AuthenticationHeader(authProvider).values)
|
||||
}
|
||||
|
||||
private fun getApiKey(apiEnvironment: ApiEnvironment): String {
|
||||
return when (apiEnvironment) {
|
||||
ApiEnvironment.MOCK,
|
||||
ApiEnvironment.DEV,
|
||||
ApiEnvironment.DEV_2,
|
||||
ApiEnvironment.DEV_3,
|
||||
-> environmentConfigStorage.getConfigSync().tangemApiKeyDev
|
||||
ApiEnvironment.STAGE -> environmentConfigStorage.getConfigSync().tangemApiKeyStage
|
||||
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().tangemApiKey
|
||||
} ?: error("No tangem tech api config provided")
|
||||
}
|
||||
}
|
||||
|
|
@ -42,12 +42,10 @@ internal object ApiConfigsModule {
|
|||
@Provides
|
||||
@IntoSet
|
||||
fun provideTangemTechConfig(
|
||||
environmentConfigStorage: EnvironmentConfigStorage,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
authProvider: AuthProvider,
|
||||
appInfoProvider: AppInfoProvider,
|
||||
): ApiConfig = TangemTech(
|
||||
environmentConfigStorage = environmentConfigStorage,
|
||||
appVersionProvider = appVersionProvider,
|
||||
authProvider = authProvider,
|
||||
appInfoProvider = appInfoProvider,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.datasource.utils
|
||||
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
|
@ -12,21 +13,17 @@ import okhttp3.Response
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class AddHeadersInterceptor(
|
||||
private val requestHeaders: Set<RequestHeader>,
|
||||
private val requestHeaders: Map<String, ProviderSuspend<String>>,
|
||||
) : Interceptor {
|
||||
|
||||
constructor(requestHeader: RequestHeader) : this(requestHeaders = setOf(requestHeader))
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val requestBuilder = chain.request().newBuilder()
|
||||
|
||||
requestHeaders
|
||||
.flatMap { it.values.toList() }
|
||||
.forEach { (name, valueProvider) ->
|
||||
val value = runBlocking { valueProvider() }
|
||||
requestHeaders.forEach { (name, valueProvider) ->
|
||||
val value = runBlocking { valueProvider() }
|
||||
|
||||
requestBuilder.addHeader(name = name, value = value)
|
||||
}
|
||||
requestBuilder.addHeader(name = name, value = value)
|
||||
}
|
||||
|
||||
val request = requestBuilder.build()
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,6 @@ import kotlinx.coroutines.runBlocking
|
|||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
/** Extension for adding headers [requestHeaders] to every [OkHttpClient] request */
|
||||
internal fun OkHttpClient.Builder.addHeaders(vararg requestHeaders: RequestHeader): OkHttpClient.Builder {
|
||||
return addInterceptor(
|
||||
interceptor = AddHeadersInterceptor(requestHeaders = requestHeaders.toSet()),
|
||||
)
|
||||
}
|
||||
|
||||
/** Extension for adding headers [requestHeaders] to every [OkHttpClient] request */
|
||||
internal fun OkHttpClient.Builder.addHeaders(
|
||||
requestHeaders: Map<String, ProviderSuspend<String>>,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package com.tangem.datasource.utils
|
|||
|
||||
import android.os.Build
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.datasource.utils.RequestHeader.CacheControlHeader.checkHeaderValueOrEmpty
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
|
|
@ -40,6 +42,13 @@ sealed class RequestHeader(vararg pairs: Pair<String, ProviderSuspend<String>>)
|
|||
"device" to ProviderSuspend { "${Build.MANUFACTURER} ${Build.MODEL}".checkHeaderValueOrEmpty() },
|
||||
)
|
||||
|
||||
/**
|
||||
* Use ONLY for tangemApi (not express or yields)
|
||||
*/
|
||||
class TangemApiKeyHeader(authProvider: AuthProvider, apiEnvironment: Provider<ApiEnvironment>) : RequestHeader(
|
||||
"api-key" to authProvider.getApiKey(apiEnvironment),
|
||||
)
|
||||
|
||||
/**
|
||||
* Use it to avoid crash in okhttp headers
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
package com.tangem.datasource.api.common.config
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import timber.log.Timber
|
||||
|
|
@ -12,6 +17,17 @@ import timber.log.Timber
|
|||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class ApiConfigTest {
|
||||
|
||||
private val appAuthProvider = mockk<AuthProvider>()
|
||||
private val apiKeyProvider = mockk<ProviderSuspend<String>>()
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
clearMocks(
|
||||
appAuthProvider,
|
||||
)
|
||||
every { appAuthProvider.getApiKey(any()) } returns apiKeyProvider
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `all baseUrls ends with slash`() {
|
||||
// Arrange
|
||||
|
|
@ -41,15 +57,14 @@ class ApiConfigTest {
|
|||
YieldSupply(
|
||||
environmentConfigStorage = mockk(),
|
||||
appVersionProvider = mockk(),
|
||||
authProvider = mockk(),
|
||||
authProvider = appAuthProvider,
|
||||
appInfoProvider = mockk(),
|
||||
)
|
||||
}
|
||||
ApiConfig.ID.TangemTech -> {
|
||||
TangemTech(
|
||||
environmentConfigStorage = mockk(),
|
||||
appVersionProvider = mockk(),
|
||||
authProvider = mockk(),
|
||||
authProvider = appAuthProvider,
|
||||
appInfoProvider = mockk(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.datasource.api.common.config.ApiConfig.Companion.INTERNAL_BUIL
|
|||
import com.tangem.datasource.api.common.config.ApiConfig.Companion.MOCKED_BUILD_TYPE
|
||||
import com.tangem.datasource.api.common.config.ApiConfig.Companion.RELEASE_BUILD_TYPE
|
||||
import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.BLOCK_AID_API_KEY
|
||||
import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.TANGEM_API_KEY
|
||||
import com.tangem.lib.auth.ExpressAuthProvider
|
||||
import com.tangem.lib.auth.StakeKitAuthProvider
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
|
|
@ -40,8 +41,9 @@ internal class ProdApiConfigsManagerTest {
|
|||
private val stakeKitAuthProvider = mockk<StakeKitAuthProvider>()
|
||||
private val appAuthProvider = mockk<AuthProvider>()
|
||||
private val appInfoProvider = mockk<AppInfoProvider>()
|
||||
private val tangemApiKeyProvider = mockk<ProviderSuspend<String>>()
|
||||
|
||||
private val manager = ProdApiConfigsManager(apiConfigs = createApiConfigs())
|
||||
private lateinit var manager: ProdApiConfigsManager
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
|
|
@ -56,9 +58,14 @@ internal class ProdApiConfigsManagerTest {
|
|||
every { appVersionProvider.versionName } returns VERSION_NAME
|
||||
every { expressAuthProvider.getSessionId() } returns EXPRESS_SESSION_ID
|
||||
every { stakeKitAuthProvider.getApiKey() } returns STAKE_KIT_API_KEY
|
||||
every { appAuthProvider.getApiKey(any()) } returns tangemApiKeyProvider
|
||||
coEvery { tangemApiKeyProvider.invoke() } returns TANGEM_API_KEY
|
||||
coEvery { appAuthProvider.getCardId() } returns APP_CARD_ID
|
||||
coEvery { appAuthProvider.getCardPublicKey() } returns APP_CARD_PUBLIC_KEY
|
||||
|
||||
every { appInfoProvider.osVersion } returns "Android 16"
|
||||
|
||||
manager = ProdApiConfigsManager(apiConfigs = createApiConfigs())
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
|
@ -94,7 +101,6 @@ internal class ProdApiConfigsManagerTest {
|
|||
}
|
||||
ApiConfig.ID.TangemTech -> {
|
||||
TangemTech(
|
||||
environmentConfigStorage = environmentConfigStorage,
|
||||
appVersionProvider = appVersionProvider,
|
||||
authProvider = appAuthProvider,
|
||||
appInfoProvider = appInfoProvider,
|
||||
|
|
@ -175,7 +181,7 @@ internal class ProdApiConfigsManagerTest {
|
|||
environment = ApiEnvironment.PROD,
|
||||
baseUrl = "https://api.tangem.org/",
|
||||
headers = mapOf(
|
||||
"api-key" to ProviderSuspend { MockEnvironmentConfigStorage.TANGEM_API_KEY },
|
||||
"api-key" to ProviderSuspend { TANGEM_API_KEY },
|
||||
"card_id" to ProviderSuspend { APP_CARD_ID },
|
||||
"card_public_key" to ProviderSuspend { APP_CARD_PUBLIC_KEY },
|
||||
"version" to ProviderSuspend { VERSION_NAME },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue