From eda40a916168dd4c07aec7ee3f6ce26d9171176f Mon Sep 17 00:00:00 2001 From: Shivam Date: Thu, 20 Nov 2025 14:43:22 +0530 Subject: [PATCH 1/2] feat: 3ds via authentication module ios --- example/metro.config.js | 2 +- example/package.json | 7 + example/src/App.tsx | 66 +++++- example/src/AuthenticationScreen.tsx | 187 +++++++++++++++ .../Hyperswitch3ds.podspec | 53 +++++ .../android/build.gradle | 81 +++++++ .../android/gradle.properties | 5 + .../android/src/main/AndroidManifest.xml | 3 + .../android/src/main/AndroidManifestNew.xml | 2 + .../hyperswitch3ds/Hyperswitch3dsModule.kt | 25 ++ .../hyperswitch3ds/Hyperswitch3dsPackage.kt | 17 ++ .../ios/Hyperswitch3ds-Bridging-Header.h | 2 + .../ios/Hyperswitch3ds.mm | 30 +++ .../ios/Hyperswitch3ds.swift | 219 ++++++++++++++++++ .../ios/Hyperswitch3dsChallengeManager.swift | 78 +++++++ .../react-native-hyperswitch-3ds/package.json | 25 ++ .../src/index.tsx | 88 +++++++ yarn.lock | 38 +++ 18 files changed, 926 insertions(+), 2 deletions(-) create mode 100644 example/src/AuthenticationScreen.tsx create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/Hyperswitch3ds.podspec create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/android/build.gradle create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/android/gradle.properties create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/android/src/main/AndroidManifest.xml create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/android/src/main/AndroidManifestNew.xml create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/android/src/main/java/com/hyperswitch3ds/Hyperswitch3dsModule.kt create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/android/src/main/java/com/hyperswitch3ds/Hyperswitch3dsPackage.kt create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/ios/Hyperswitch3ds-Bridging-Header.h create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/ios/Hyperswitch3ds.mm create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/ios/Hyperswitch3ds.swift create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/ios/Hyperswitch3dsChallengeManager.swift create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/package.json create mode 100644 packages/@juspay-tech/react-native-hyperswitch-3ds/src/index.tsx diff --git a/example/metro.config.js b/example/metro.config.js index 0575308..2da198e 100644 --- a/example/metro.config.js +++ b/example/metro.config.js @@ -2,7 +2,7 @@ const path = require('path'); const { getDefaultConfig } = require('@react-native/metro-config'); const { withMetroConfig } = require('react-native-monorepo-config'); -const root = path.resolve(__dirname, '..', 'packages', '@juspay-tech', 'react-native-hyperswitch'); +const root = path.resolve(__dirname, '..'); /** * Metro configuration diff --git a/example/package.json b/example/package.json index 9442e95..2b87172 100644 --- a/example/package.json +++ b/example/package.json @@ -12,6 +12,8 @@ "adb": "adb reverse tcp:8081 tcp:8081" }, "dependencies": { + "@juspay-tech/react-native-hyperswitch": "*", + "@juspay-tech/react-native-hyperswitch-3ds": "*", "@sentry/react-native": "^6.20.0", "react": "19.0.0", "react-native": "0.79.2", @@ -36,5 +38,10 @@ "react-native-builder-bob": "^0.40.8", "react-native-dotenv": "^3.4.11", "react-native-monorepo-config": "^0.1.9" + }, + "hyperswitch": { + "ios": { + "authProvider": "trident" + } } } diff --git a/example/src/App.tsx b/example/src/App.tsx index 1ad09f0..8579d07 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,12 +1,76 @@ +import { useState } from 'react'; +import { View, StyleSheet, TouchableOpacity, Text } from 'react-native'; import { HyperProvider } from '@juspay-tech/react-native-hyperswitch'; import PaymentScreen from './PaymentScreen'; +import AuthenticationScreen from './AuthenticationScreen'; + +type Screen = 'payment' | 'authentication'; export default function App() { + const [activeScreen, setActiveScreen] = useState('payment'); + return ( - + + + setActiveScreen('payment')} + > + + Payment + + + setActiveScreen('authentication')} + > + + Authentication + + + + + {activeScreen === 'payment' ? : } + + ); } + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + }, + tabBar: { + flexDirection: 'row', + backgroundColor: '#fff', + borderBottomWidth: 1, + borderBottomColor: '#e0e0e0', + paddingTop: 50, + }, + tab: { + flex: 1, + paddingVertical: 15, + alignItems: 'center', + borderBottomWidth: 2, + borderBottomColor: 'transparent', + }, + activeTab: { + borderBottomColor: '#007AFF', + }, + tabText: { + fontSize: 16, + color: '#666', + }, + activeTabText: { + color: '#007AFF', + fontWeight: '600', + }, + content: { + flex: 1, + }, +}); diff --git a/example/src/AuthenticationScreen.tsx b/example/src/AuthenticationScreen.tsx new file mode 100644 index 0000000..054a2f4 --- /dev/null +++ b/example/src/AuthenticationScreen.tsx @@ -0,0 +1,187 @@ +import { + isAvailable, + initializeThreeDS, + generateAReqParams, + recieveChallengeParamsFromRN, + generateChallenge, + threeDSProvider +} from '@juspay-tech/react-native-hyperswitch-3ds'; +import { Text, View, StyleSheet, Button, ScrollView, Platform } from 'react-native'; +import { useState } from 'react'; + +export default function AuthenticationScreen() { + const [threeDsResult, setThreeDsResult] = useState(''); + const [aReqResult, setAReqResult] = useState(''); + const [challengeParamsResult, setChallengeParamsResult] = useState(''); + const [challengeResult, setChallengeResult] = useState(''); + + const handleInitThreeDs = () => { + try { + const configuration = { + provider: threeDSProvider.trident, + publishableKey: "pk_snd_test", + }; + + initializeThreeDS(configuration, 'sandbox', (status) => { + console.log('3DS Status:', status); + setThreeDsResult(`Status: ${status.status}\nMessage: ${status.message}`); + }); + } catch (error) { + setThreeDsResult(`Error: ${error}`); + console.error('Failed to initialize 3DS session:', error); + } + }; + + const handleGenerateAReqParams = () => { + try { + const messageVersion = '2.1.0'; + const directoryServerId = 'A0000001'; + const cardBrand = 'visa'; + + generateAReqParams( + messageVersion, + (status, aReqParams) => { + const result = `Status: ${status.status}\nMessage: ${status.message}\n\nAReq Params:\n${JSON.stringify(aReqParams, null, 2)}`; + setAReqResult(result); + }, + directoryServerId, + cardBrand + ); + } catch (error) { + setAReqResult(`Error: ${error}`); + } + }; + + const handleReceiveChallengeParams = () => { + try { + const acsSignedContent = 'test_acs_signed_content'; + const acsRefNumber = 'test_acs_ref_number'; + const acsTransactionId = 'test_acs_transaction_id'; + const threeDSRequestorAppURL = 'hyperswitch://challenge'; + const threeDSServerTransId = 'test_server_trans_id'; + + recieveChallengeParamsFromRN( + acsSignedContent, + acsRefNumber, + acsTransactionId, + threeDSRequestorAppURL, + threeDSServerTransId, + (status) => { + setChallengeParamsResult(`Status: ${status.status}\nMessage: ${status.message}`); + } + ); + } catch (error) { + setChallengeParamsResult(`Error: ${error}`); + } + }; + + const handleGenerateChallenge = () => { + try { + generateChallenge((status) => { + setChallengeResult(`Status: ${status.status}\nMessage: ${status.message}`); + }); + } catch (error) { + setChallengeResult(`Error: ${error}`); + } + }; + + return ( + + Hyperswitch Auth Module Test + Module Available: {isAvailable ? '✓ Yes' : '✗ No'} + + + 1. Initialize 3DS Session +