Skip to content

Commit

Permalink
Catch Cardinal Null Pointer Exception and General Cleanup (#717)
Browse files Browse the repository at this point in the history
* Catch null pointer exception in CardinalClient.

* Add exception to CardinalClient.

* Add CardinalClient unit test for null pointer exception.

* Update CHANGELOG.

* Update Kotlin version and cleanup unused code imports.

* Remove clear text identifiers.

* Remove jcenter from gradle file.

* Revert Kotlin version and use fun interfaces for internal callback methods.
  • Loading branch information
sshropshire authored Apr 12, 2023
1 parent 323061c commit fc82623
Show file tree
Hide file tree
Showing 21 changed files with 172 additions and 114 deletions.
3 changes: 1 addition & 2 deletions BraintreeCore/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />

<application
android:usesCleartextTraffic="true">
<application>

<!--suppress AndroidDomInspection -->
<activity android:name=".TestActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import androidx.annotation.RestrictTo
* @suppress
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface AuthorizationCallback {
fun interface AuthorizationCallback {
fun onAuthorizationResult(authorization: Authorization?, error: Exception?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,24 +169,19 @@ open class BraintreeClient @VisibleForTesting internal constructor(
* @param callback [ConfigurationCallback]
*/
open fun getConfiguration(callback: ConfigurationCallback) {
getAuthorization(object : AuthorizationCallback {
override fun onAuthorizationResult(authorization: Authorization?, authError: Exception?) {
if (authorization != null) {
configurationLoader.loadConfiguration(authorization,
object : ConfigurationLoaderCallback {
override fun onResult(configuration: Configuration?, configError: Exception?) {
if (configuration != null) {
callback.onResult(configuration, null)
} else {
callback.onResult(null, configError)
}
}
})
} else {
callback.onResult(null, authError)
getAuthorization { authorization, authError ->
if (authorization != null) {
configurationLoader.loadConfiguration(authorization) { configuration, configError ->
if (configuration != null) {
callback.onResult(configuration, null)
} else {
callback.onResult(null, configError)
}
}
} else {
callback.onResult(null, authError)
}
})
}
}

/**
Expand All @@ -202,15 +197,13 @@ open class BraintreeClient @VisibleForTesting internal constructor(
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun sendAnalyticsEvent(eventName: String) {
getAuthorization(object : AuthorizationCallback {
override fun onAuthorizationResult(authorization: Authorization?, error: Exception?) {
if (authorization != null) {
getConfiguration { configuration, _ ->
sendAnalyticsEvent(eventName, configuration, authorization)
}
getAuthorization { authorization, _ ->
if (authorization != null) {
getConfiguration { configuration, _ ->
sendAnalyticsEvent(eventName, configuration, authorization)
}
}
})
}
}

private fun sendAnalyticsEvent(
Expand All @@ -234,76 +227,70 @@ open class BraintreeClient @VisibleForTesting internal constructor(
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun sendGET(url: String, responseCallback: HttpResponseCallback) {
getAuthorization(object : AuthorizationCallback {
override fun onAuthorizationResult(authorization: Authorization?, authError: Exception?) {
if (authorization != null) {
getConfiguration { configuration, configError ->
if (configuration != null) {
httpClient.get(url, configuration, authorization, responseCallback)
} else {
responseCallback.onResult(null, configError)
}
getAuthorization { authorization, authError ->
if (authorization != null) {
getConfiguration { configuration, configError ->
if (configuration != null) {
httpClient.get(url, configuration, authorization, responseCallback)
} else {
responseCallback.onResult(null, configError)
}
} else {
responseCallback.onResult(null, authError)
}
} else {
responseCallback.onResult(null, authError)
}
})
}
}

/**
* @suppress
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun sendPOST(url: String, data: String, responseCallback: HttpResponseCallback) {
getAuthorization(object : AuthorizationCallback {
override fun onAuthorizationResult(authorization: Authorization?, authError: Exception?) {
if (authorization != null) {
getConfiguration { configuration, configError ->
if (configuration != null) {
httpClient.post(
url,
data,
configuration,
authorization,
responseCallback
)
} else {
responseCallback.onResult(null, configError)
}
getAuthorization { authorization, authError ->
if (authorization != null) {
getConfiguration { configuration, configError ->
if (configuration != null) {
httpClient.post(
url,
data,
configuration,
authorization,
responseCallback
)
} else {
responseCallback.onResult(null, configError)
}
} else {
responseCallback.onResult(null, authError)
}
} else {
responseCallback.onResult(null, authError)
}
})
}
}

/**
* @suppress
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun sendGraphQLPOST(payload: String?, responseCallback: HttpResponseCallback) {
getAuthorization(object : AuthorizationCallback {
override fun onAuthorizationResult(authorization: Authorization?, authError: Exception?) {
if (authorization != null) {
getConfiguration { configuration, configError ->
if (configuration != null) {
graphQLClient.post(
payload,
configuration,
authorization,
responseCallback
)
} else {
responseCallback.onResult(null, configError)
}
getAuthorization { authorization, authError ->
if (authorization != null) {
getConfiguration { configuration, configError ->
if (configuration != null) {
graphQLClient.post(
payload,
configuration,
authorization,
responseCallback
)
} else {
responseCallback.onResult(null, configError)
}
} else {
responseCallback.onResult(null, authError)
}
} else {
responseCallback.onResult(null, authError)
}
})
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.braintreepayments.api

import org.json.JSONArray
import org.json.JSONObject
import kotlin.collections.ArrayList

/**
* Contains the remote card configuration for the Braintree SDK.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.braintreepayments.api

internal interface ConfigurationLoaderCallback {
internal fun interface ConfigurationLoaderCallback {
fun onResult(result: Configuration?, error: Exception?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.json.JSONObject
* @property kountMerchantId the Kount Merchant Id.
* @property isEnabled `true` if Kount is enabled, `false` otherwise.
*/
internal data class KountConfiguration private constructor(val kountMerchantId: String) {
internal data class KountConfiguration internal constructor(val kountMerchantId: String) {

constructor(json: JSONObject?) : this(Json.optString(json, KOUNT_MERCHANT_ID_KEY, ""))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ abstract class PaymentMethod {

abstract val apiPath: String?

internal constructor()
/**
* @suppress
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
constructor()

/**
* Sets the integration method associated with the tokenization call for analytics use.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.braintreepayments.api
import android.text.TextUtils
import org.json.JSONArray
import org.json.JSONObject
import kotlin.collections.ArrayList

/**
* Contains the remote Samsung Pay configuration for the Braintree SDK.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package com.braintreepayments.api
import android.content.Context
import androidx.annotation.RestrictTo
import androidx.annotation.VisibleForTesting
import com.braintreepayments.api.BraintreeSharedPreferences
import com.braintreepayments.api.UUIDHelper
import java.util.*

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
package com.braintreepayments.api

import org.robolectric.RobolectricTestRunner
import android.net.ConnectivityManager
import android.content.pm.PackageManager
import org.robolectric.util.ReflectionHelpers
import android.os.Build.VERSION
import android.content.pm.ApplicationInfo
import android.net.NetworkInfo
import android.content.Intent
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.os.Build
import android.os.Build.VERSION
import io.mockk.*
import org.json.JSONException
import org.junit.Assert
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.util.ReflectionHelpers
import java.io.File

@RunWith(RobolectricTestRunner::class)
Expand Down
3 changes: 1 addition & 2 deletions BraintreeDataCollector/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />

<application
android:usesCleartextTraffic="true">
<application>

<!--suppress AndroidDomInspection -->
<activity android:name=".TestActivity" />
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Braintree Android SDK Release Notes

## unreleased

* ThreeDSecure
* Catch Null Pointer Exception in `ThreeDSecureActivity` to prevent crash (fixes #715)

## 4.27.0

* DataCollector
Expand Down
3 changes: 1 addition & 2 deletions Card/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />

<application
android:usesCleartextTraffic="true">
<application>

<!--suppress AndroidDomInspection -->
<activity android:name=".TestActivity" />
Expand Down
1 change: 0 additions & 1 deletion Demo/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
android:label="@string/app_name"
android:theme="@style/DemoAppTheme"
android:name=".DemoApplication"
android:usesCleartextTraffic="true"
tools:replace="android:allowBackup">

<meta-data android:name="com.google.android.gms.wallet.api.enabled" android:value="true" />
Expand Down
2 changes: 1 addition & 1 deletion LocalPayment/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />

<application android:usesCleartextTraffic="true">
<application>

<!--suppress AndroidDomInspection -->
<activity android:name=".TestActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class CardinalClient {
CardinalClient () {}

void initialize(Context context, Configuration configuration, final ThreeDSecureRequest request, final CardinalInitializeCallback callback) {
configurationCardinal(context, configuration, request);
configureCardinal(context, configuration, request);
Cardinal.getInstance().init(configuration.getCardinalAuthenticationJwt(), new CardinalInitService() {
@Override
public void onSetupCompleted(String sessionId) {
Expand All @@ -37,14 +37,18 @@ public void onValidated(ValidateResponse validateResponse, String serverJWT) {
});
}

void continueLookup(FragmentActivity activity, ThreeDSecureResult threeDSecureResult, CardinalValidateReceiver validateReceiver) {
void continueLookup(FragmentActivity activity, ThreeDSecureResult threeDSecureResult, CardinalValidateReceiver validateReceiver) throws BraintreeException {
ThreeDSecureLookup lookup = threeDSecureResult.getLookup();
String transactionId = lookup.getTransactionId();
String paReq = lookup.getPareq();
Cardinal.getInstance().cca_continue(transactionId, paReq, activity, validateReceiver);
try {
Cardinal.getInstance().cca_continue(transactionId, paReq, activity, validateReceiver);
} catch (NullPointerException e) {
throw new BraintreeException("Cardinal SDK Error.", e);
}
}

private void configurationCardinal(Context context, Configuration configuration, ThreeDSecureRequest request) {
private void configureCardinal(Context context, Configuration configuration, ThreeDSecureRequest request) {
CardinalEnvironment cardinalEnvironment = CardinalEnvironment.STAGING;
if ("production".equalsIgnoreCase(configuration.getEnvironment())) {
cardinalEnvironment = CardinalEnvironment.PRODUCTION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,23 @@ void onCreateInternal(CardinalClient cardinalClient) {

ThreeDSecureResult threeDSecureResult = extras.getParcelable(EXTRA_THREE_D_SECURE_RESULT);
if (threeDSecureResult != null) {
cardinalClient.continueLookup(this, threeDSecureResult, this);
try {
cardinalClient.continueLookup(this, threeDSecureResult, this);
} catch (BraintreeException e) {
finishWithError(e.getMessage());
}
} else {
Intent result = new Intent();
result.putExtra(EXTRA_ERROR_MESSAGE, "Unable to launch 3DS authentication.");
setResult(RESULT_COULD_NOT_START_CARDINAL, result);
finish();
finishWithError("Unable to launch 3DS authentication.");
}
}

private void finishWithError(String errorMessage) {
Intent result = new Intent();
result.putExtra(EXTRA_ERROR_MESSAGE, errorMessage);
setResult(RESULT_COULD_NOT_START_CARDINAL, result);
finish();
}

@Override
public void onValidated(Context context, ValidateResponse validateResponse, String jwt) {
Intent result = new Intent();
Expand Down
Loading

0 comments on commit fc82623

Please sign in to comment.