From 0615075a27347c058ec0b9affcb4dc1d26632e37 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Tue, 14 Jan 2025 09:16:32 -0600 Subject: [PATCH 1/4] update logic to handle missing dfReferenceId --- .../api/threedsecure/ThreeDSecureClient.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt b/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt index 121487ecf4..2f66c97d64 100644 --- a/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt +++ b/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt @@ -204,11 +204,17 @@ class ThreeDSecureClient internal constructor( configuration, request ) { consumerSessionId: String?, _ -> - if (consumerSessionId != null) { - try { + if (consumerSessionId != null && !consumerSessionId.isEmpty()) { lookupJSON.put("dfReferenceId", consumerSessionId) - } catch (ignored: JSONException) { - } + } else { + callbackPrepareLookupFailure( + callback, + ThreeDSecurePrepareLookupResult.Failure( + BraintreeException("There was an error retrieving the dfReferenceId.") + ) + ) + + return@initialize } braintreeClient.sendAnalyticsEvent(ThreeDSecureAnalytics.LOOKUP_SUCCEEDED) callback.onPrepareLookupResult( From 6b37ddacda4be632b273784ebf94eb4e3fdbdcb8 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Tue, 14 Jan 2025 09:16:52 -0600 Subject: [PATCH 2/4] add unit test for empty dfReferenceId; remove now inaccurate test --- .../ThreeDSecureClientUnitTest.java | 66 ++++++++----------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java b/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java index 8db8436e20..8377b5adcd 100644 --- a/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java +++ b/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java @@ -128,10 +128,9 @@ public void prepareLookup_returnsValidLookupJSONString() } @Test - public void prepareLookup_returnsValidLookupJSONString_whenCardinalSetupFails() - throws JSONException, BraintreeException { + public void prepareLookup_initializesCardinal() throws BraintreeException { CardinalClient cardinalClient = new MockCardinalClientBuilder() - .error(new Exception("cardinal error")) + .successReferenceId("fake-df") .build(); BraintreeClient braintreeClient = new MockBraintreeClientBuilder() @@ -148,32 +147,16 @@ public void prepareLookup_returnsValidLookupJSONString_whenCardinalSetupFails() ThreeDSecurePrepareLookupCallback callback = mock(ThreeDSecurePrepareLookupCallback.class); sut.prepareLookup(activity, basicRequest, callback); - ArgumentCaptor captor = ArgumentCaptor.forClass(ThreeDSecurePrepareLookupResult.class); - verify(callback).onPrepareLookupResult(captor.capture()); - - ThreeDSecurePrepareLookupResult prepareLookupResult = captor.getValue(); - assertTrue(prepareLookupResult instanceof ThreeDSecurePrepareLookupResult.Success); - assertSame(basicRequest, ((ThreeDSecurePrepareLookupResult.Success) prepareLookupResult).getRequest()); - - String clientData = ((ThreeDSecurePrepareLookupResult.Success) prepareLookupResult).getClientData(); - JSONObject lookup = new JSONObject(clientData); - Assert.assertEquals("encoded_auth_fingerprint", - lookup.getString("authorizationFingerprint")); - Assert.assertEquals(lookup.getString("braintreeLibraryVersion"), - "Android-" + com.braintreepayments.api.core.BuildConfig.VERSION_NAME); - Assert.assertEquals(lookup.getString("nonce"), "a-nonce"); - assertFalse(lookup.has("dfReferenceId")); - - JSONObject clientMetaData = lookup.getJSONObject("clientMetadata"); - Assert.assertEquals(clientMetaData.getString("requestedThreeDSecureVersion"), "2"); - Assert.assertEquals(clientMetaData.getString("sdkVersion"), - "Android/" + com.braintreepayments.api.core.BuildConfig.VERSION_NAME); + verify(cardinalClient).initialize(same(activity), same(threeDSecureEnabledConfig), + same(basicRequest), any(CardinalInitializeCallback.class)); } @Test - public void prepareLookup_initializesCardinal() throws BraintreeException { + public void prepareLookup_whenCardinalClientInitializeFails_forwardsError() + throws BraintreeException { + BraintreeException initializeRuntimeError = new BraintreeException("initialize error"); CardinalClient cardinalClient = new MockCardinalClientBuilder() - .successReferenceId("fake-df") + .initializeRuntimeError(initializeRuntimeError) .build(); BraintreeClient braintreeClient = new MockBraintreeClientBuilder() @@ -190,27 +173,28 @@ public void prepareLookup_initializesCardinal() throws BraintreeException { ThreeDSecurePrepareLookupCallback callback = mock(ThreeDSecurePrepareLookupCallback.class); sut.prepareLookup(activity, basicRequest, callback); - verify(cardinalClient).initialize(same(activity), same(threeDSecureEnabledConfig), - same(basicRequest), any(CardinalInitializeCallback.class)); + ArgumentCaptor captor = ArgumentCaptor.forClass(ThreeDSecurePrepareLookupResult.class); + verify(callback).onPrepareLookupResult(captor.capture()); + ThreeDSecurePrepareLookupResult prepareLookupResult = captor.getValue(); + assertTrue(prepareLookupResult instanceof ThreeDSecurePrepareLookupResult.Failure); + assertEquals(initializeRuntimeError, ((ThreeDSecurePrepareLookupResult.Failure) prepareLookupResult).getError()); } @Test - public void prepareLookup_whenCardinalClientInitializeFails_forwardsError() - throws BraintreeException { - BraintreeException initializeRuntimeError = new BraintreeException("initialize error"); + public void prepareLookup_whenDfReferenceIdMissing_forwardsError() throws BraintreeException { CardinalClient cardinalClient = new MockCardinalClientBuilder() - .initializeRuntimeError(initializeRuntimeError) - .build(); + .successReferenceId("") + .build(); BraintreeClient braintreeClient = new MockBraintreeClientBuilder() - .configuration(threeDSecureEnabledConfig) - .build(); + .configuration(threeDSecureEnabledConfig) + .build(); ThreeDSecureClient sut = new ThreeDSecureClient( - braintreeClient, - cardinalClient, - new ThreeDSecureAPI(braintreeClient), - merchantRepository + braintreeClient, + cardinalClient, + new ThreeDSecureAPI(braintreeClient), + merchantRepository ); ThreeDSecurePrepareLookupCallback callback = mock(ThreeDSecurePrepareLookupCallback.class); @@ -220,7 +204,11 @@ public void prepareLookup_whenCardinalClientInitializeFails_forwardsError() verify(callback).onPrepareLookupResult(captor.capture()); ThreeDSecurePrepareLookupResult prepareLookupResult = captor.getValue(); assertTrue(prepareLookupResult instanceof ThreeDSecurePrepareLookupResult.Failure); - assertEquals(initializeRuntimeError, ((ThreeDSecurePrepareLookupResult.Failure) prepareLookupResult).getError()); + Exception error = ((ThreeDSecurePrepareLookupResult.Failure) prepareLookupResult).getError(); + + TestCase.assertTrue(error instanceof BraintreeException); + Assert.assertEquals(error.getMessage(), + "There was an error retrieving the dfReferenceId."); } @Test From aaf84cd34f04ef819105ac56135285322707cac3 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Tue, 14 Jan 2025 09:17:53 -0600 Subject: [PATCH 3/4] add CHANGELOG entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c035ee1c..2dd56e16c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * PayPal * Fix bug to ensure that `PayPalVaultRequest.userAuthenticationEmail` is not sent as an empty string +* ThreeDSecure + * Return error if no `dfReferenceId` is returned in the 3D Secure flow ## 5.3.0 (2024-12-11) From 33b4898dbd39439bc31dfa76046a2eacfa7493e9 Mon Sep 17 00:00:00 2001 From: Jax DesMarais-Leder Date: Tue, 14 Jan 2025 09:35:34 -0600 Subject: [PATCH 4/4] Update ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt Co-authored-by: Rich Herrera --- .../braintreepayments/api/threedsecure/ThreeDSecureClient.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt b/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt index 2f66c97d64..f84437bb5d 100644 --- a/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt +++ b/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt @@ -204,7 +204,7 @@ class ThreeDSecureClient internal constructor( configuration, request ) { consumerSessionId: String?, _ -> - if (consumerSessionId != null && !consumerSessionId.isEmpty()) { + if (!consumerSessionId.isNullOrEmpty()) { lookupJSON.put("dfReferenceId", consumerSessionId) } else { callbackPrepareLookupFailure(