diff --git a/financial-connections/build.gradle b/financial-connections/build.gradle index a4000f3b55f..a72d929a7ec 100644 --- a/financial-connections/build.gradle +++ b/financial-connections/build.gradle @@ -23,6 +23,7 @@ dependencies { api project(":stripe-core") api project(":stripe-ui-core") api project(":payments-model") + implementation project(":stripe-attestation") implementation libs.androidx.activity implementation libs.androidx.annotation diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt index 4c32eb7c616..071b07291e1 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt @@ -21,6 +21,7 @@ import com.stripe.android.financialconnections.FinancialConnectionsSheetViewEffe import com.stripe.android.financialconnections.FinancialConnectionsSheetViewEffect.OpenAuthFlowWithUrl import com.stripe.android.financialconnections.FinancialConnectionsSheetViewEffect.OpenNativeAuthFlow import com.stripe.android.financialconnections.FinancialConnectionsSheetViewModel.Companion.QUERY_PARAM_PAYMENT_METHOD +import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.ErrorCode import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Metadata @@ -58,6 +59,7 @@ import com.stripe.android.financialconnections.navigation.topappbar.TopAppBarSta import com.stripe.android.financialconnections.presentation.FinancialConnectionsViewModel import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.financialconnections.utils.parcelable +import com.stripe.attestation.IntegrityRequestManager import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -68,6 +70,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( @Named(APPLICATION_ID) private val applicationId: String, savedStateHandle: SavedStateHandle, private val getOrFetchSync: GetOrFetchSync, + private val integrityRequestManager: IntegrityRequestManager, private val fetchFinancialConnectionsSession: FetchFinancialConnectionsSession, private val fetchFinancialConnectionsSessionForToken: FetchFinancialConnectionsSessionForToken, private val logger: Logger, @@ -111,6 +114,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( private fun fetchManifest() { viewModelScope.launch { kotlin.runCatching { + prepareStandardRequestManager() getOrFetchSync(refetchCondition = Always) }.onFailure { finishWithResult(stateFlow.value, Failed(it)) @@ -120,6 +124,20 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( } } + private suspend fun prepareStandardRequestManager(): Boolean { + val result = runCatching { integrityRequestManager.prepare() } + result.exceptionOrNull()?.let { + analyticsTracker.track( + FinancialConnectionsAnalyticsEvent.Error( + extraMessage = "Failed to warm up the IntegrityStandardRequestManager", + pane = Pane.CONSENT, + exception = it + ) + ) + } + return result.isSuccess + } + /** * Builds the ChromeCustomTab intent to launch the hosted auth flow and launches it. * diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 8cfcec85202..6467d10bf47 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -34,6 +34,7 @@ import com.stripe.android.financialconnections.utils.Experiment.CONNECTIONS_CONS import com.stripe.android.financialconnections.utils.error import com.stripe.android.financialconnections.utils.experimentAssignment import com.stripe.android.financialconnections.utils.trackExposure +import com.stripe.attestation.IntegrityRequestManager import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -44,6 +45,7 @@ internal class ConsentViewModel @AssistedInject constructor( @Assisted initialState: ConsentState, nativeAuthFlowCoordinator: NativeAuthFlowCoordinator, private val acceptConsent: AcceptConsent, + private val integrityRequestManager: IntegrityRequestManager, private val getOrFetchSync: GetOrFetchSync, private val navigationManager: NavigationManager, private val eventTracker: FinancialConnectionsAnalyticsTracker, @@ -53,6 +55,11 @@ internal class ConsentViewModel @AssistedInject constructor( ) : FinancialConnectionsViewModel(initialState, nativeAuthFlowCoordinator) { init { + viewModelScope.launch { + integrityRequestManager.requestToken() + .onSuccess { logger.debug("Integrity token: $it") } + .onFailure { logger.error("Failed to get integrity token", it) } + } logErrors() suspend { val sync = getOrFetchSync() diff --git a/stripe-attestation/src/main/java/com/stripe/attestation/IntegrityStandardRequestManager.kt b/stripe-attestation/src/main/java/com/stripe/attestation/IntegrityStandardRequestManager.kt index 415eb4b8952..2d7cd5b8ae0 100644 --- a/stripe-attestation/src/main/java/com/stripe/attestation/IntegrityStandardRequestManager.kt +++ b/stripe-attestation/src/main/java/com/stripe/attestation/IntegrityStandardRequestManager.kt @@ -40,6 +40,10 @@ class IntegrityStandardRequestManager( private var integrityTokenProvider: StandardIntegrityTokenProvider? = null override suspend fun prepare(): Result = runCatching { + if (integrityTokenProvider != null) { + return Result.success(Unit) + } + val finishedTask: Task = standardIntegrityManager .prepareIntegrityToken( PrepareIntegrityTokenRequest.builder()