Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,15 @@ class PaymentConfigurationTest {
assertThat(ParcelUtils.create(paymentConfig))
.isEqualTo(paymentConfig)
}

@Test
fun `isLiveMode is true when publishable key is live`() {
assertThat(PaymentConfiguration(publishableKey = "pk_test_123").isLiveMode()).isFalse()
assertThat(PaymentConfiguration(publishableKey = "pk_live_123").isLiveMode()).isTrue()
assertThat(
PaymentConfiguration(
publishableKey = "pk_test_51HvTI7Lu5o3livep6t5AgBSkMvWoTtA0nyA7pV"
).isLiveMode()
).isFalse()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ internal data class CommonConfiguration(
val appearance: PaymentSheet.Appearance,
) : Parcelable {

fun validate(isLiveMode: Boolean, @PaymentElementCallbackIdentifier callbackIdentifier: String) {
fun validate(@PaymentElementCallbackIdentifier callbackIdentifier: String) {
customerAndMerchantValidate()
externalPaymentMethodsValidate(isLiveMode)
confirmationTokenValidate(isLiveMode, callbackIdentifier)
externalPaymentMethodsValidate()
confirmationTokenValidate(callbackIdentifier)

customer?.accessType?.let { customerAccessType ->
customerAccessTypeValidate(customerAccessType)
Expand Down Expand Up @@ -73,9 +73,9 @@ internal data class CommonConfiguration(

// These exception messages are not localized as they are not intended to be displayed to a user.
@Suppress("ThrowsCount")
private fun externalPaymentMethodsValidate(isLiveMode: Boolean) {
private fun externalPaymentMethodsValidate() {
externalPaymentMethods.forEach { externalPaymentMethod ->
if (!externalPaymentMethod.startsWith("external_") && isLiveMode.not()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't check isLiveMode in other validation functions. I propose we remove it if we don't have good reasons to keep it. cc. @toluo-stripe

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that this isn't worth failing load for. We can still allow a user to successfully check out with a mis configuration in production. I think it's worth keeping!

if (!externalPaymentMethod.startsWith("external_")) {
throw IllegalArgumentException(
"External payment method '$externalPaymentMethod' does not start with 'external_'. " +
"All external payment methods must use the 'external_' prefix. " +
Expand All @@ -89,13 +89,11 @@ internal data class CommonConfiguration(
// These exception messages are not localized as they are not intended to be displayed to a user.
@Suppress("ThrowsCount")
private fun confirmationTokenValidate(
isLiveMode: Boolean,
@PaymentElementCallbackIdentifier callbackIdentifier: String
) {
if (
PaymentElementCallbackReferences[callbackIdentifier]?.createIntentWithConfirmationTokenCallback != null &&
customer?.accessType is PaymentSheet.CustomerAccessType.LegacyCustomerEphemeralKey &&
isLiveMode.not()
customer?.accessType is PaymentSheet.CustomerAccessType.LegacyCustomerEphemeralKey
) {
throw IllegalArgumentException(
"createIntentWithConfirmationTokenCallback must be used with CustomerSession."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.stripe.android.common.coroutines.awaitWithTimeout
import com.stripe.android.common.validation.isSupportedWithBillingConfig
import com.stripe.android.core.exception.StripeException
import com.stripe.android.core.injection.IOContext
import com.stripe.android.core.injection.IS_LIVE_MODE
import com.stripe.android.customersheet.analytics.CustomerSheetEventReporter
import com.stripe.android.customersheet.data.CustomerSheetInitializationDataSource
import com.stripe.android.customersheet.data.CustomerSheetSession
Expand All @@ -29,7 +28,6 @@ import com.stripe.android.paymentsheet.model.SavedSelection
import com.stripe.android.paymentsheet.model.validate
import kotlinx.coroutines.flow.first
import javax.inject.Inject
import javax.inject.Named
import kotlin.coroutines.CoroutineContext
import kotlin.time.Duration.Companion.seconds

Expand All @@ -38,7 +36,6 @@ internal interface CustomerSheetLoader {
}

internal class DefaultCustomerSheetLoader(
@Named(IS_LIVE_MODE) private val isLiveModeProvider: () -> Boolean,
private val googlePayRepositoryFactory: @JvmSuppressWildcards (GooglePayEnvironment) -> GooglePayRepository,
private val isFinancialConnectionsAvailable: IsFinancialConnectionsSdkAvailable,
private val lpmRepository: LpmRepository,
Expand All @@ -49,15 +46,13 @@ internal class DefaultCustomerSheetLoader(
) : CustomerSheetLoader {

@Inject constructor(
@Named(IS_LIVE_MODE) isLiveModeProvider: () -> Boolean,
googlePayRepositoryFactory: @JvmSuppressWildcards (GooglePayEnvironment) -> GooglePayRepository,
isFinancialConnectionsAvailable: IsFinancialConnectionsSdkAvailable,
lpmRepository: LpmRepository,
eventReporter: CustomerSheetEventReporter,
errorReporter: ErrorReporter,
@IOContext workContext: CoroutineContext
) : this(
isLiveModeProvider = isLiveModeProvider,
googlePayRepositoryFactory = googlePayRepositoryFactory,
isFinancialConnectionsAvailable = isFinancialConnectionsAvailable,
lpmRepository = lpmRepository,
Expand Down Expand Up @@ -143,7 +138,7 @@ internal class DefaultCustomerSheetLoader(
).sharedDataSpecs

val isGooglePaySupportedOnDevice = googlePayRepositoryFactory(
if (isLiveModeProvider()) GooglePayEnvironment.Production else GooglePayEnvironment.Test
if (elementsSession.stripeIntent.isLiveMode) GooglePayEnvironment.Production else GooglePayEnvironment.Test
).isReady().first()
val isGooglePayReadyAndEnabled = configuration.googlePayEnabled && isGooglePaySupportedOnDevice

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import com.stripe.android.common.model.PaymentMethodRemovePermission
import com.stripe.android.core.Logger
import com.stripe.android.core.exception.StripeException
import com.stripe.android.core.injection.IOContext
import com.stripe.android.core.injection.IS_LIVE_MODE
import com.stripe.android.core.networking.AnalyticsEvent
import com.stripe.android.core.networking.ApiRequest
import com.stripe.android.core.strings.ResolvableString
Expand Down Expand Up @@ -109,7 +108,6 @@ internal class CustomerSheetViewModel(
private val stripeRepository: StripeRepository,
private val eventReporter: CustomerSheetEventReporter,
private val workContext: CoroutineContext = Dispatchers.IO,
private val isLiveModeProvider: () -> Boolean,
private val productUsage: Set<String>,
confirmationHandlerFactory: ConfirmationHandler.Factory,
private val customerSheetLoader: CustomerSheetLoader,
Expand All @@ -129,7 +127,6 @@ internal class CustomerSheetViewModel(
stripeRepository: StripeRepository,
eventReporter: CustomerSheetEventReporter,
@IOContext workContext: CoroutineContext = Dispatchers.IO,
@Named(IS_LIVE_MODE) isLiveModeProvider: () -> Boolean,
@Named(PRODUCT_USAGE) productUsage: Set<String>,
confirmationHandlerFactory: ConfirmationHandler.Factory,
customerSheetLoader: CustomerSheetLoader,
Expand All @@ -150,7 +147,6 @@ internal class CustomerSheetViewModel(
eventReporter = eventReporter,
workContext = workContext,
productUsage = productUsage,
isLiveModeProvider = isLiveModeProvider,
confirmationHandlerFactory = confirmationHandlerFactory,
customerSheetLoader = customerSheetLoader,
errorReporter = errorReporter,
Expand All @@ -163,10 +159,28 @@ internal class CustomerSheetViewModel(
productUsageTokens = productUsage,
)

private val customerState = MutableStateFlow(
CustomerState(
paymentMethods = listOf(),
configuration = configuration,
currentSelection = originalPaymentSelection,
permissions = CustomerPermissions(
removePaymentMethod = PaymentMethodRemovePermission.None,
canRemoveLastPaymentMethod = false,
canUpdateFullPaymentMethodDetails = false,
),
metadata = null,
)
)

private val isLiveMode
get() = customerState.value.metadata?.stripeIntent?.isLiveMode
?: paymentConfigurationProvider.get().isLiveMode()

private val backStack = MutableStateFlow<List<CustomerSheetViewState>>(
listOf(
CustomerSheetViewState.Loading(
isLiveMode = isLiveModeProvider()
isLiveMode = isLiveMode
)
)
)
Expand All @@ -184,20 +198,6 @@ internal class CustomerSheetViewModel(
error = null,
)
)
private val customerState = MutableStateFlow(
CustomerState(
paymentMethods = listOf(),
configuration = configuration,
currentSelection = originalPaymentSelection,
permissions = CustomerPermissions(
removePaymentMethod = PaymentMethodRemovePermission.None,
canRemoveLastPaymentMethod = false,
canUpdateFullPaymentMethodDetails = false,
),
metadata = null,
)
)

private val selectPaymentMethodState = combineAsStateFlow(
customerState,
selectionConfirmationState,
Expand All @@ -214,7 +214,7 @@ internal class CustomerSheetViewModel(
title = configuration.headerTextForSelectionScreen,
savedPaymentMethods = paymentMethods,
paymentSelection = paymentSelection,
isLiveMode = isLiveModeProvider(),
isLiveMode = isLiveMode,
canRemovePaymentMethods = customerState.canRemove,
primaryButtonVisible = primaryButtonVisible,
showGooglePay = shouldShowGooglePay(paymentMethodMetadata),
Expand Down Expand Up @@ -577,7 +577,7 @@ internal class CustomerSheetViewModel(
transition(
to = CustomerSheetViewState.UpdatePaymentMethod(
updatePaymentMethodInteractor = DefaultUpdatePaymentMethodInteractor(
isLiveMode = isLiveModeProvider(),
isLiveMode = isLiveMode,
canRemove = customerState.canRemove,
canUpdateFullPaymentMethodDetails = customerState.canUpdateFullPaymentMethodDetails,
displayableSavedPaymentMethod = paymentMethod,
Expand Down Expand Up @@ -610,7 +610,7 @@ internal class CustomerSheetViewModel(
)
},
),
isLiveMode = isLiveModeProvider(),
isLiveMode = isLiveMode,
)
)
}
Expand Down Expand Up @@ -855,7 +855,7 @@ internal class CustomerSheetViewModel(
),
draftPaymentSelection = null,
enabled = true,
isLiveMode = isLiveModeProvider(),
isLiveMode = isLiveMode,
isProcessing = false,
isFirstPaymentMethod = isFirstPaymentMethod,
primaryButtonLabel = R.string.stripe_paymentsheet_save.resolvableString,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import com.stripe.android.PaymentConfiguration
import com.stripe.android.core.Logger
import com.stripe.android.core.injection.ENABLE_LOGGING
import com.stripe.android.core.injection.IOContext
import com.stripe.android.core.injection.IS_LIVE_MODE
import com.stripe.android.core.injection.PUBLISHABLE_KEY
import com.stripe.android.core.injection.STRIPE_ACCOUNT_ID
import com.stripe.android.core.injection.UIContext
Expand Down Expand Up @@ -113,12 +112,6 @@ internal interface CustomerSheetViewModelModule {
paymentConfiguration: Provider<PaymentConfiguration>
): () -> String? = { paymentConfiguration.get().stripeAccountId }

@Provides
@Named(IS_LIVE_MODE)
fun isLiveMode(
paymentConfiguration: Provider<PaymentConfiguration>
): () -> Boolean = { paymentConfiguration.get().isLiveMode() }

@Provides
internal fun providesErrorReporter(
analyticsRequestFactory: AnalyticsRequestFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ package com.stripe.android.link.injection

import android.app.Application
import android.content.Context
import com.stripe.android.PaymentConfiguration
import com.stripe.android.common.di.ApplicationIdModule
import com.stripe.android.common.di.MobileSessionIdModule
import com.stripe.android.core.injection.CoreCommonModule
import com.stripe.android.core.injection.CoroutineContextModule
import com.stripe.android.core.injection.IS_LIVE_MODE
import com.stripe.android.googlepaylauncher.injection.GooglePayLauncherModule
import com.stripe.android.link.DefaultLinkConfigurationLoader
import com.stripe.android.link.LinkConfigurationLoader
Expand All @@ -24,7 +22,6 @@ import dagger.Binds
import dagger.Module
import dagger.Provides
import javax.inject.Named
import javax.inject.Provider
import javax.inject.Singleton

@Module(
Expand Down Expand Up @@ -71,11 +68,5 @@ internal interface LinkControllerModule {
@Singleton
@Named(PRODUCT_USAGE)
fun provideProductUsageTokens() = setOf("LinkPaymentMethodLauncher")

@Provides
@Named(IS_LIVE_MODE)
fun isLiveMode(
paymentConfiguration: Provider<PaymentConfiguration>
): () -> Boolean = { paymentConfiguration.get().isLiveMode() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.app.Application
import androidx.activity.result.ActivityResultCaller
import androidx.lifecycle.LifecycleOwner
import com.stripe.android.PaymentConfiguration
import com.stripe.android.core.injection.IS_LIVE_MODE
import com.stripe.android.paymentelement.EmbeddedPaymentElement
import com.stripe.android.paymentelement.embedded.DefaultEmbeddedResultCallbackHelper
import com.stripe.android.paymentelement.embedded.EmbeddedResultCallbackHelper
Expand All @@ -13,8 +12,6 @@ import dagger.BindsInstance
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
import javax.inject.Named
import javax.inject.Provider

@Subcomponent(
modules = [
Expand Down Expand Up @@ -56,11 +53,5 @@ internal interface EmbeddedPaymentElementModule {
fun paymentConfiguration(application: Application): PaymentConfiguration {
return PaymentConfiguration.getInstance(application)
}

@Provides
@Named(IS_LIVE_MODE)
fun isLiveMode(
paymentConfiguration: Provider<PaymentConfiguration>
): () -> Boolean = { paymentConfiguration.get().isLiveMode() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import android.app.Application
import android.content.Context
import android.content.res.Resources
import androidx.lifecycle.SavedStateHandle
import com.stripe.android.PaymentConfiguration
import com.stripe.android.cards.CardAccountRangeRepository
import com.stripe.android.cards.DefaultCardAccountRangeRepositoryFactory
import com.stripe.android.common.di.ApplicationIdModule
import com.stripe.android.common.di.MobileSessionIdModule
import com.stripe.android.core.injection.IS_LIVE_MODE
import com.stripe.android.core.injection.ViewModelScope
import com.stripe.android.core.utils.RealUserFacingLogger
import com.stripe.android.core.utils.UserFacingLogger
Expand Down Expand Up @@ -52,7 +50,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Named
import javax.inject.Provider
import javax.inject.Singleton

@Singleton
Expand Down Expand Up @@ -182,12 +179,6 @@ internal interface EmbeddedPaymentElementViewModelModule {
return confirmationStateHolder.state?.paymentMethodMetadata
}

@Provides
@Named(IS_LIVE_MODE)
fun providesIsLiveMode(
paymentConfiguration: Provider<PaymentConfiguration>
): () -> Boolean = { paymentConfiguration.get().isLiveMode() }

@Provides
@Singleton
fun providesLinkAccountHolder(savedStateHandle: SavedStateHandle): LinkAccountHolder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {
} else {
try {
starterArgs.initializationMode.validate()
starterArgs.config.asCommonConfiguration().validate(
viewModel.isLiveModeProvider(),
starterArgs.paymentElementCallbackIdentifier
)
starterArgs.config.asCommonConfiguration().validate(starterArgs.paymentElementCallbackIdentifier)
} catch (e: IllegalArgumentException) {
finishWithError(e)
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import com.stripe.android.common.model.asCommonConfiguration
import com.stripe.android.core.Logger
import com.stripe.android.core.exception.StripeException
import com.stripe.android.core.injection.IOContext
import com.stripe.android.core.injection.IS_LIVE_MODE
import com.stripe.android.core.strings.ResolvableString
import com.stripe.android.core.utils.requireApplication
import com.stripe.android.googlepaylauncher.GooglePayEnvironment
Expand Down Expand Up @@ -68,7 +67,6 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
import kotlin.coroutines.CoroutineContext

Expand All @@ -88,7 +86,6 @@ internal class PaymentSheetViewModel @Inject internal constructor(
private val errorReporter: ErrorReporter,
internal val cvcRecollectionHandler: CvcRecollectionHandler,
private val cvcRecollectionInteractorFactory: CvcRecollectionInteractor.Factory,
@Named(IS_LIVE_MODE) val isLiveModeProvider: () -> Boolean,
) : BaseSheetViewModel(
config = args.config,
eventReporter = eventReporter,
Expand Down Expand Up @@ -413,7 +410,7 @@ internal class PaymentSheetViewModel @Inject internal constructor(
lastFour = cvcRecollectionData.lastFour ?: "",
cardBrand = cvcRecollectionData.brand,
cvc = "",
isTestMode = paymentMethodMetadata.value?.stripeIntent?.isLiveMode?.not() ?: false,
isTestMode = paymentMethodMetadata.value?.stripeIntent?.isLiveMode?.not() ?: false
),
processing = processing,
coroutineScope = viewModelScope,
Expand Down
Loading
Loading