Skip to content

Commit

Permalink
Updates lookup call to use mobile endpoint on verified flows
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosmuvi-stripe committed Dec 23, 2024
1 parent ade027d commit 12696a2
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 29 deletions.
4 changes: 1 addition & 3 deletions .idea/codestyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -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
)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = false,
appVerificationEnabled = false,
content = networkingLinkSignupPane(),
)
),
Expand All @@ -49,6 +50,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = false,
appVerificationEnabled = false,
content = networkingLinkSignupPane(),
)
),
Expand All @@ -74,6 +76,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = false,
appVerificationEnabled = false,
content = networkingLinkSignupPane(),
)
),
Expand All @@ -99,6 +102,7 @@ internal class NetworkingLinkSignupPreviewParameterProvider :
initiallySelectedCountryCode = null,
),
isInstantDebits = true,
appVerificationEnabled = false,
content = linkLoginPane(),
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -195,15 +196,18 @@ 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) }
if (validEmail != null) {
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) }
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ internal class NetworkingLinkVerificationViewModel @AssistedInject constructor(
return InitData(
businessName = manifest.businessName,
emailAddress = requireNotNull(email),
appVerificationEnabled = manifest.appVerificationEnabled,
initialInstitution = manifest.initialInstitution,
)
}
Expand All @@ -108,6 +109,7 @@ internal class NetworkingLinkVerificationViewModel @AssistedInject constructor(
) {
lookupConsumerAndStartVerification(
email = initData.emailAddress,
appVerificationEnabled = initData.appVerificationEnabled,
businessName = initData.businessName,
verificationType = VerificationType.SMS,
onConsumerNotFound = {
Expand Down Expand Up @@ -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?,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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?,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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`
*/
Expand Down

0 comments on commit 12696a2

Please sign in to comment.