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/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..fa154bbeb65 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
@@ -3,19 +3,34 @@ package com.stripe.android.financialconnections.domain
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 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) {
+ val token = integrityRequestManager.requestToken()
+ requireNotNull(
+ consumerSessionRepository.mobileLookupConsumerSession(
+ email = email.lowercase().trim(),
+ verificationToken = token.getOrThrow(),
+ )
+ )
+ } 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/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..87897989356 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,9 @@ internal data class FinancialConnectionsSessionManifest(
@SerialName(value = "institution_search_disabled")
val institutionSearchDisabled: Boolean,
+ @SerialName(value = "app_verification_enabled")
+ val appVerificationEnabled: Boolean,
+
@SerialName(value = "livemode")
val livemode: Boolean,
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..0737d20d8cb 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,22 @@ internal interface FinancialConnectionsConsumerSessionRepository {
suspend fun getCachedConsumerSession(): CachedConsumerSession?
+ suspend fun postConsumerSession(
+ email: String,
+ clientSecret: String
+ ): ConsumerSessionLookup
+
+ suspend fun mobileLookupConsumerSession(
+ email: String,
+ verificationToken: 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 +128,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 +234,28 @@ 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
+ ): ConsumerSessionLookup = consumersApiService.mobileLookupConsumerSession(
+ email = email,
+ verificationToken = verificationToken,
+ 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..deff09004b6 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,13 @@ interface ConsumersApiService {
requestOptions: ApiRequest.Options
): ConsumerSessionLookup
+ suspend fun mobileLookupConsumerSession(
+ email: String,
+ requestSurface: String,
+ verificationToken: String,
+ requestOptions: ApiRequest.Options
+ ): ConsumerSessionLookup
+
suspend fun startConsumerVerification(
consumerSessionClientSecret: String,
locale: Locale,
@@ -176,6 +183,31 @@ 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,
+ 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(),
+ "verification_token" to verificationToken
+ )
+ ),
+ responseJsonParser = ConsumerSessionLookupJsonParser()
+ )
+ }
+
/**
* Triggers a verification for the consumer corresponding to the given client secret.
*/
@@ -328,6 +360,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`
*/