From 56c13bd18d25ba847b7e6632ee913ac309f168b1 Mon Sep 17 00:00:00 2001 From: Michael Shafrir Date: Mon, 7 Oct 2019 07:47:31 -0400 Subject: [PATCH] Unify logging config between Stripe and Stripe 3DS2 Use the value for `enableLogging` passed in the `Stripe` constructor to determine whether to enable logging in the Stripe 3DS2 SDK. --- .../example/activity/PaymentAuthActivity.kt | 36 +++++++++--------- .../com/stripe/example/service/BackendApi.kt | 2 +- .../com/stripe/android/PaymentAuthConfig.java | 16 -------- .../com/stripe/android/PaymentController.kt | 13 +++++-- .../main/java/com/stripe/android/Stripe.kt | 11 ++++-- .../stripe/android/PaymentControllerTest.kt | 38 ++++++++++--------- 6 files changed, 57 insertions(+), 59 deletions(-) diff --git a/example/src/main/java/com/stripe/example/activity/PaymentAuthActivity.kt b/example/src/main/java/com/stripe/example/activity/PaymentAuthActivity.kt index 141185a348d..007d3812af7 100644 --- a/example/src/main/java/com/stripe/example/activity/PaymentAuthActivity.kt +++ b/example/src/main/java/com/stripe/example/activity/PaymentAuthActivity.kt @@ -46,12 +46,12 @@ class PaymentAuthActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_payment_auth) - val uiCustomization = PaymentAuthConfig.Stripe3ds2UiCustomization.Builder().build() + val uiCustomization = + PaymentAuthConfig.Stripe3ds2UiCustomization.Builder().build() PaymentAuthConfig.init(PaymentAuthConfig.Builder() .set3ds2Config(PaymentAuthConfig.Stripe3ds2Config.Builder() .setTimeout(6) .setUiCustomization(uiCustomization) - .setEnableLogging(true) .build()) .build()) @@ -62,11 +62,10 @@ class PaymentAuthActivity : AppCompatActivity() { backendApi = RetrofitFactory.instance.create(BackendApi::class.java) val publishableKey = PaymentConfiguration.getInstance(this).publishableKey - stripe = if (stripeAccountId != null) { - Stripe(this, publishableKey, stripeAccountId) - } else { - Stripe(this, publishableKey) - } + stripe = Stripe(this, publishableKey, + stripeAccountId = stripeAccountId, + enableLogging = true + ) buy_3ds1_button.setOnClickListener { createPaymentIntent(stripeAccountId, AuthType.ThreeDS1) @@ -103,10 +102,10 @@ class PaymentAuthActivity : AppCompatActivity() { progress_bar.visibility = View.VISIBLE statusTextView.append("\n\nPayment authentication completed, getting result") - val isPaymentResult = stripe.onPaymentResult(requestCode, data, AuthResultListener(this)) - + val isPaymentResult = + stripe.onPaymentResult(requestCode, data, AuthResultListener(this)) if (!isPaymentResult) { - val isSetupResult = stripe.onSetupResult(requestCode, data, SetupAuthResultListener(this)) + stripe.onSetupResult(requestCode, data, SetupAuthResultListener(this)) } } @@ -130,7 +129,9 @@ class PaymentAuthActivity : AppCompatActivity() { authType: AuthType ) { compositeSubscription.add( - backendApi.createPaymentIntent(createPaymentIntentParams(stripeAccountId)) + backendApi.createPaymentIntent( + createPaymentIntentParams(stripeAccountId).toMutableMap() + ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe { @@ -196,16 +197,17 @@ class PaymentAuthActivity : AppCompatActivity() { progress_bar.visibility = View.INVISIBLE } - private fun createPaymentIntentParams(stripeAccountId: String?): HashMap { - val params = hashMapOf( + private fun createPaymentIntentParams(stripeAccountId: String?): Map { + return mapOf( "payment_method_types[]" to "card", "amount" to 1000, "currency" to "usd" ) - if (stripeAccountId != null) { - params["stripe_account"] = stripeAccountId - } - return params + .plus( + stripeAccountId?.let { + mapOf("stripe_account" to it) + }.orEmpty() + ) } private class AuthResultListener constructor( diff --git a/example/src/main/java/com/stripe/example/service/BackendApi.kt b/example/src/main/java/com/stripe/example/service/BackendApi.kt index 7e8df3499ff..46db9c9949f 100644 --- a/example/src/main/java/com/stripe/example/service/BackendApi.kt +++ b/example/src/main/java/com/stripe/example/service/BackendApi.kt @@ -17,7 +17,7 @@ interface BackendApi { @FormUrlEncoded @POST("create_intent") - fun createPaymentIntent(@FieldMap params: HashMap): Observable + fun createPaymentIntent(@FieldMap params: MutableMap): Observable @FormUrlEncoded @POST("create_setup_intent") diff --git a/stripe/src/main/java/com/stripe/android/PaymentAuthConfig.java b/stripe/src/main/java/com/stripe/android/PaymentAuthConfig.java index af111e3d499..d1b5b42a603 100644 --- a/stripe/src/main/java/com/stripe/android/PaymentAuthConfig.java +++ b/stripe/src/main/java/com/stripe/android/PaymentAuthConfig.java @@ -73,12 +73,10 @@ public static final class Stripe3ds2Config { final int timeout; @NonNull final Stripe3ds2UiCustomization uiCustomization; - final boolean enableLogging; private Stripe3ds2Config(@NonNull Builder builder) { timeout = checkValidTimeout(builder.mTimeout); uiCustomization = Objects.requireNonNull(builder.mUiCustomization); - enableLogging = builder.mEnableLogging; } private int checkValidTimeout(int timeout) { @@ -93,7 +91,6 @@ public static final class Builder implements ObjectBuilder { private int mTimeout = DEFAULT_TIMEOUT; private Stripe3ds2UiCustomization mUiCustomization = new Stripe3ds2UiCustomization.Builder().build(); - private boolean mEnableLogging = false; @NonNull public Builder setTimeout(@IntRange(from = 5, to = 99) int timeout) { @@ -107,19 +104,6 @@ public Builder setUiCustomization(@NonNull Stripe3ds2UiCustomization uiCustomiza return this; } - /** - * Enable logging in the Stripe 3DS2 SDK; disabled by default. - * It is recommended to disable logging in production. - * - *

Logs can be accessed from the command line using - * adb logcat -s Stripe3ds2.

- */ - @NonNull - public Builder setEnableLogging(boolean enableLogging) { - this.mEnableLogging = enableLogging; - return this; - } - @NonNull public Stripe3ds2Config build() { return new Stripe3ds2Config(this); diff --git a/stripe/src/main/java/com/stripe/android/PaymentController.kt b/stripe/src/main/java/com/stripe/android/PaymentController.kt index 51a979a02d3..77818fbf93a 100644 --- a/stripe/src/main/java/com/stripe/android/PaymentController.kt +++ b/stripe/src/main/java/com/stripe/android/PaymentController.kt @@ -39,13 +39,13 @@ import java.util.concurrent.TimeUnit internal open class PaymentController @VisibleForTesting constructor( context: Context, private val stripeRepository: StripeRepository, + enableLogging: Boolean = false, private val messageVersionRegistry: MessageVersionRegistry = MessageVersionRegistry(), private val config: PaymentAuthConfig = PaymentAuthConfig.get(), private val threeDs2Service: StripeThreeDs2Service = - StripeThreeDs2ServiceImpl(context, StripeSSLSocketFactory(), - config.stripe3ds2Config.enableLogging), + StripeThreeDs2ServiceImpl(context, StripeSSLSocketFactory(), enableLogging), private val analyticsRequestExecutor: FireAndForgetRequestExecutor = StripeFireAndForgetRequestExecutor(), private val analyticsDataFactory: AnalyticsDataFactory = @@ -765,9 +765,14 @@ internal open class PaymentController @VisibleForTesting constructor( .start(PaymentRelayStarter.Data.create(exception)) } + @JvmOverloads @JvmStatic - fun create(context: Context, stripeRepository: StripeRepository): PaymentController { - return PaymentController(context.applicationContext, stripeRepository) + fun create( + context: Context, + stripeRepository: StripeRepository, + enableLogging: Boolean = false + ): PaymentController { + return PaymentController(context.applicationContext, stripeRepository, enableLogging) } } } diff --git a/stripe/src/main/java/com/stripe/android/Stripe.kt b/stripe/src/main/java/com/stripe/android/Stripe.kt index 257c5c74162..4caa870bd09 100644 --- a/stripe/src/main/java/com/stripe/android/Stripe.kt +++ b/stripe/src/main/java/com/stripe/android/Stripe.kt @@ -59,6 +59,9 @@ class Stripe internal constructor( * @param context Activity or application context * @param publishableKey the client's publishable key * @param stripeAccountId optional, the Stripe Connect account id to attach to [Stripe API requests](https://stripe.com/docs/connect/authentication#authentication-via-the-stripe-account-header) + * @param enableLogging enable logging in the Stripe and Stripe 3DS2 SDKs; disabled by default. + * It is recommended to disable logging in production. Logs can be accessed from the command line using + * `adb logcat -s StripeSdk` */ @JvmOverloads constructor( @@ -75,7 +78,8 @@ class Stripe internal constructor( ), StripeNetworkUtils(context.applicationContext), ApiKeyValidator.get().requireValid(publishableKey), - stripeAccountId + stripeAccountId, + enableLogging ) private constructor( @@ -83,11 +87,12 @@ class Stripe internal constructor( stripeRepository: StripeRepository, stripeNetworkUtils: StripeNetworkUtils, publishableKey: String, - stripeAccountId: String? + stripeAccountId: String?, + enableLogging: Boolean ) : this( stripeRepository, stripeNetworkUtils, - PaymentController.create(context.applicationContext, stripeRepository), + PaymentController.create(context.applicationContext, stripeRepository, enableLogging), publishableKey, stripeAccountId ) diff --git a/stripe/src/test/java/com/stripe/android/PaymentControllerTest.kt b/stripe/src/test/java/com/stripe/android/PaymentControllerTest.kt index dd3a5f90a74..ae00788db37 100644 --- a/stripe/src/test/java/com/stripe/android/PaymentControllerTest.kt +++ b/stripe/src/test/java/com/stripe/android/PaymentControllerTest.kt @@ -103,6 +103,7 @@ class PaymentControllerTest { controller = PaymentController( ApplicationProvider.getApplicationContext(), FakeStripeRepository(), + false, MessageVersionRegistry(), CONFIG, threeDs2Service, @@ -116,7 +117,9 @@ class PaymentControllerTest { @Throws(CertificateException::class) fun handleNextAction_withMastercardAnd3ds2_shouldStart3ds2ChallengeFlow() { val paymentIntent = PaymentIntentFixtures.PI_REQUIRES_MASTERCARD_3DS2 - val dsPublicKey = Stripe3ds2Fingerprint.create(paymentIntent.stripeSdkData!!) + val dsPublicKey = Stripe3ds2Fingerprint.create( + requireNotNull(paymentIntent.stripeSdkData) + ) .directoryServerEncryption .directoryServerPublicKey `when`(threeDs2Service.createTransaction( @@ -145,7 +148,7 @@ class PaymentControllerTest { verify(fireAndForgetRequestExecutor) .executeAsync(apiRequestArgumentCaptor.capture()) - val analyticsParams = apiRequestArgumentCaptor.firstValue.params!! + val analyticsParams = requireNotNull(apiRequestArgumentCaptor.firstValue.params) assertEquals("stripe_android.3ds2_fingerprint", analyticsParams[AnalyticsDataFactory.FIELD_EVENT]) assertEquals(PaymentIntentFixtures.PI_REQUIRES_MASTERCARD_3DS2.id, @@ -196,7 +199,7 @@ class PaymentControllerTest { verify(fireAndForgetRequestExecutor) .executeAsync(apiRequestArgumentCaptor.capture()) assertEquals("stripe_android.3ds1_sdk", - apiRequestArgumentCaptor.firstValue.params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(apiRequestArgumentCaptor.firstValue.params)[AnalyticsDataFactory.FIELD_EVENT]) } @Test @@ -216,7 +219,7 @@ class PaymentControllerTest { verify(fireAndForgetRequestExecutor) .executeAsync(apiRequestArgumentCaptor.capture()) - val analyticsParams = apiRequestArgumentCaptor.firstValue.params!! + val analyticsParams = requireNotNull(apiRequestArgumentCaptor.firstValue.params) assertEquals("stripe_android.url_redirect_next_action", analyticsParams[AnalyticsDataFactory.FIELD_EVENT]) assertEquals("pi_1EZlvVCRMbs6FrXfKpq2xMmy", @@ -276,9 +279,9 @@ class PaymentControllerTest { val analyticsRequests = apiRequestArgumentCaptor.allValues assertEquals("stripe_android.3ds2_challenge_flow_completed", - analyticsRequests[0].params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequests[0].params)[AnalyticsDataFactory.FIELD_EVENT]) - val analyticsParamsSecond = analyticsRequests[1].params!! + val analyticsParamsSecond = requireNotNull(analyticsRequests[1].params) assertEquals("stripe_android.3ds2_challenge_flow_presented", analyticsParamsSecond[AnalyticsDataFactory.FIELD_EVENT]) assertEquals("oob", @@ -298,10 +301,10 @@ class PaymentControllerTest { val analyticsRequests = apiRequestArgumentCaptor.allValues assertEquals("stripe_android.3ds2_challenge_flow_timed_out", - analyticsRequests[0].params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequests[0].params)[AnalyticsDataFactory.FIELD_EVENT]) assertEquals("stripe_android.3ds2_challenge_flow_presented", - analyticsRequests[1].params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequests[1].params)[AnalyticsDataFactory.FIELD_EVENT]) } @Test @@ -318,10 +321,10 @@ class PaymentControllerTest { val analyticsRequests = apiRequestArgumentCaptor.allValues assertEquals("stripe_android.3ds2_challenge_flow_canceled", - analyticsRequests[0].params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequests[0].params)[AnalyticsDataFactory.FIELD_EVENT]) assertEquals("stripe_android.3ds2_challenge_flow_presented", - analyticsRequests[1].params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequests[1].params)[AnalyticsDataFactory.FIELD_EVENT]) } @Test @@ -342,7 +345,7 @@ class PaymentControllerTest { .executeAsync(apiRequestArgumentCaptor.capture()) val analyticsRequests = apiRequestArgumentCaptor.allValues - val analyticsParamsFirst = analyticsRequests[0].params!! + val analyticsParamsFirst = requireNotNull(analyticsRequests[0].params) assertEquals("stripe_android.3ds2_challenge_flow_errored", analyticsParamsFirst[AnalyticsDataFactory.FIELD_EVENT]) @@ -353,7 +356,7 @@ class PaymentControllerTest { assertEquals("Resource not found", errorData["error_message"]) assertEquals("stripe_android.3ds2_challenge_flow_presented", - analyticsRequests[1].params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequests[1].params)[AnalyticsDataFactory.FIELD_EVENT]) } @Test @@ -380,7 +383,7 @@ class PaymentControllerTest { .executeAsync(apiRequestArgumentCaptor.capture()) val analyticsRequests = apiRequestArgumentCaptor.allValues - val analyticsParamsFirst = analyticsRequests[0].params!! + val analyticsParamsFirst = requireNotNull(analyticsRequests[0].params) assertEquals("stripe_android.3ds2_challenge_flow_errored", analyticsParamsFirst[AnalyticsDataFactory.FIELD_EVENT]) @@ -390,7 +393,7 @@ class PaymentControllerTest { assertEquals("201", errorData["error_code"]) assertEquals("stripe_android.3ds2_challenge_flow_presented", - analyticsRequests[1].params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequests[1].params)[AnalyticsDataFactory.FIELD_EVENT]) } @Test @@ -488,7 +491,7 @@ class PaymentControllerTest { verify(fireAndForgetRequestExecutor).executeAsync(apiRequestArgumentCaptor.capture()) val analyticsRequest = apiRequestArgumentCaptor.firstValue - val analyticsParams = analyticsRequest.params!! + val analyticsParams = requireNotNull(analyticsRequest.params) assertEquals("stripe_android.3ds2_frictionless_flow", analyticsParams[AnalyticsDataFactory.FIELD_EVENT]) assertEquals("pi_1ExkUeAWhjPjYwPiXph9ouXa", @@ -516,7 +519,7 @@ class PaymentControllerTest { verify(fireAndForgetRequestExecutor).executeAsync(apiRequestArgumentCaptor.capture()) val analyticsRequest = apiRequestArgumentCaptor.firstValue assertEquals("stripe_android.3ds2_fallback", - analyticsRequest.params!![AnalyticsDataFactory.FIELD_EVENT]) + requireNotNull(analyticsRequest.params)[AnalyticsDataFactory.FIELD_EVENT]) } @Test @@ -529,12 +532,11 @@ class PaymentControllerTest { ) authCallback.onSuccess(Stripe3ds2AuthResultFixtures.ERROR) verify(paymentRelayStarter).start(relayStarterDataArgumentCaptor.capture()) - val exception = relayStarterDataArgumentCaptor.firstValue.exception!! assertEquals("Error encountered during 3DS2 authentication request. " + "Code: 302, Detail: null, " + "Description: Data could not be decrypted by the receiving system due to " + "technical or other reason., Component: D", - exception.message) + relayStarterDataArgumentCaptor.firstValue.exception?.message) } private class FakeStripeRepository : AbsFakeStripeRepository() {