diff --git a/.idea/codestyles/Project.xml b/.idea/codestyles/Project.xml
index aa7276802a9..90ee029868b 100644
--- a/.idea/codestyles/Project.xml
+++ b/.idea/codestyles/Project.xml
@@ -32,8 +32,6 @@
-
-
@@ -160,4 +158,4 @@
-
+
\ No newline at end of file
diff --git a/financial-connections-example/src/main/java/com/stripe/android/financialconnections/example/FinancialConnectionsPlaygroundViewModel.kt b/financial-connections-example/src/main/java/com/stripe/android/financialconnections/example/FinancialConnectionsPlaygroundViewModel.kt
index a63255e0bfb..77dda6e7678 100644
--- a/financial-connections-example/src/main/java/com/stripe/android/financialconnections/example/FinancialConnectionsPlaygroundViewModel.kt
+++ b/financial-connections-example/src/main/java/com/stripe/android/financialconnections/example/FinancialConnectionsPlaygroundViewModel.kt
@@ -442,9 +442,7 @@ enum class Merchant(
Networking("networking"),
LiveTesting("live_testing", canSwitchBetweenTestAndLive = false),
TestMode("testmode", canSwitchBetweenTestAndLive = false),
- NmeDefaultVerification("nme", canSwitchBetweenTestAndLive = true),
- NmeABAVVerification("nme_abav", canSwitchBetweenTestAndLive = true),
- NmeSkipVerification("nme_skip", canSwitchBetweenTestAndLive = true),
+ Trusted("trusted", canSwitchBetweenTestAndLive = false),
Custom("other");
companion object {
diff --git a/financial-connections/detekt-baseline.xml b/financial-connections/detekt-baseline.xml
index 9a70a986a90..2ec88779b7f 100644
--- a/financial-connections/detekt-baseline.xml
+++ b/financial-connections/detekt-baseline.xml
@@ -8,6 +8,7 @@
LongMethod:AccountItem.kt$@Composable @Preview internal fun AccountItemPreview()
LongMethod:Button.kt$@Composable internal fun FinancialConnectionsButton( onClick: () -> Unit, modifier: Modifier = Modifier, type: Type = Primary, size: FinancialConnectionsButton.Size = FinancialConnectionsButton.Size.Regular, enabled: Boolean = true, loading: Boolean = false, content: @Composable (RowScope.() -> Unit) )
LongMethod:FinancialConnectionsSheetNativeActivity.kt$FinancialConnectionsSheetNativeActivity$@Composable fun NavHost( initialPane: Pane, testMode: Boolean, )
+ LongMethod:FinancialConnectionsSheetNativeViewModel.kt$FinancialConnectionsSheetNativeViewModel$private fun closeAuthFlow( earlyTerminationCause: EarlyTerminationCause? = null, closeAuthFlowError: Throwable? = null )
LongMethod:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Async<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit )
LongMethod:LinkAccountPickerPreviewParameterProvider.kt$LinkAccountPickerPreviewParameterProvider$private fun partnerAccountList()
LongMethod:NetworkingSaveToLinkVerificationScreen.kt$@Composable private fun NetworkingSaveToLinkVerificationLoaded( confirmVerificationAsync: Async<Unit>, payload: Payload, onCloseFromErrorClick: (Throwable) -> Unit, onSkipClick: () -> Unit, )
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 01146f0a3df..06a7d9d0cfd 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
@@ -40,6 +40,7 @@ import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator
import com.stripe.android.financialconnections.domain.NativeAuthFlowRouter
import com.stripe.android.financialconnections.exception.AppInitializationError
import com.stripe.android.financialconnections.exception.CustomManualEntryRequiredError
+import com.stripe.android.financialconnections.features.error.isAttestationError
import com.stripe.android.financialconnections.features.manualentry.isCustomManualEntryError
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs.ForData
@@ -521,6 +522,10 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor(
fromNative: Boolean = false,
@StringRes finishMessage: Int? = null,
) {
+ if (result is Failed && result.error.isAttestationError()) {
+ switchToWebFlow()
+ return
+ }
eventReporter.onResult(state.initialArgs.configuration, result)
// Native emits its own events before finishing.
if (fromNative.not()) {
@@ -536,6 +541,27 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor(
setState { copy(viewEffect = FinishWithResult(result, finishMessage)) }
}
+ /**
+ * On scenarios where native failed mid flow due to attestation errors, switch back to web flow.
+ */
+ private fun switchToWebFlow() {
+ viewModelScope.launch {
+ val sync = getOrFetchSync()
+ val hostedAuthUrl = HostedAuthUrlBuilder.create(
+ args = initialState.initialArgs,
+ manifest = sync.manifest,
+ )!!
+ setState {
+ copy(
+ manifest = manifest,
+ // Use intermediate state to prevent the flow from closing in [onResume].
+ webAuthFlowStatus = AuthFlowStatus.INTERMEDIATE_DEEPLINK,
+ viewEffect = OpenAuthFlowWithUrl(hostedAuthUrl)
+ )
+ }
+ }
+ }
+
companion object {
val Factory = viewModelFactory {
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/HandleError.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/HandleError.kt
index ffc56b6c0fd..c69a87ee85f 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/HandleError.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/HandleError.kt
@@ -3,10 +3,14 @@ package com.stripe.android.financialconnections.domain
import com.stripe.android.core.Logger
import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker
import com.stripe.android.financialconnections.analytics.logError
+import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator.Message.CloseWithError
+import com.stripe.android.financialconnections.features.error.isAttestationError
import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest
import com.stripe.android.financialconnections.navigation.Destination
import com.stripe.android.financialconnections.navigation.NavigationManager
import com.stripe.android.financialconnections.repository.FinancialConnectionsErrorRepository
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
import javax.inject.Inject
internal interface HandleError {
@@ -21,6 +25,7 @@ internal interface HandleError {
internal class RealHandleError @Inject constructor(
private val errorRepository: FinancialConnectionsErrorRepository,
private val analyticsTracker: FinancialConnectionsAnalyticsTracker,
+ private val nativeAuthFlowCoordinator: NativeAuthFlowCoordinator,
private val logger: Logger,
private val navigationManager: NavigationManager
) : HandleError {
@@ -42,7 +47,7 @@ internal class RealHandleError @Inject constructor(
extraMessage: String,
error: Throwable,
pane: FinancialConnectionsSessionManifest.Pane,
- displayErrorScreen: Boolean
+ displayErrorScreen: Boolean,
) {
analyticsTracker.logError(
extraMessage = extraMessage,
@@ -51,8 +56,14 @@ internal class RealHandleError @Inject constructor(
pane = pane
)
- // Navigate to error screen
- if (displayErrorScreen) {
+ if (error.isAttestationError()) {
+ GlobalScope.launch {
+ nativeAuthFlowCoordinator().emit(
+ value = CloseWithError(cause = error)
+ )
+ }
+ } else if (displayErrorScreen) {
+ // Navigate to error screen
errorRepository.set(error)
navigationManager.tryNavigateTo(route = Destination.Error(referrer = pane))
}
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupAccount.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupAccount.kt
index 1b14c57fa9e..2d4ab3c0e0b 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupAccount.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupAccount.kt
@@ -1,21 +1,38 @@
package com.stripe.android.financialconnections.domain
+import android.app.Application
import com.stripe.android.financialconnections.FinancialConnectionsSheet
import com.stripe.android.financialconnections.repository.FinancialConnectionsConsumerSessionRepository
import com.stripe.android.model.ConsumerSessionLookup
+import com.stripe.attestation.IntegrityRequestManager
import javax.inject.Inject
internal class LookupAccount @Inject constructor(
+ private val application: Application,
+ private val integrityRequestManager: IntegrityRequestManager,
private val consumerSessionRepository: FinancialConnectionsConsumerSessionRepository,
val configuration: FinancialConnectionsSheet.Configuration,
) {
suspend operator fun invoke(
- email: String
- ): ConsumerSessionLookup = requireNotNull(
- consumerSessionRepository.lookupConsumerSession(
- email = email.lowercase().trim(),
- clientSecret = configuration.financialConnectionsSessionClientSecret
- )
- )
+ email: String,
+ verifiedFlow: Boolean
+ ): ConsumerSessionLookup {
+ return if (verifiedFlow) {
+ requireNotNull(
+ consumerSessionRepository.mobileLookupConsumerSession(
+ email = email.lowercase().trim(),
+ verificationToken = integrityRequestManager.requestToken().getOrThrow(),
+ appId = application.packageName
+ )
+ )
+ } else {
+ requireNotNull(
+ consumerSessionRepository.postConsumerSession(
+ email = email.lowercase().trim(),
+ clientSecret = configuration.financialConnectionsSessionClientSecret
+ )
+ )
+ }
+ }
}
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupConsumerAndStartVerification.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupConsumerAndStartVerification.kt
index 4816b09d398..61c13c7094f 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupConsumerAndStartVerification.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/LookupConsumerAndStartVerification.kt
@@ -22,13 +22,14 @@ internal class LookupConsumerAndStartVerification @Inject constructor(
email: String,
businessName: String?,
verificationType: VerificationType,
+ appVerificationEnabled: Boolean,
onConsumerNotFound: suspend () -> Unit,
onLookupError: suspend (Throwable) -> Unit,
onStartVerification: suspend () -> Unit,
onVerificationStarted: suspend (ConsumerSession) -> Unit,
onStartVerificationError: suspend (Throwable) -> Unit
) {
- runCatching { lookupAccount(email) }
+ runCatching { lookupAccount(email, appVerificationEnabled) }
.onSuccess { session ->
if (session.exists) {
onStartVerification()
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorExt.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorExt.kt
new file mode 100644
index 00000000000..7c6cea93f6c
--- /dev/null
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorExt.kt
@@ -0,0 +1,7 @@
+package com.stripe.android.financialconnections.features.error
+
+import com.stripe.android.core.exception.APIException
+
+internal fun Throwable.isAttestationError(): Boolean {
+ return this is APIException && stripeError?.code == "link_failed_to_attest_request"
+}
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt
index b15b00e9fa6..7cfa965f1b9 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt
@@ -30,6 +30,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = false,
+ appVerificationEnabled = false,
content = networkingLinkSignupPane(),
)
),
@@ -49,6 +50,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = false,
+ appVerificationEnabled = false,
content = networkingLinkSignupPane(),
)
),
@@ -74,6 +76,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = false,
+ appVerificationEnabled = false,
content = networkingLinkSignupPane(),
)
),
@@ -99,6 +102,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = true,
+ appVerificationEnabled = false,
content = linkLoginPane(),
)
),
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt
index 2bb6f76bd17..e39f948c903 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt
@@ -103,6 +103,7 @@ internal class NetworkingLinkSignupViewModel @AssistedInject constructor(
NetworkingLinkSignupState.Payload(
content = requireNotNull(content),
merchantName = sync.manifest.getBusinessName(),
+ appVerificationEnabled = sync.manifest.appVerificationEnabled,
emailController = SimpleTextFieldController(
textFieldConfig = EmailConfig(label = R.string.stripe_networking_signup_email_label),
initialValue = sync.manifest.accountholderCustomerEmailAddress ?: prefillDetails?.email,
@@ -195,7 +196,7 @@ internal class NetworkingLinkSignupViewModel @AssistedInject constructor(
/**
* @param validEmail valid email, or null if entered email is invalid.
*/
- private suspend fun onEmailEntered(
+ private fun onEmailEntered(
validEmail: String?
) {
setState { copy(validEmail = validEmail) }
@@ -203,7 +204,10 @@ internal class NetworkingLinkSignupViewModel @AssistedInject constructor(
logger.debug("VALID EMAIL ADDRESS $validEmail.")
searchJob += suspend {
delay(getLookupDelayMs(validEmail))
- lookupAccount(validEmail)
+ lookupAccount(
+ email = validEmail,
+ verifiedFlow = stateFlow.value.payload()?.appVerificationEnabled == true
+ )
}.execute { copy(lookupAccount = if (it.isCancellationError()) Uninitialized else it) }
} else {
setState { copy(lookupAccount = Uninitialized) }
@@ -342,6 +346,7 @@ internal data class NetworkingLinkSignupState(
data class Payload(
val merchantName: String?,
val emailController: SimpleTextFieldController,
+ val appVerificationEnabled: Boolean,
val phoneController: PhoneNumberController,
val isInstantDebits: Boolean,
val content: Content,
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt
index 90337dfe901..84ff7eeb8c8 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt
@@ -99,6 +99,7 @@ internal class NetworkingLinkVerificationViewModel @AssistedInject constructor(
return InitData(
businessName = manifest.businessName,
emailAddress = requireNotNull(email),
+ appVerificationEnabled = manifest.appVerificationEnabled,
initialInstitution = manifest.initialInstitution,
)
}
@@ -108,6 +109,7 @@ internal class NetworkingLinkVerificationViewModel @AssistedInject constructor(
) {
lookupConsumerAndStartVerification(
email = initData.emailAddress,
+ appVerificationEnabled = initData.appVerificationEnabled,
businessName = initData.businessName,
verificationType = VerificationType.SMS,
onConsumerNotFound = {
@@ -228,6 +230,7 @@ internal class NetworkingLinkVerificationViewModel @AssistedInject constructor(
private data class InitData(
val businessName: String?,
val emailAddress: String,
+ val appVerificationEnabled: Boolean,
val initialInstitution: FinancialConnectionsInstitution?,
)
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/model/FinancialConnectionsSessionManifest.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/model/FinancialConnectionsSessionManifest.kt
index d4605c0aadd..69c7bfedd5f 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/model/FinancialConnectionsSessionManifest.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/model/FinancialConnectionsSessionManifest.kt
@@ -72,6 +72,8 @@ internal data class FinancialConnectionsSessionManifest(
@SerialName(value = "institution_search_disabled")
val institutionSearchDisabled: Boolean,
+ val appVerificationEnabled: Boolean = true,
+
@SerialName(value = "livemode")
val livemode: Boolean,
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt
index 09d5023a004..81c6d133030 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt
@@ -38,6 +38,7 @@ import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator.
import com.stripe.android.financialconnections.exception.CustomManualEntryRequiredError
import com.stripe.android.financialconnections.exception.FinancialConnectionsError
import com.stripe.android.financialconnections.exception.UnclassifiedError
+import com.stripe.android.financialconnections.features.error.isAttestationError
import com.stripe.android.financialconnections.features.manualentry.isCustomManualEntryError
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityResult
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityResult.Canceled
@@ -307,9 +308,15 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor(
if (state.completed) {
return@launch
}
-
setState { copy(completed = true) }
+ if (closeAuthFlowError?.isAttestationError() == true) {
+ // Attestation error is a special case where we need to close the native flow
+ // and continue with the AuthFlow on a web browser.
+ finishWithResult(Failed(error = closeAuthFlowError))
+ return@launch
+ }
+
runCatching {
val completionResult = completeFinancialConnectionsSession(earlyTerminationCause, closeAuthFlowError)
val session = completionResult.session
diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt
index 80378469a0e..9fb625db051 100644
--- a/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt
+++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt
@@ -27,17 +27,23 @@ internal interface FinancialConnectionsConsumerSessionRepository {
suspend fun getCachedConsumerSession(): CachedConsumerSession?
+ suspend fun postConsumerSession(
+ email: String,
+ clientSecret: String
+ ): ConsumerSessionLookup
+
+ suspend fun mobileLookupConsumerSession(
+ email: String,
+ verificationToken: String,
+ appId: String
+ ): ConsumerSessionLookup
+
suspend fun signUp(
email: String,
phoneNumber: String,
country: String,
): ConsumerSessionSignup
- suspend fun lookupConsumerSession(
- email: String,
- clientSecret: String
- ): ConsumerSessionLookup
-
suspend fun startConsumerVerification(
consumerSessionClientSecret: String,
connectionsMerchantName: String?,
@@ -123,15 +129,6 @@ private class FinancialConnectionsConsumerSessionRepositoryImpl(
consumerSessionRepository.provideConsumerSession()
}
- override suspend fun lookupConsumerSession(
- email: String,
- clientSecret: String
- ): ConsumerSessionLookup = mutex.withLock {
- postConsumerSession(email, clientSecret).also { lookup ->
- updateCachedConsumerSessionFromLookup(lookup)
- }
- }
-
override suspend fun signUp(
email: String,
phoneNumber: String,
@@ -238,14 +235,30 @@ private class FinancialConnectionsConsumerSessionRepositoryImpl(
).getOrThrow()
}
- private suspend fun postConsumerSession(
+ override suspend fun postConsumerSession(
email: String,
clientSecret: String
): ConsumerSessionLookup = financialConnectionsConsumersApiService.postConsumerSession(
email = email,
clientSecret = clientSecret,
requestSurface = requestSurface,
- )
+ ).also {
+ updateCachedConsumerSessionFromLookup(it)
+ }
+
+ override suspend fun mobileLookupConsumerSession(
+ email: String,
+ verificationToken: String,
+ appId: String
+ ): ConsumerSessionLookup = consumersApiService.mobileLookupConsumerSession(
+ email = email,
+ verificationToken = verificationToken,
+ appId = appId,
+ requestSurface = requestSurface,
+ requestOptions = provideApiRequestOptions(useConsumerPublishableKey = false),
+ ).also {
+ updateCachedConsumerSessionFromLookup(it)
+ }
private fun updateCachedConsumerSession(
source: String,
diff --git a/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt b/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt
index 343faa09b4e..73e1203cbbd 100644
--- a/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt
+++ b/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt
@@ -50,6 +50,14 @@ interface ConsumersApiService {
requestOptions: ApiRequest.Options
): ConsumerSessionLookup
+ suspend fun mobileLookupConsumerSession(
+ email: String,
+ requestSurface: String,
+ verificationToken: String,
+ appId: String,
+ requestOptions: ApiRequest.Options
+ ): ConsumerSessionLookup
+
suspend fun startConsumerVerification(
consumerSessionClientSecret: String,
locale: Locale,
@@ -176,6 +184,35 @@ class ConsumersApiServiceImpl(
)
}
+ /**
+ * Retrieves the ConsumerSession if the given email is associated with a Link account.
+ */
+ override suspend fun mobileLookupConsumerSession(
+ email: String,
+ requestSurface: String,
+ verificationToken: String,
+ appId: String,
+ requestOptions: ApiRequest.Options
+ ): ConsumerSessionLookup {
+ return executeRequestWithModelJsonParser(
+ stripeErrorJsonParser = stripeErrorJsonParser,
+ stripeNetworkClient = stripeNetworkClient,
+ request = apiRequestFactory.createPost(
+ mobileConsumerSessionLookupUrl,
+ requestOptions,
+ mapOf(
+ "request_surface" to requestSurface,
+ "email_address" to email.lowercase(),
+ "android_verification_token" to verificationToken,
+ "session_id" to "12345", // TODO (carlosmuvi): remove this when we have a real session id
+ "email_source" to "user_action", // TODO (carlosmuvi): remove this when we have a real app id
+ "app_id" to appId
+ )
+ ),
+ responseJsonParser = ConsumerSessionLookupJsonParser()
+ )
+ }
+
/**
* Triggers a verification for the consumer corresponding to the given client secret.
*/
@@ -328,6 +365,12 @@ class ConsumersApiServiceImpl(
internal val consumerSessionLookupUrl: String =
getApiUrl("consumers/sessions/lookup")
+ /**
+ * @return `https://api.stripe.com/v1/consumers/sessions/lookup`
+ */
+ internal val mobileConsumerSessionLookupUrl: String =
+ getApiUrl("consumers/mobile/sessions/lookup")
+
/**
* @return `https://api.stripe.com/v1/consumers/sessions/start_verification`
*/