@sanctum-key/react-native-sdk 1.0.60 → 1.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/android/build/.transforms/ac63f648699cdd4b91e6ee06476f2a70/results.bin +1 -0
- package/android/build/.transforms/ac63f648699cdd4b91e6ee06476f2a70/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +9 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +45 -25
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +9 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +34 -12
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$BarcodeRegion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$6$1.class → SanctumKeySdkModule$definition$1$7$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$6$2.class → SanctumKeySdkModule$definition$1$7$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$1.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$5.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$3.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$3.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$4.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$2.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$5.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$6.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$4.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$7.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$8.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$6.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$9.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$1.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$2.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$3.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$3.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$4.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$4.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$5.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$5.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$6.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$6.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$7.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$7.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$View$1.class → SanctumKeySdkModule$definition$lambda$24$$inlined$View$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$1.class → SanctumKeySdkModule$definition$lambda$24$lambda$23$$inlined$Prop$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$2.class → SanctumKeySdkModule$definition$lambda$24$lambda$23$$inlined$Prop$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule.class +0 -0
- package/android/src/main/AndroidManifest.xml +9 -0
- package/android/src/main/java/kyc/sanctumkey/com/SanctumKeySdkModule.kt +147 -0
- package/build/package.json +1 -1
- package/build/src/SanctumKeySdkModule.d.ts +2 -0
- package/build/src/SanctumKeySdkModule.d.ts.map +1 -1
- package/build/src/SanctumKeySdkModule.js.map +1 -1
- package/build/src/SanctumKeySdkModule.web.d.ts +2 -0
- package/build/src/SanctumKeySdkModule.web.d.ts.map +1 -1
- package/build/src/SanctumKeySdkModule.web.js +14 -0
- package/build/src/SanctumKeySdkModule.web.js.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.js +1 -1
- package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.js +27 -17
- package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +46 -28
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/OverLay/IdCard.d.ts +1 -1
- package/build/src/components/OverLay/IdCard.d.ts.map +1 -1
- package/build/src/components/OverLay/IdCard.js +47 -14
- package/build/src/components/OverLay/IdCard.js.map +1 -1
- package/build/src/components/OverLay/type.d.ts +2 -0
- package/build/src/components/OverLay/type.d.ts.map +1 -1
- package/build/src/components/OverLay/type.js.map +1 -1
- package/build/src/components/Svgs/scanningLine.d.ts +4 -1
- package/build/src/components/Svgs/scanningLine.d.ts.map +1 -1
- package/build/src/components/Svgs/scanningLine.js +15 -11
- package/build/src/components/Svgs/scanningLine.js.map +1 -1
- package/build/src/components/TemplateKYCExample.d.ts +4 -1
- package/build/src/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/src/components/TemplateKYCExample.js +2 -2
- package/build/src/components/TemplateKYCExample.js.map +1 -1
- package/build/src/components/TemplateKYCFlowRefactored.d.ts +4 -2
- package/build/src/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/src/components/TemplateKYCFlowRefactored.js +157 -8
- package/build/src/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/src/config/region_mapping.d.ts.map +1 -1
- package/build/src/config/region_mapping.js +28 -0
- package/build/src/config/region_mapping.js.map +1 -1
- package/build/src/config/region_mapping.json +28 -0
- package/build/src/index.d.ts +2 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +2 -0
- package/build/src/index.js.map +1 -1
- package/build/src/security/deviceSecurity.d.ts +30 -0
- package/build/src/security/deviceSecurity.d.ts.map +1 -0
- package/build/src/security/deviceSecurity.js +55 -0
- package/build/src/security/deviceSecurity.js.map +1 -0
- package/build/src/utils/logger.d.ts.map +1 -1
- package/build/src/utils/logger.js +5 -0
- package/build/src/utils/logger.js.map +1 -1
- package/ios/SanctumKeySdkModule.swift +93 -0
- package/package.json +1 -1
- package/src/SanctumKeySdkModule.ts +2 -0
- package/src/SanctumKeySdkModule.web.ts +16 -0
- package/src/components/KYCElements/CountrySelection.tsx +3 -1
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +73 -24
- package/src/components/KYCElements/IDCardCapture.tsx +53 -30
- package/src/components/OverLay/IdCard.tsx +72 -15
- package/src/components/OverLay/type.ts +4 -2
- package/src/components/Svgs/scanningLine.tsx +19 -12
- package/src/components/TemplateKYCExample.tsx +8 -1
- package/src/components/TemplateKYCFlowRefactored.tsx +202 -16
- package/src/config/region_mapping.json +28 -0
- package/src/config/region_mapping.ts +28 -0
- package/src/index.ts +9 -1
- package/src/security/deviceSecurity.ts +106 -0
- package/src/utils/logger.ts +5 -0
|
@@ -8,6 +8,9 @@ import android.graphics.BitmapFactory
|
|
|
8
8
|
import android.graphics.Color
|
|
9
9
|
import android.graphics.Matrix
|
|
10
10
|
import android.net.Uri
|
|
11
|
+
import android.os.Build
|
|
12
|
+
import android.os.Debug
|
|
13
|
+
import android.provider.Settings
|
|
11
14
|
import android.view.Gravity
|
|
12
15
|
import android.view.View
|
|
13
16
|
import android.widget.FrameLayout
|
|
@@ -39,6 +42,7 @@ import expo.modules.kotlin.viewevent.EventDispatcher
|
|
|
39
42
|
import expo.modules.kotlin.views.ExpoView
|
|
40
43
|
import java.io.FileInputStream
|
|
41
44
|
import java.io.InputStream
|
|
45
|
+
import java.io.File
|
|
42
46
|
import java.util.EnumMap
|
|
43
47
|
import java.util.concurrent.TimeUnit
|
|
44
48
|
import kotlin.math.ceil
|
|
@@ -440,6 +444,137 @@ class SanctumKeySdkModule : Module() {
|
|
|
440
444
|
?: decodeBarcodeWithZxing(imagePath, requestedFormats)
|
|
441
445
|
}
|
|
442
446
|
|
|
447
|
+
private fun isProbablyEmulator(): Boolean {
|
|
448
|
+
val fingerprint = Build.FINGERPRINT.lowercase()
|
|
449
|
+
val model = Build.MODEL.lowercase()
|
|
450
|
+
val manufacturer = Build.MANUFACTURER.lowercase()
|
|
451
|
+
val brand = Build.BRAND.lowercase()
|
|
452
|
+
val device = Build.DEVICE.lowercase()
|
|
453
|
+
val product = Build.PRODUCT.lowercase()
|
|
454
|
+
val hardware = Build.HARDWARE.lowercase()
|
|
455
|
+
val board = Build.BOARD.lowercase()
|
|
456
|
+
|
|
457
|
+
return fingerprint.startsWith("generic") ||
|
|
458
|
+
fingerprint.startsWith("unknown") ||
|
|
459
|
+
fingerprint.contains("emulator") ||
|
|
460
|
+
fingerprint.contains("test-keys") && model.contains("sdk") ||
|
|
461
|
+
model.contains("google_sdk") ||
|
|
462
|
+
model.contains("emulator") ||
|
|
463
|
+
model.contains("android sdk built for") ||
|
|
464
|
+
manufacturer.contains("genymotion") ||
|
|
465
|
+
hardware.contains("goldfish") ||
|
|
466
|
+
hardware.contains("ranchu") ||
|
|
467
|
+
hardware.contains("vbox86") ||
|
|
468
|
+
board.contains("goldfish") ||
|
|
469
|
+
product.contains("sdk_gphone") ||
|
|
470
|
+
product.contains("google_sdk") ||
|
|
471
|
+
product.contains("sdk_x86") ||
|
|
472
|
+
product.contains("vbox86p") ||
|
|
473
|
+
(brand.startsWith("generic") && device.startsWith("generic"))
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
private fun rootSignals(context: Context): List<String> {
|
|
477
|
+
val signals = mutableSetOf<String>()
|
|
478
|
+
val tags = Build.TAGS.orEmpty()
|
|
479
|
+
if (tags.contains("test-keys")) signals.add("android_build_test_keys")
|
|
480
|
+
|
|
481
|
+
val rootPaths = listOf(
|
|
482
|
+
"/system/app/Superuser.apk",
|
|
483
|
+
"/system/bin/su",
|
|
484
|
+
"/system/xbin/su",
|
|
485
|
+
"/sbin/su",
|
|
486
|
+
"/su/bin/su",
|
|
487
|
+
"/data/local/su",
|
|
488
|
+
"/data/local/bin/su",
|
|
489
|
+
"/data/local/xbin/su",
|
|
490
|
+
"/data/adb/magisk",
|
|
491
|
+
"/sbin/.magisk",
|
|
492
|
+
"/init.magisk.rc"
|
|
493
|
+
)
|
|
494
|
+
rootPaths.firstOrNull { File(it).exists() }?.let { signals.add("root_artifact:$it") }
|
|
495
|
+
|
|
496
|
+
System.getenv("PATH")
|
|
497
|
+
?.split(File.pathSeparator)
|
|
498
|
+
?.firstOrNull { directory -> File(directory, "su").exists() }
|
|
499
|
+
?.let { signals.add("su_binary_on_path") }
|
|
500
|
+
|
|
501
|
+
val rootManagementPackages = listOf(
|
|
502
|
+
"com.topjohnwu.magisk",
|
|
503
|
+
"eu.chainfire.supersu",
|
|
504
|
+
"com.noshufou.android.su",
|
|
505
|
+
"com.koushikdutta.superuser",
|
|
506
|
+
"com.thirdparty.superuser"
|
|
507
|
+
)
|
|
508
|
+
rootManagementPackages.firstOrNull { packageName ->
|
|
509
|
+
try {
|
|
510
|
+
@Suppress("DEPRECATION")
|
|
511
|
+
context.packageManager.getApplicationInfo(packageName, 0)
|
|
512
|
+
true
|
|
513
|
+
} catch (_: Exception) {
|
|
514
|
+
false
|
|
515
|
+
}
|
|
516
|
+
}?.let { signals.add("root_management_app:$it") }
|
|
517
|
+
|
|
518
|
+
return signals.toList()
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
private fun getDeviceSecurityStatus(): Map<String, Any> {
|
|
522
|
+
val context = appContext.reactContext
|
|
523
|
+
?: return mapOf(
|
|
524
|
+
"platform" to "android",
|
|
525
|
+
"supported" to false,
|
|
526
|
+
"isRooted" to false,
|
|
527
|
+
"isJailbroken" to false,
|
|
528
|
+
"isEmulator" to false,
|
|
529
|
+
"isDeveloperModeEnabled" to false,
|
|
530
|
+
"developerModeCheckSupported" to true,
|
|
531
|
+
"isDebuggerAttached" to false,
|
|
532
|
+
"isCompromised" to false,
|
|
533
|
+
"riskSignals" to listOf("android_context_unavailable")
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
val signals = rootSignals(context).toMutableSet()
|
|
537
|
+
val isEmulator = isProbablyEmulator()
|
|
538
|
+
val developerOptionsEnabled = try {
|
|
539
|
+
Settings.Global.getInt(
|
|
540
|
+
context.contentResolver,
|
|
541
|
+
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
|
|
542
|
+
0
|
|
543
|
+
) == 1
|
|
544
|
+
} catch (_: Exception) {
|
|
545
|
+
false
|
|
546
|
+
}
|
|
547
|
+
val adbEnabled = try {
|
|
548
|
+
Settings.Global.getInt(context.contentResolver, Settings.Global.ADB_ENABLED, 0) == 1
|
|
549
|
+
} catch (_: Exception) {
|
|
550
|
+
false
|
|
551
|
+
}
|
|
552
|
+
val developerModeEnabled = developerOptionsEnabled || adbEnabled
|
|
553
|
+
val debuggerAttached = Debug.isDebuggerConnected() || Debug.waitingForDebugger()
|
|
554
|
+
|
|
555
|
+
if (isEmulator) signals.add("android_emulator_build")
|
|
556
|
+
if (developerOptionsEnabled) signals.add("android_developer_options_enabled")
|
|
557
|
+
if (adbEnabled) signals.add("android_adb_enabled")
|
|
558
|
+
if (debuggerAttached) signals.add("android_debugger_attached")
|
|
559
|
+
|
|
560
|
+
val isRooted = signals.any {
|
|
561
|
+
it.startsWith("root_") || it.startsWith("su_") || it == "android_build_test_keys"
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return mapOf(
|
|
565
|
+
"platform" to "android",
|
|
566
|
+
"supported" to true,
|
|
567
|
+
"isRooted" to isRooted,
|
|
568
|
+
"isJailbroken" to false,
|
|
569
|
+
"isEmulator" to isEmulator,
|
|
570
|
+
"isDeveloperModeEnabled" to developerModeEnabled,
|
|
571
|
+
"developerModeCheckSupported" to true,
|
|
572
|
+
"isDebuggerAttached" to debuggerAttached,
|
|
573
|
+
"isCompromised" to isRooted,
|
|
574
|
+
"riskSignals" to signals.toList()
|
|
575
|
+
)
|
|
576
|
+
}
|
|
577
|
+
|
|
443
578
|
override fun definition() = ModuleDefinition {
|
|
444
579
|
Name("SanctumKeySdk")
|
|
445
580
|
|
|
@@ -457,6 +592,18 @@ class SanctumKeySdkModule : Module() {
|
|
|
457
592
|
}
|
|
458
593
|
}
|
|
459
594
|
|
|
595
|
+
AsyncFunction("checkDeviceSecurity") { promise: Promise ->
|
|
596
|
+
try {
|
|
597
|
+
promise.resolve(getDeviceSecurityStatus())
|
|
598
|
+
} catch (error: Exception) {
|
|
599
|
+
promise.reject(
|
|
600
|
+
"DEVICE_SECURITY_CHECK_ERROR",
|
|
601
|
+
error.message ?: "Unable to check device security",
|
|
602
|
+
error
|
|
603
|
+
)
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
460
607
|
AsyncFunction("requestCameraPermission") { promise: Promise ->
|
|
461
608
|
val activity = appContext.currentActivity
|
|
462
609
|
if (activity == null) {
|
package/build/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { NativeModule } from 'expo';
|
|
2
2
|
import { SanctumKeySdkModuleEvents } from './SanctumKeySdk.types';
|
|
3
|
+
import type { DeviceSecurityCheckResult } from './security/deviceSecurity';
|
|
3
4
|
declare class SanctumKeySdkModule extends NativeModule<SanctumKeySdkModuleEvents> {
|
|
4
5
|
PI: number;
|
|
5
6
|
testModule(): Promise<string>;
|
|
7
|
+
checkDeviceSecurity(): Promise<Omit<DeviceSecurityCheckResult, 'checkedAt'>>;
|
|
6
8
|
requestCameraPermission(): Promise<boolean>;
|
|
7
9
|
decodeBarcodeFromImage?(imagePath: string, formats: string[]): Promise<string | null>;
|
|
8
10
|
openCameraWithInstructions(instructions: string): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanctumKeySdkModule.d.ts","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"SanctumKeySdkModule.d.ts","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAE3E,OAAO,OAAO,mBAAoB,SAAQ,YAAY,CAAC,yBAAyB,CAAC;IAC/E,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAC7B,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,WAAW,CAAC,CAAC;IAC5E,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;IAC3C,sBAAsB,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACrF,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9G,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnH;;AAGD,wBAAyE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanctumKeySdkModule.js","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"SanctumKeySdkModule.js","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAiBxD,yDAAyD;AACzD,eAAe,mBAAmB,CAAsB,eAAe,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\n\nimport { NativeModule } from 'expo';\n\nimport { SanctumKeySdkModuleEvents } from './SanctumKeySdk.types';\nimport type { DeviceSecurityCheckResult } from './security/deviceSecurity';\n\ndeclare class SanctumKeySdkModule extends NativeModule<SanctumKeySdkModuleEvents> {\n PI: number;\n testModule(): Promise<string>;\n checkDeviceSecurity(): Promise<Omit<DeviceSecurityCheckResult, 'checkedAt'>>;\n requestCameraPermission(): Promise<boolean>;\n decodeBarcodeFromImage?(imagePath: string, formats: string[]): Promise<string | null>;\n openCameraWithInstructions(instructions: string): Promise<{ success: boolean; path?: string; error?: string }>;\n openFilePicker(allowedTypes: string[]): Promise<{ success: boolean; uri?: string; path?: string; error?: string }>;\n}\n\n// This call loads the native module object from the JSI.\nexport default requireNativeModule<SanctumKeySdkModule>('SanctumKeySdk');\n"]}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { NativeModule } from 'expo';
|
|
2
2
|
import { SanctumKeySdkModuleEvents } from './SanctumKeySdk.types';
|
|
3
|
+
import type { DeviceSecurityCheckResult } from './security/deviceSecurity';
|
|
3
4
|
declare class SanctumKeySdkModule extends NativeModule<SanctumKeySdkModuleEvents> {
|
|
4
5
|
PI: number;
|
|
6
|
+
checkDeviceSecurity(): Promise<Omit<DeviceSecurityCheckResult, 'checkedAt'>>;
|
|
5
7
|
requestCameraPermission(): Promise<boolean>;
|
|
6
8
|
openCameraWithInstructions(instructions: string): Promise<{
|
|
7
9
|
success: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanctumKeySdkModule.web.d.ts","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"SanctumKeySdkModule.web.d.ts","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAE3E,cAAM,mBAAoB,SAAQ,YAAY,CAAC,yBAAyB,CAAC;IACvE,EAAE,SAAW;IAEP,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,WAAW,CAAC,CAAC;IAe5E,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;IAK3C,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAQ9G,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAOzH;;AAED,wBAA6E"}
|
|
@@ -2,6 +2,20 @@ import { registerWebModule } from 'expo-modules-core';
|
|
|
2
2
|
import { NativeModule } from 'expo';
|
|
3
3
|
class SanctumKeySdkModule extends NativeModule {
|
|
4
4
|
PI = Math.PI;
|
|
5
|
+
async checkDeviceSecurity() {
|
|
6
|
+
return {
|
|
7
|
+
platform: 'web',
|
|
8
|
+
supported: false,
|
|
9
|
+
isRooted: false,
|
|
10
|
+
isJailbroken: false,
|
|
11
|
+
isEmulator: false,
|
|
12
|
+
isDeveloperModeEnabled: false,
|
|
13
|
+
developerModeCheckSupported: false,
|
|
14
|
+
isDebuggerAttached: false,
|
|
15
|
+
isCompromised: false,
|
|
16
|
+
riskSignals: ['native_device_security_check_unavailable_on_web'],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
5
19
|
async requestCameraPermission() {
|
|
6
20
|
console.warn('Camera permission not available on web');
|
|
7
21
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanctumKeySdkModule.web.js","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SanctumKeySdkModule.web.js","sourceRoot":"","sources":["../../src/SanctumKeySdkModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAKpC,MAAM,mBAAoB,SAAQ,YAAuC;IACvE,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;IAEb,KAAK,CAAC,mBAAmB;QACvB,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,KAAK;YACnB,UAAU,EAAE,KAAK;YACjB,sBAAsB,EAAE,KAAK;YAC7B,2BAA2B,EAAE,KAAK;YAClC,kBAAkB,EAAE,KAAK;YACzB,aAAa,EAAE,KAAK;YACpB,WAAW,EAAE,CAAC,iDAAiD,CAAC;SACjE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,uBAAuB;QAC3B,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,0BAA0B,CAAC,YAAoB;QACnD,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC5C,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,sCAAsC;SAC9C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,YAAsB;QACzC,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QACjD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,2CAA2C;SACnD,CAAC;IACJ,CAAC;CACF;AAED,eAAe,iBAAiB,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC","sourcesContent":["import { registerWebModule } from 'expo-modules-core';\nimport { NativeModule } from 'expo';\n\nimport { SanctumKeySdkModuleEvents } from './SanctumKeySdk.types';\nimport type { DeviceSecurityCheckResult } from './security/deviceSecurity';\n\nclass SanctumKeySdkModule extends NativeModule<SanctumKeySdkModuleEvents> {\n PI = Math.PI;\n\n async checkDeviceSecurity(): Promise<Omit<DeviceSecurityCheckResult, 'checkedAt'>> {\n return {\n platform: 'web',\n supported: false,\n isRooted: false,\n isJailbroken: false,\n isEmulator: false,\n isDeveloperModeEnabled: false,\n developerModeCheckSupported: false,\n isDebuggerAttached: false,\n isCompromised: false,\n riskSignals: ['native_device_security_check_unavailable_on_web'],\n };\n }\n \n async requestCameraPermission(): Promise<boolean> {\n console.warn('Camera permission not available on web');\n return false;\n }\n \n async openCameraWithInstructions(instructions: string): Promise<{ success: boolean; path?: string; error?: string }> {\n console.warn('Camera not available on web');\n return {\n success: false,\n error: 'Camera not available on web platform'\n };\n }\n \n async openFilePicker(allowedTypes: string[]): Promise<{ success: boolean; uri?: string; path?: string; error?: string }> {\n console.warn('File picker not available on web');\n return {\n success: false,\n error: 'File picker not available on web platform'\n };\n }\n}\n\nexport default registerWebModule(SanctumKeySdkModule, 'SanctumKeySdkModule');\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountrySelection.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/CountrySelection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAoB,MAAM,uBAAuB,CAAC;AAIrE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"CountrySelection.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/CountrySelection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAoB,MAAM,uBAAuB,CAAC;AAIrE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAsH5D,CAAC"}
|
|
@@ -60,7 +60,7 @@ export const CountrySelection = ({ element, value, onValueChange, error, }) => {
|
|
|
60
60
|
|
|
61
61
|
<FlatList data={filteredCountries} keyExtractor={(item) => item.value} renderItem={renderCountry} showsVerticalScrollIndicator={true} // Enable scroll indicator for better UX visibility
|
|
62
62
|
contentContainerStyle={styles.listContent} keyboardShouldPersistTaps="handled" keyboardDismissMode="on-drag" // 🚨 UX FIX: Hides keyboard naturally when user starts scrolling
|
|
63
|
-
initialNumToRender={15} maxToRenderPerBatch={20} windowSize={5} removeClippedSubviews={true} accessibilityRole="list" ListEmptyComponent={<Text style={styles.emptyText} accessibilityRole="text">
|
|
63
|
+
nestedScrollEnabled persistentScrollbar initialNumToRender={15} maxToRenderPerBatch={20} windowSize={5} removeClippedSubviews={true} accessibilityRole="list" ListEmptyComponent={<Text style={styles.emptyText} accessibilityRole="text">
|
|
64
64
|
Aucun pays configuré ou trouvé.
|
|
65
65
|
</Text>}/>
|
|
66
66
|
{error && (<Text style={styles.errorText} accessibilityRole="alert">{error}</Text>)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountrySelection.js","sourceRoot":"","sources":["../../../../src/components/KYCElements/CountrySelection.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useMemo, useEffect } from 'react';\nimport { View, Text, TouchableOpacity, StyleSheet, FlatList, TextInput } from 'react-native';\nimport { KYCElement, KYCElementOption } from '../../types/KYC.types';\nimport { sdkLogger } from '../../utils/logger'; \nimport { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow'; \n\ninterface CountrySelectionProps {\n element: KYCElement;\n value?: string;\n onValueChange: (value: string) => void;\n error?: string;\n}\n\nexport const CountrySelection: React.FC<CountrySelectionProps> = ({\n element,\n value,\n onValueChange,\n error,\n}) => {\n const countries = element.options || [];\n const [searchQuery, setSearchQuery] = useState('');\n \n const { state } = useTemplateKYCFlowContext();\n\n useEffect(() => {\n if (state.session?.session_id) {\n sdkLogger.info(\"User started country selection step\", { \n availableCountriesCount: countries.length \n });\n }\n }, [state.session?.session_id, countries.length]);\n\n // Filter countries based on user input\n const filteredCountries = useMemo(() => {\n if (!searchQuery.trim()) return countries;\n return countries.filter(country =>\n country.label.toLowerCase().includes(searchQuery.toLowerCase())\n );\n }, [countries, searchQuery]);\n\n // Extract the render logic into a separate function for FlatList performance\n const renderCountry = ({ item: country }: { item: KYCElementOption }) => {\n const isSelected = value === country.value;\n\n return (\n <TouchableOpacity\n style={[\n styles.option,\n isSelected && styles.selectedOption\n ]}\n onPress={() => {\n sdkLogger.info(\"User selected country\", { countryCode: country.value }); // 🚨 LOG\n onValueChange(country.value);\n }}\n activeOpacity={0.7}\n // Accessibility Enhancements\n accessible={true}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: isSelected }}\n accessibilityLabel={`${country.label}. ${isSelected ? 'Selected' : 'Unselected'}.`}\n accessibilityHint={`Tap to select ${country.label} as your country`}\n >\n <Text style={styles.optionIcon}>{country.icon}</Text>\n <View style={styles.optionContent}>\n <Text style={[\n styles.optionLabel,\n isSelected && styles.selectedOptionLabel\n ]}>\n {country.label}\n </Text>\n {country.description && (\n <Text style={styles.optionDescription}>{country.description}</Text>\n )}\n </View>\n {isSelected && (\n <View style={styles.checkmark}>\n <Text style={styles.checkmarkText}>✓</Text>\n </View>\n )}\n </TouchableOpacity>\n );\n };\n\n return (\n <View style={styles.container}>\n <View style={styles.headerContainer}>\n <Text style={styles.title} accessibilityRole=\"header\">{element.title}</Text>\n <Text style={styles.description}>{element.description}</Text>\n\n {/* Search Bar */}\n <TextInput\n style={styles.searchInput}\n placeholder=\"Rechercher un pays...\"\n placeholderTextColor=\"#999\"\n value={searchQuery}\n onChangeText={setSearchQuery}\n clearButtonMode=\"while-editing\" // Adds a clear 'x' on iOS\n \n // Accessibility for Search\n accessibilityRole=\"search\"\n accessibilityLabel=\"Search countries\"\n accessibilityHint=\"Type to filter the list of configured countries below\"\n />\n </View>\n\n <FlatList\n data={filteredCountries}\n keyExtractor={(item) => item.value}\n renderItem={renderCountry}\n showsVerticalScrollIndicator={true} // Enable scroll indicator for better UX visibility\n contentContainerStyle={styles.listContent}\n keyboardShouldPersistTaps=\"handled\"\n keyboardDismissMode=\"on-drag\" // 🚨 UX FIX: Hides keyboard naturally when user starts scrolling\n initialNumToRender={15}\n maxToRenderPerBatch={20}\n windowSize={5}\n removeClippedSubviews={true}\n accessibilityRole=\"list\"\n ListEmptyComponent={\n <Text style={styles.emptyText} accessibilityRole=\"text\">\n Aucun pays configuré ou trouvé.\n </Text>\n }\n />\n {error && (\n <Text style={styles.errorText} accessibilityRole=\"alert\">{error}</Text>\n )}\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: '#fff', },\n headerContainer: { paddingHorizontal: 16, paddingTop: 16, paddingBottom: 8, },\n title: { fontSize: 24, fontWeight: 'bold', color: '#333', marginBottom: 8, textAlign: 'center', },\n description: { fontSize: 16, color: '#666', textAlign: 'center', marginBottom: 16, lineHeight: 22, },\n searchInput: { backgroundColor: '#f5f5f5', borderRadius: 10, padding: 12, fontSize: 16, color: '#333', borderWidth: 1, borderColor: '#e5e5e5', marginBottom: 8, },\n listContent: { paddingHorizontal: 16, paddingBottom: 24, },\n emptyText: { textAlign: 'center', color: '#999', marginTop: 20, fontSize: 16, },\n option: { flexDirection: 'row', alignItems: 'center', padding: 16, backgroundColor: 'white', borderRadius: 12, marginBottom: 12, borderWidth: 2, borderColor: '#e5e5e5', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.05, shadowRadius: 3.84, elevation: 3, },\n selectedOption: { borderColor: '#4CAF50', backgroundColor: '#f0f9f0', },\n optionIcon: { fontSize: 32, marginRight: 16, },\n optionContent: { flex: 1, },\n optionLabel: { fontSize: 18, fontWeight: '600', color: '#333', },\n selectedOptionLabel: { color: '#4CAF50', },\n optionDescription: { fontSize: 14, color: '#666', marginTop: 4, },\n checkmark: { width: 24, height: 24, borderRadius: 12, backgroundColor: '#4CAF50', justifyContent: 'center', alignItems: 'center', },\n checkmarkText: { color: 'white', fontSize: 16, fontWeight: 'bold', },\n errorText: { color: '#dc2626', fontSize: 14, margin: 16, textAlign: 'center', },\n});"]}
|
|
1
|
+
{"version":3,"file":"CountrySelection.js","sourceRoot":"","sources":["../../../../src/components/KYCElements/CountrySelection.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useMemo, useEffect } from 'react';\nimport { View, Text, TouchableOpacity, StyleSheet, FlatList, TextInput } from 'react-native';\nimport { KYCElement, KYCElementOption } from '../../types/KYC.types';\nimport { sdkLogger } from '../../utils/logger'; \nimport { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow'; \n\ninterface CountrySelectionProps {\n element: KYCElement;\n value?: string;\n onValueChange: (value: string) => void;\n error?: string;\n}\n\nexport const CountrySelection: React.FC<CountrySelectionProps> = ({\n element,\n value,\n onValueChange,\n error,\n}) => {\n const countries = element.options || [];\n const [searchQuery, setSearchQuery] = useState('');\n \n const { state } = useTemplateKYCFlowContext();\n\n useEffect(() => {\n if (state.session?.session_id) {\n sdkLogger.info(\"User started country selection step\", { \n availableCountriesCount: countries.length \n });\n }\n }, [state.session?.session_id, countries.length]);\n\n // Filter countries based on user input\n const filteredCountries = useMemo(() => {\n if (!searchQuery.trim()) return countries;\n return countries.filter(country =>\n country.label.toLowerCase().includes(searchQuery.toLowerCase())\n );\n }, [countries, searchQuery]);\n\n // Extract the render logic into a separate function for FlatList performance\n const renderCountry = ({ item: country }: { item: KYCElementOption }) => {\n const isSelected = value === country.value;\n\n return (\n <TouchableOpacity\n style={[\n styles.option,\n isSelected && styles.selectedOption\n ]}\n onPress={() => {\n sdkLogger.info(\"User selected country\", { countryCode: country.value }); // 🚨 LOG\n onValueChange(country.value);\n }}\n activeOpacity={0.7}\n // Accessibility Enhancements\n accessible={true}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: isSelected }}\n accessibilityLabel={`${country.label}. ${isSelected ? 'Selected' : 'Unselected'}.`}\n accessibilityHint={`Tap to select ${country.label} as your country`}\n >\n <Text style={styles.optionIcon}>{country.icon}</Text>\n <View style={styles.optionContent}>\n <Text style={[\n styles.optionLabel,\n isSelected && styles.selectedOptionLabel\n ]}>\n {country.label}\n </Text>\n {country.description && (\n <Text style={styles.optionDescription}>{country.description}</Text>\n )}\n </View>\n {isSelected && (\n <View style={styles.checkmark}>\n <Text style={styles.checkmarkText}>✓</Text>\n </View>\n )}\n </TouchableOpacity>\n );\n };\n\n return (\n <View style={styles.container}>\n <View style={styles.headerContainer}>\n <Text style={styles.title} accessibilityRole=\"header\">{element.title}</Text>\n <Text style={styles.description}>{element.description}</Text>\n\n {/* Search Bar */}\n <TextInput\n style={styles.searchInput}\n placeholder=\"Rechercher un pays...\"\n placeholderTextColor=\"#999\"\n value={searchQuery}\n onChangeText={setSearchQuery}\n clearButtonMode=\"while-editing\" // Adds a clear 'x' on iOS\n \n // Accessibility for Search\n accessibilityRole=\"search\"\n accessibilityLabel=\"Search countries\"\n accessibilityHint=\"Type to filter the list of configured countries below\"\n />\n </View>\n\n <FlatList\n data={filteredCountries}\n keyExtractor={(item) => item.value}\n renderItem={renderCountry}\n showsVerticalScrollIndicator={true} // Enable scroll indicator for better UX visibility\n contentContainerStyle={styles.listContent}\n keyboardShouldPersistTaps=\"handled\"\n keyboardDismissMode=\"on-drag\" // 🚨 UX FIX: Hides keyboard naturally when user starts scrolling\n nestedScrollEnabled\n persistentScrollbar\n initialNumToRender={15}\n maxToRenderPerBatch={20}\n windowSize={5}\n removeClippedSubviews={true}\n accessibilityRole=\"list\"\n ListEmptyComponent={\n <Text style={styles.emptyText} accessibilityRole=\"text\">\n Aucun pays configuré ou trouvé.\n </Text>\n }\n />\n {error && (\n <Text style={styles.errorText} accessibilityRole=\"alert\">{error}</Text>\n )}\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: '#fff', },\n headerContainer: { paddingHorizontal: 16, paddingTop: 16, paddingBottom: 8, },\n title: { fontSize: 24, fontWeight: 'bold', color: '#333', marginBottom: 8, textAlign: 'center', },\n description: { fontSize: 16, color: '#666', textAlign: 'center', marginBottom: 16, lineHeight: 22, },\n searchInput: { backgroundColor: '#f5f5f5', borderRadius: 10, padding: 12, fontSize: 16, color: '#333', borderWidth: 1, borderColor: '#e5e5e5', marginBottom: 8, },\n listContent: { paddingHorizontal: 16, paddingBottom: 24, },\n emptyText: { textAlign: 'center', color: '#999', marginTop: 20, fontSize: 16, },\n option: { flexDirection: 'row', alignItems: 'center', padding: 16, backgroundColor: 'white', borderRadius: 12, marginBottom: 12, borderWidth: 2, borderColor: '#e5e5e5', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.05, shadowRadius: 3.84, elevation: 3, },\n selectedOption: { borderColor: '#4CAF50', backgroundColor: '#f0f9f0', },\n optionIcon: { fontSize: 32, marginRight: 16, },\n optionContent: { flex: 1, },\n optionLabel: { fontSize: 18, fontWeight: '600', color: '#333', },\n selectedOptionLabel: { color: '#4CAF50', },\n optionDescription: { fontSize: 14, color: '#666', marginTop: 4, },\n checkmark: { width: 24, height: 24, borderRadius: 12, backgroundColor: '#4CAF50', justifyContent: 'center', alignItems: 'center', },\n checkmarkText: { color: 'white', fontSize: 16, fontWeight: 'bold', },\n errorText: { color: '#dc2626', fontSize: 14, margin: 16, textAlign: 'center', },\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountrySelectionTemplate.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/CountrySelectionTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAyC,OAAO,EAAgB,MAAM,uBAAuB,CAAC;AAQxH,UAAU,6BAA6B;IACrC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACrF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAeD,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC,6BAA6B,
|
|
1
|
+
{"version":3,"file":"CountrySelectionTemplate.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/CountrySelectionTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAyC,OAAO,EAAgB,MAAM,uBAAuB,CAAC;AAQxH,UAAU,6BAA6B;IACrC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACrF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAeD,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC,6BAA6B,CAoW5E,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useMemo, useEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FlatList, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import { countryMapping } from '../../config/region_mapping';
|
|
4
4
|
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
5
5
|
import { Button } from '../ui/Button';
|
|
@@ -195,18 +195,26 @@ export const CountrySelectionTemplate = ({ component, value, onValueChange, erro
|
|
|
195
195
|
};
|
|
196
196
|
const renderCountrySelection = () => {
|
|
197
197
|
return (<>
|
|
198
|
-
<TextInput style={styles.searchBar} placeholder={state.currentLanguage === "en" ? "
|
|
199
|
-
<
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
198
|
+
<TextInput style={styles.searchBar} placeholder={state.currentLanguage === "en" ? "Search countries" : "Rechercher un pays"} placeholderTextColor="#64748B" value={searchQuery} onChangeText={setSearchQuery} autoCorrect={false} autoCapitalize="none" clearButtonMode="while-editing" returnKeyType="search" accessibilityRole="search" accessibilityLabel={state.currentLanguage === "en" ? "Search countries" : "Rechercher un pays"} accessibilityHint={state.currentLanguage === "en" ? "Filters the country list as you type" : "Filtre la liste des pays pendant la saisie"}/>
|
|
199
|
+
<FlatList style={styles.listContainer} contentContainerStyle={[
|
|
200
|
+
styles.listContent,
|
|
201
|
+
filteredCountries.length === 0 && styles.emptyListContent,
|
|
202
|
+
]} data={filteredCountries} keyExtractor={(country) => country.code} renderItem={({ item: country }) => {
|
|
203
|
+
const isSelected = selectedCountryCode === country.code;
|
|
204
|
+
const countryName = state.currentLanguage === "en" ? country.name_en : country.name;
|
|
205
|
+
return (<TouchableOpacity style={[styles.option, isSelected && styles.selectedOption]} onPress={() => handleCountrySelect(country.code)} activeOpacity={0.7} accessible accessibilityRole="radio" accessibilityState={{ selected: isSelected }} accessibilityLabel={`${countryName}, ${country.code}`} accessibilityHint={state.currentLanguage === "en" ? "Select this issuing country" : "Sélectionner ce pays émetteur"}>
|
|
206
|
+
<Text style={styles.flag} accessible={false}>{country.flag}</Text>
|
|
207
|
+
<View style={styles.optionContent}>
|
|
208
|
+
<Text style={[styles.optionName, isSelected && styles.selectedOptionName]}>{countryName}</Text>
|
|
209
|
+
<Text style={styles.optionCode}>{country.code}</Text>
|
|
210
|
+
</View>
|
|
211
|
+
{isSelected && (<View style={[styles.checkmark, { backgroundColor: component.ui.themeColor || '#2DBD60' }]} accessible={false}>
|
|
212
|
+
<Text style={styles.checkmarkText}>✓</Text>
|
|
213
|
+
</View>)}
|
|
214
|
+
</TouchableOpacity>);
|
|
215
|
+
}} ListEmptyComponent={<Text style={styles.emptyText} accessibilityRole="text">
|
|
216
|
+
{state.currentLanguage === "en" ? "No matching countries found." : "Aucun pays trouvé."}
|
|
217
|
+
</Text>} showsVerticalScrollIndicator persistentScrollbar={Platform.OS === 'android'} keyboardShouldPersistTaps="handled" keyboardDismissMode={Platform.OS === 'ios' ? 'interactive' : 'on-drag'} nestedScrollEnabled initialNumToRender={12} maxToRenderPerBatch={12} windowSize={7} accessibilityRole="list"/>
|
|
210
218
|
</>);
|
|
211
219
|
};
|
|
212
220
|
const renderDocumentTypeSelection = () => {
|
|
@@ -303,14 +311,16 @@ export const CountrySelectionTemplate = ({ component, value, onValueChange, erro
|
|
|
303
311
|
</View>);
|
|
304
312
|
};
|
|
305
313
|
const styles = StyleSheet.create({
|
|
306
|
-
root: { flex: 1, maxWidth: 760, width: '100%' },
|
|
307
|
-
container: { backgroundColor: 'white', margin: 10, borderRadius: 10, paddingVertical: 16, paddingHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.35, shadowRadius: 4.84, elevation: 10 },
|
|
314
|
+
root: { flex: 1, minHeight: 0, maxWidth: 760, width: '100%' },
|
|
315
|
+
container: { flex: 1, minHeight: 0, backgroundColor: 'white', margin: 10, borderRadius: 10, paddingVertical: 16, paddingHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.35, shadowRadius: 4.84, elevation: 10 },
|
|
308
316
|
progressContainer: { marginBottom: 16, alignItems: 'center' },
|
|
309
317
|
progressText: { fontSize: 14, color: '#666', fontWeight: '500' },
|
|
310
318
|
title: { fontSize: 24, fontWeight: 'bold', color: '#333', marginBottom: 8, textAlign: 'center' },
|
|
311
319
|
description: { fontSize: 16, color: '#666', textAlign: 'center', marginBottom: 24, lineHeight: 22 },
|
|
312
320
|
searchBar: { height: 52, backgroundColor: '#F1F5F9', borderRadius: 12, paddingHorizontal: 16, fontSize: 16, color: '#1E293B', marginBottom: 16, borderWidth: 1, borderColor: '#CBD5E1', fontWeight: '500' },
|
|
313
|
-
listContainer: {
|
|
321
|
+
listContainer: { flex: 1, minHeight: 120, marginBottom: 12 },
|
|
322
|
+
listContent: { paddingBottom: 8 },
|
|
323
|
+
emptyListContent: { flexGrow: 1, justifyContent: 'center' },
|
|
314
324
|
option: { flexDirection: 'row', alignItems: 'center', padding: 16, backgroundColor: '#F8F9FA', borderRadius: 12, marginBottom: 12, borderWidth: 2, borderColor: '#E9ECEF', minHeight: 64 },
|
|
315
325
|
selectedOption: { borderColor: '#2DBD60', backgroundColor: '#F0F9F0' },
|
|
316
326
|
flag: { fontSize: 32, marginRight: 16 },
|
|
@@ -322,7 +332,7 @@ const styles = StyleSheet.create({
|
|
|
322
332
|
checkmarkText: { color: 'white', fontSize: 16, fontWeight: 'bold' },
|
|
323
333
|
infoBox: { backgroundColor: '#F9FAFB', padding: 12, borderRadius: 12, marginBottom: 16 },
|
|
324
334
|
infoText: { fontSize: 14, color: '#666', lineHeight: 20 },
|
|
325
|
-
buttonContainer: { flexDirection: 'row', marginTop:
|
|
335
|
+
buttonContainer: { flexDirection: 'row', marginTop: 12, gap: 12 },
|
|
326
336
|
errorText: { color: '#dc2626', fontSize: 14, marginTop: 8, textAlign: 'center' },
|
|
327
337
|
emptyText: { textAlign: 'center', color: '#64748B', fontSize: 16, marginTop: 24, fontWeight: '500' }
|
|
328
338
|
});
|