From 3ba8e9aca51d8df94edc5bde39a7090cc8e85746 Mon Sep 17 00:00:00 2001 From: ChiragKV-Juspay Date: Thu, 20 Nov 2025 20:00:44 +0530 Subject: [PATCH 1/3] feat: created threedsmodule and threeds-trident libraries --- demo-app-threeds/.gitignore | 1 + demo-app-threeds/build.gradle | 40 ++ demo-app-threeds/proguard-rules.pro | 21 + .../ExampleInstrumentedTest.kt | 24 + demo-app-threeds/src/main/AndroidManifest.xml | 24 + .../demo_app_threeds/MainActivity.kt | 540 ++++++++++++++++++ .../res/drawable/ic_launcher_background.xml | 170 ++++++ .../res/drawable/ic_launcher_foreground.xml | 30 + .../src/main/res/layout/activity_main.xml | 55 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../src/main/res/values/colors.xml | 10 + .../src/main/res/values/strings.xml | 3 + .../src/main/res/values/themes.xml | 5 + .../demo_app_threeds/ExampleUnitTest.kt | 17 + demo-app/build.gradle | 13 +- .../.gitignore | 1 + .../build.gradle | 35 ++ .../consumer-rules.pro | 0 .../proguard-rules.pro | 21 + .../trident/ExampleInstrumentedTest.kt | 24 + .../src/main/AndroidManifest.xml | 4 + .../threeds/trident/TridentConfigurator.kt | 28 + .../threeds/trident/TridentProviderFactory.kt | 49 ++ .../threeds/trident/TridentThreeDSProvider.kt | 426 ++++++++++++++ .../threeds/trident/ExampleUnitTest.kt | 17 + hyperswitch-sdk-android-threeDS/.gitignore | 1 + hyperswitch-sdk-android-threeDS/build.gradle | 31 + .../consumer-rules.pro | 0 .../proguard-rules.pro | 21 + .../threeds/ExampleInstrumentedTest.kt | 24 + .../src/main/AndroidManifest.xml | 4 + .../io/hyperswitch/threeds/ThreeDSManager.kt | 276 +++++++++ .../api/AuthenticationRequestParameters.kt | 15 + .../threeds/api/AuthenticationResult.kt | 16 + .../threeds/api/ChallengeEvents.kt | 40 ++ .../api/ThreeDSAuthenticationSession.kt | 47 ++ .../hyperswitch/threeds/api/ThreeDSService.kt | 49 ++ .../threeds/api/ThreeDSTransaction.kt | 100 ++++ .../callbacks/AuthParametersCallback.kt | 24 + .../threeds/callbacks/ChallengeCallback.kt | 40 ++ .../callbacks/InitializationCallback.kt | 25 + .../threeds/callbacks/TransactionCallback.kt | 24 + .../threeds/models/ChallengeParameters.kt | 54 ++ .../threeds/models/ThreeDSConfiguration.kt | 30 + .../threeds/models/ThreeDSError.kt | 31 + .../threeds/models/ThreeDSProviderType.kt | 20 + .../threeds/models/TransactionRequest.kt | 51 ++ .../threeds/models/UiCustomization.kt | 65 +++ .../threeds/provider/ProviderFactory.kt | 61 ++ .../threeds/provider/ProviderRegistry.kt | 173 ++++++ .../threeds/provider/ThreeDSProvider.kt | 99 ++++ .../io/hyperswitch/threeds/ExampleUnitTest.kt | 17 + settings.gradle | 3 + 64 files changed, 2910 insertions(+), 1 deletion(-) create mode 100644 demo-app-threeds/.gitignore create mode 100644 demo-app-threeds/build.gradle create mode 100644 demo-app-threeds/proguard-rules.pro create mode 100644 demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt create mode 100644 demo-app-threeds/src/main/AndroidManifest.xml create mode 100644 demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt create mode 100644 demo-app-threeds/src/main/res/drawable/ic_launcher_background.xml create mode 100644 demo-app-threeds/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 demo-app-threeds/src/main/res/layout/activity_main.xml create mode 100644 demo-app-threeds/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 demo-app-threeds/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 demo-app-threeds/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 demo-app-threeds/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 demo-app-threeds/src/main/res/values/colors.xml create mode 100644 demo-app-threeds/src/main/res/values/strings.xml create mode 100644 demo-app-threeds/src/main/res/values/themes.xml create mode 100644 demo-app-threeds/src/test/java/io/hyperswitch/demo_app_threeds/ExampleUnitTest.kt create mode 100644 hyperswitch-sdk-android-threeDS-trident/.gitignore create mode 100644 hyperswitch-sdk-android-threeDS-trident/build.gradle create mode 100644 hyperswitch-sdk-android-threeDS-trident/consumer-rules.pro create mode 100644 hyperswitch-sdk-android-threeDS-trident/proguard-rules.pro create mode 100644 hyperswitch-sdk-android-threeDS-trident/src/androidTest/java/io/hyperswitch/threeds/trident/ExampleInstrumentedTest.kt create mode 100644 hyperswitch-sdk-android-threeDS-trident/src/main/AndroidManifest.xml create mode 100644 hyperswitch-sdk-android-threeDS-trident/src/main/java/io/hyperswitch/threeds/trident/TridentConfigurator.kt create mode 100644 hyperswitch-sdk-android-threeDS-trident/src/main/java/io/hyperswitch/threeds/trident/TridentProviderFactory.kt create mode 100644 hyperswitch-sdk-android-threeDS-trident/src/main/java/io/hyperswitch/threeds/trident/TridentThreeDSProvider.kt create mode 100644 hyperswitch-sdk-android-threeDS-trident/src/test/java/io/hyperswitch/threeds/trident/ExampleUnitTest.kt create mode 100644 hyperswitch-sdk-android-threeDS/.gitignore create mode 100644 hyperswitch-sdk-android-threeDS/build.gradle create mode 100644 hyperswitch-sdk-android-threeDS/consumer-rules.pro create mode 100644 hyperswitch-sdk-android-threeDS/proguard-rules.pro create mode 100644 hyperswitch-sdk-android-threeDS/src/androidTest/java/io/hyperswitch/threeds/ExampleInstrumentedTest.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/AndroidManifest.xml create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/ThreeDSManager.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/api/AuthenticationRequestParameters.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/api/AuthenticationResult.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/api/ChallengeEvents.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/api/ThreeDSAuthenticationSession.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/api/ThreeDSService.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/api/ThreeDSTransaction.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/callbacks/AuthParametersCallback.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/callbacks/ChallengeCallback.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/callbacks/InitializationCallback.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/callbacks/TransactionCallback.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/models/ChallengeParameters.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/models/ThreeDSConfiguration.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/models/ThreeDSError.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/models/ThreeDSProviderType.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/models/TransactionRequest.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/models/UiCustomization.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/provider/ProviderFactory.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/provider/ProviderRegistry.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/main/java/io/hyperswitch/threeds/provider/ThreeDSProvider.kt create mode 100644 hyperswitch-sdk-android-threeDS/src/test/java/io/hyperswitch/threeds/ExampleUnitTest.kt diff --git a/demo-app-threeds/.gitignore b/demo-app-threeds/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/demo-app-threeds/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/demo-app-threeds/build.gradle b/demo-app-threeds/build.gradle new file mode 100644 index 00000000..f3c8dbfc --- /dev/null +++ b/demo-app-threeds/build.gradle @@ -0,0 +1,40 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'io.hyperswitch.demo_app_threeds' + compileSdk 36 + + defaultConfig { + applicationId "io.hyperswitch.demo_app_threeds" + minSdk 24 + targetSdk 36 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation (project(":hyperswitch-sdk-android-threeDS-trident")) + + implementation("com.squareup.okhttp3:okhttp:4.12.0") + + + implementation libs.fuel + implementation libs.kotlin.coroutines + implementation libs.androidx.preference + implementation 'org.slf4j:slf4j-nop:2.0.17' + androidTestImplementation('com.wix:detox:+') +} \ No newline at end of file diff --git a/demo-app-threeds/proguard-rules.pro b/demo-app-threeds/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/demo-app-threeds/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt b/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..72b74d32 --- /dev/null +++ b/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package io.hyperswitch.demo_app_threeds + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("io.hyperswitch.demo_app_threeds", appContext.packageName) + } +} \ No newline at end of file diff --git a/demo-app-threeds/src/main/AndroidManifest.xml b/demo-app-threeds/src/main/AndroidManifest.xml new file mode 100644 index 00000000..aea25576 --- /dev/null +++ b/demo-app-threeds/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt b/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt new file mode 100644 index 00000000..4e17ba8f --- /dev/null +++ b/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt @@ -0,0 +1,540 @@ +package io.hyperswitch.demo_app_threeds + +import android.app.Activity +import android.os.Bundle +import android.util.Log +import android.widget.Button +import android.widget.TextView +import io.hyperswitch.threeds.models.ThreeDSEnvironment +import io.hyperswitch.threeds.api.* +import io.hyperswitch.threeds.models.ChallengeParameters +import io.hyperswitch.threeds.provider.ProviderRegistry +import io.hyperswitch.threeds.trident.TridentProviderFactory +import okhttp3.* +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.RequestBody.Companion.toRequestBody +import org.json.JSONObject +import java.io.IOException + +class MainActivity : Activity() { + + private lateinit var statusText: TextView + private var publishKey: String = "" + private var paymentIntentClientSecret: String = "" + + // New merchant-facing API objects + private lateinit var authenticationSession: ThreeDSAuthenticationSession + private var service: ThreeDSService? = null + private var transaction: ThreeDSTransaction? = null + private var aReqParams: AuthenticationRequestParameters? = null + private var challengeParameters: ChallengeParameters? = null + + + private val apiKey = "" + private val profileId = "" + private val baseUrl = "" + private var authenticationId: String? = null + // Eligibility response data + private var threeDsServerTransactionId: String? = null + private var messageVersion: String? = null + private var directoryServerId: String? = null + + // HTTP client - use singleton to avoid creating multiple instances + private val httpClient by lazy { + OkHttpClient.Builder() + .connectTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .readTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .writeTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .build() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + statusText = findViewById(R.id.statusText) + + // Register providers for testing + ProviderRegistry.registerProvider(TridentProviderFactory()) + + // // Initialize ThreeDSAuthenticationSession using the new unified 3DS library + // // Providers are now auto-discovered - no manual registration needed! + authenticationSession = ThreeDSAuthenticationSession(this, publishKey) + + // Log discovered providers for verification + // logDiscoveredProviders() + + setupButtons() + } + + override fun onDestroy() { + super.onDestroy() + // Clean up resources to prevent memory leaks + service = null + transaction = null + aReqParams = null + challengeParameters = null + + Log.d("ThreeDSTest", "Cleared activity references") + + // Cancel any pending HTTP calls + try { + httpClient.dispatcher.executorService.shutdown() + } catch (e: Exception) { + Log.w("ThreeDSTest", "Error shutting down HTTP client: ${e.message}") + } + } + + private fun setupButtons() { + findViewById