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) 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..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,11 +204,17 @@ class ThreeDSecureClient internal constructor( configuration, request ) { consumerSessionId: String?, _ -> - if (consumerSessionId != null) { - try { + if (!consumerSessionId.isNullOrEmpty()) { 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( 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