@au10tixorg/secureme-sdk 4.7.0
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/LICENSE +21 -0
- package/README.md +479 -0
- package/android/build.gradle +156 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +6 -0
- package/android/src/main/java/com/securemesdk/SecuremeSdkModule.kt +59 -0
- package/android/src/main/java/com/securemesdk/SecuremeSdkPackage.kt +17 -0
- package/android/src/main/java/com/securemesdk/helpers/ReadableMapExt.kt +51 -0
- package/android/src/main/java/com/securemesdk/helpers/SessionParser.kt +21 -0
- package/android/src/main/java/com/securemesdk/models/SDKError.kt +24 -0
- package/android/src/main/java/com/securemesdk/secureme/SecureMeBottomSheet.kt +308 -0
- package/ios/Extensions/DictionaryExtensions.swift +90 -0
- package/ios/Extensions/SecureMeExtensions.swift +82 -0
- package/ios/Models/SDKError.swift +36 -0
- package/ios/Secureme/SecuremeService.swift +261 -0
- package/ios/SecuremeSdk-Bridging-Header.h +2 -0
- package/ios/SecuremeSdk.m +14 -0
- package/ios/SecuremeSdk.swift +102 -0
- package/ios/SecuremeSdk.xcodeproj/project.pbxproj +317 -0
- package/ios/SecuremeSdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/lib/commonjs/index.js +103 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/index.js +85 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/index.d.ts +32 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +95 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/package.json +164 -0
- package/secureme-sdk.podspec +27 -0
- package/src/index.tsx +119 -0
- package/src/types.ts +113 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
package com.securemesdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
+
import com.facebook.react.bridge.ReactMethod
|
|
7
|
+
import com.facebook.react.bridge.ReadableMap
|
|
8
|
+
import com.securemesdk.models.SDKError
|
|
9
|
+
import com.securemesdk.secureme.SecureMeBottomSheet
|
|
10
|
+
|
|
11
|
+
class SecuremeSdkModule(reactContext: ReactApplicationContext) :
|
|
12
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
13
|
+
|
|
14
|
+
companion object {
|
|
15
|
+
private const val TAG = "SecureMe"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun getName(): String {
|
|
19
|
+
return "SecuremeSdk"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@ReactMethod
|
|
23
|
+
fun start(
|
|
24
|
+
workFlowResponse: String, flowMap: ReadableMap, configMap: ReadableMap, promise: Promise
|
|
25
|
+
) {
|
|
26
|
+
try {
|
|
27
|
+
val activity = this.reactApplicationContext.currentActivity
|
|
28
|
+
|
|
29
|
+
if (activity is androidx.fragment.app.FragmentActivity) {
|
|
30
|
+
|
|
31
|
+
activity.runOnUiThread {
|
|
32
|
+
val bottomSheet = SecureMeBottomSheet()
|
|
33
|
+
bottomSheet.setup(
|
|
34
|
+
workFlowResponse = workFlowResponse,
|
|
35
|
+
flowMap = flowMap,
|
|
36
|
+
configMap = configMap
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
bottomSheet.onSuccessAction = { success ->
|
|
40
|
+
promise.resolve(success)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
bottomSheet.onErrorAction = { error ->
|
|
44
|
+
promise.reject(error.code, error.message)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
bottomSheet.show(activity.supportFragmentManager, TAG)
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
val error =
|
|
51
|
+
SDKError.SecureMeFailure("Current activity is null or not a FragmentActivity")
|
|
52
|
+
promise.reject(error.code, error.message)
|
|
53
|
+
}
|
|
54
|
+
} catch (e: Exception) {
|
|
55
|
+
val error = SDKError.SecureMeFailure(e.message ?: "")
|
|
56
|
+
promise.reject(error.code, error.message)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.securemesdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SecuremeSdkPackage : ReactPackage {
|
|
10
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
11
|
+
return listOf(SecuremeSdkModule(reactContext))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
15
|
+
return emptyList()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
package com.securemesdk.helpers
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableMap
|
|
4
|
+
|
|
5
|
+
fun ReadableMap.getSafeBool(key: String, default: Boolean = false): Boolean {
|
|
6
|
+
if (this.hasKey(key) && !this.isNull(key)) {
|
|
7
|
+
return try {
|
|
8
|
+
this.getBoolean(key)
|
|
9
|
+
} catch (e: Exception) {
|
|
10
|
+
default
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return default
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fun ReadableMap.getSafeFloat(key: String, default: Float? = null): Float? {
|
|
17
|
+
if (this.hasKey(key) && !this.isNull(key)) {
|
|
18
|
+
return try {
|
|
19
|
+
this.getDouble(key).toFloat()
|
|
20
|
+
} catch (e: Exception) {
|
|
21
|
+
default
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return default
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fun ReadableMap.getSafeInt(key: String, default: Int = 0): Int {
|
|
28
|
+
if (this.hasKey(key) && !this.isNull(key)) {
|
|
29
|
+
return try {
|
|
30
|
+
this.getInt(key)
|
|
31
|
+
} catch (e: Exception) {
|
|
32
|
+
try {
|
|
33
|
+
this.getDouble(key).toInt()
|
|
34
|
+
} catch (e2: Exception) {
|
|
35
|
+
default
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return default
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fun ReadableMap.getSafeString(key: String, default: String? = null): String? {
|
|
43
|
+
if (this.hasKey(key) && !this.isNull(key)) {
|
|
44
|
+
return try {
|
|
45
|
+
this.getString(key) ?: default
|
|
46
|
+
} catch (e: Exception) {
|
|
47
|
+
default
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return default
|
|
51
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
package com.securemesdk.helpers
|
|
2
|
+
|
|
3
|
+
import com.securemesdk.models.SDKError
|
|
4
|
+
import org.json.JSONArray
|
|
5
|
+
import org.json.JSONObject
|
|
6
|
+
|
|
7
|
+
fun parseSessionData(jsonString: String): Triple<String, String, JSONArray> {
|
|
8
|
+
try {
|
|
9
|
+
val rootObject = JSONObject(jsonString)
|
|
10
|
+
|
|
11
|
+
val responseObject = rootObject.getJSONObject("response")
|
|
12
|
+
|
|
13
|
+
val session = responseObject.getString("session")
|
|
14
|
+
val accessToken = responseObject.getString("accessToken")
|
|
15
|
+
val assets = responseObject.getJSONArray("assets")
|
|
16
|
+
|
|
17
|
+
return Triple(session, accessToken, assets)
|
|
18
|
+
} catch (e: Exception) {
|
|
19
|
+
throw SDKError.JsonParse(e.message ?: "")
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package com.securemesdk.models
|
|
2
|
+
|
|
3
|
+
sealed class SDKError : Exception() {
|
|
4
|
+
|
|
5
|
+
abstract val reason: String
|
|
6
|
+
|
|
7
|
+
data class JsonParse(override val reason: String) : SDKError()
|
|
8
|
+
data class SecureMeFailure(override val reason: String) : SDKError()
|
|
9
|
+
|
|
10
|
+
val code: String
|
|
11
|
+
get() = when (this) {
|
|
12
|
+
is JsonParse -> "ERROR_JSON_PARSE"
|
|
13
|
+
is SecureMeFailure -> "ERROR_SECURE_ME_FAILURE"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override val message: String
|
|
17
|
+
get() = reason
|
|
18
|
+
|
|
19
|
+
val nsErrorCode: Int
|
|
20
|
+
get() = when (this) {
|
|
21
|
+
is JsonParse -> 1001
|
|
22
|
+
is SecureMeFailure -> 1002
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
package com.securemesdk.secureme
|
|
2
|
+
|
|
3
|
+
import android.app.Dialog
|
|
4
|
+
import android.graphics.Color
|
|
5
|
+
import android.os.Bundle
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import android.view.LayoutInflater
|
|
8
|
+
import android.view.View
|
|
9
|
+
import android.view.ViewGroup
|
|
10
|
+
import android.widget.FrameLayout
|
|
11
|
+
import androidx.activity.OnBackPressedCallback
|
|
12
|
+
import androidx.fragment.app.Fragment
|
|
13
|
+
import com.au10tix.sdk.commons.Au10Error
|
|
14
|
+
import com.au10tix.sdk.core.Au10xCore
|
|
15
|
+
import com.au10tix.sdk.security.config.SuspiciousConfig
|
|
16
|
+
import com.au10tix.sdk.protocol.FeatureSessionError
|
|
17
|
+
import com.au10tix.sdk.protocol.FeatureSessionResult
|
|
18
|
+
import com.au10tix.secureMe.SecureMe
|
|
19
|
+
import com.au10tix.secureMe.SecureMeResult
|
|
20
|
+
import com.au10tix.secureMe.callback.SecureMeCallback
|
|
21
|
+
import com.au10tix.secureMe.callback.SecureMePrepareCallback
|
|
22
|
+
import com.au10tix.secureMe.configurations.SMConfig
|
|
23
|
+
import com.au10tix.secureMe.configurations.SMFlow
|
|
24
|
+
import com.facebook.react.bridge.ReadableMap
|
|
25
|
+
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
26
|
+
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
27
|
+
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|
28
|
+
import com.securemesdk.helpers.getSafeBool
|
|
29
|
+
import com.securemesdk.helpers.getSafeFloat
|
|
30
|
+
import com.securemesdk.helpers.getSafeInt
|
|
31
|
+
import com.securemesdk.helpers.getSafeString
|
|
32
|
+
import com.securemesdk.helpers.parseSessionData
|
|
33
|
+
import com.securemesdk.models.SDKError
|
|
34
|
+
|
|
35
|
+
class SecureMeBottomSheet : BottomSheetDialogFragment() {
|
|
36
|
+
|
|
37
|
+
private var containerId = View.generateViewId()
|
|
38
|
+
private var secureMe: SecureMe? = null
|
|
39
|
+
private var fragment: Fragment? = null
|
|
40
|
+
private var workFlowResponse: String = ""
|
|
41
|
+
private var flow: SMFlow? = null
|
|
42
|
+
private var config: SMConfig? = null
|
|
43
|
+
|
|
44
|
+
var onSuccessAction: ((Boolean) -> Unit)? = null
|
|
45
|
+
var onErrorAction: ((SDKError) -> Unit)? = null
|
|
46
|
+
|
|
47
|
+
companion object {
|
|
48
|
+
private const val TAG = "SecureMe"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fun setup(workFlowResponse: String, flowMap: ReadableMap?, configMap: ReadableMap?) {
|
|
52
|
+
this.workFlowResponse = workFlowResponse
|
|
53
|
+
|
|
54
|
+
if (flowMap != null && flowMap.toHashMap().isNotEmpty()) {
|
|
55
|
+
flow = createFlow(flowMap)
|
|
56
|
+
}
|
|
57
|
+
if (configMap != null && configMap.toHashMap().isNotEmpty()) {
|
|
58
|
+
config = createConfig(configMap)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
63
|
+
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
|
|
64
|
+
dialog.setOnShowListener { dialogInterface ->
|
|
65
|
+
val bottomSheetDialog = dialogInterface as BottomSheetDialog
|
|
66
|
+
val bottomSheet =
|
|
67
|
+
bottomSheetDialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
|
|
68
|
+
|
|
69
|
+
dialog.window?.setDimAmount(0f)
|
|
70
|
+
|
|
71
|
+
bottomSheet?.let { sheet ->
|
|
72
|
+
sheet.setBackgroundColor(Color.TRANSPARENT)
|
|
73
|
+
|
|
74
|
+
val behavior = BottomSheetBehavior.from(sheet)
|
|
75
|
+
val layoutParams = sheet.layoutParams
|
|
76
|
+
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
77
|
+
sheet.layoutParams = layoutParams
|
|
78
|
+
|
|
79
|
+
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
|
80
|
+
behavior.isDraggable = false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
val backCallback = object : OnBackPressedCallback(true) {
|
|
85
|
+
override fun handleOnBackPressed() {
|
|
86
|
+
dismissAllowingStateLoss()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
dialog.onBackPressedDispatcher.addCallback(this, backCallback)
|
|
91
|
+
return dialog
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
95
|
+
super.onCreate(savedInstanceState)
|
|
96
|
+
isCancelable = false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
override fun onCreateView(
|
|
100
|
+
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
|
101
|
+
): View {
|
|
102
|
+
val programmaticContainer = FrameLayout(requireContext()).apply {
|
|
103
|
+
layoutParams = ViewGroup.LayoutParams(
|
|
104
|
+
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
|
|
105
|
+
)
|
|
106
|
+
id = containerId
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return programmaticContainer
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
113
|
+
super.onViewCreated(view, savedInstanceState)
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
Au10xCore.getInstance(requireContext()).setHost("reactNative")
|
|
117
|
+
val (sessionToken, accessToken, assets) = parseSessionData(workFlowResponse)
|
|
118
|
+
secureMe = SecureMe(
|
|
119
|
+
requireActivity(),
|
|
120
|
+
accessToken,
|
|
121
|
+
sessionToken,
|
|
122
|
+
assets,
|
|
123
|
+
object : SecureMePrepareCallback {
|
|
124
|
+
override fun onPrepared(secureMe: SecureMe) {
|
|
125
|
+
fragment = secureMe.createUI(
|
|
126
|
+
flow, config, object : SecureMeCallback {
|
|
127
|
+
override fun onUpdate(
|
|
128
|
+
event: String?, result: FeatureSessionResult?
|
|
129
|
+
) {
|
|
130
|
+
Log.d(TAG, "SecureMe update: $event")
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
override fun onComplete(result: SecureMeResult?) {
|
|
134
|
+
Log.d(TAG, "SecureMe сomplete")
|
|
135
|
+
onSuccessAction?.invoke(true)
|
|
136
|
+
close()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override fun onError(error: FeatureSessionError) {
|
|
140
|
+
Log.e(TAG, "SecureMe error: ${error?.errorMessage}")
|
|
141
|
+
|
|
142
|
+
if (error.severity != FeatureSessionError.SEVERITY_WARNING) {
|
|
143
|
+
onErrorAction?.invoke(SDKError.SecureMeFailure("${error?.errorMessage}"))
|
|
144
|
+
close()
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
activity?.runOnUiThread {
|
|
149
|
+
if (isAdded && !isDetached) {
|
|
150
|
+
try {
|
|
151
|
+
if (fragment != null) {
|
|
152
|
+
childFragmentManager.beginTransaction()
|
|
153
|
+
.replace(containerId, fragment!!).commit()
|
|
154
|
+
} else {
|
|
155
|
+
val message = "fragment is null"
|
|
156
|
+
Log.e(TAG, message)
|
|
157
|
+
|
|
158
|
+
onErrorAction?.invoke(SDKError.SecureMeFailure(message))
|
|
159
|
+
close()
|
|
160
|
+
}
|
|
161
|
+
} catch (e: Exception) {
|
|
162
|
+
onErrorAction?.invoke(SDKError.SecureMeFailure("Failed to commit fragment transaction: ${e.message}"))
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
override fun onError(error: Au10Error?) {
|
|
169
|
+
Log.e(TAG, "error: ${error?.message}")
|
|
170
|
+
|
|
171
|
+
onErrorAction?.invoke(SDKError.SecureMeFailure("${error?.message}"))
|
|
172
|
+
close()
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
} catch (e: Exception) {
|
|
176
|
+
Log.e(TAG, "error: ${e.message}")
|
|
177
|
+
onErrorAction?.invoke(SDKError.SecureMeFailure(e.message ?: ""))
|
|
178
|
+
close()
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
override fun onDestroy() {
|
|
183
|
+
secureMe?.destroy()
|
|
184
|
+
secureMe = null
|
|
185
|
+
fragment = null
|
|
186
|
+
super.onDestroy()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private fun createFlow(map: ReadableMap) = SMFlow().apply {
|
|
190
|
+
map.getMap("afl")?.let { innerMap ->
|
|
191
|
+
this.withAFL(
|
|
192
|
+
innerMap.getSafeBool("enabled"),
|
|
193
|
+
innerMap.getSafeBool("showIntro"),
|
|
194
|
+
innerMap.getSafeBool("enableFileUpload"),
|
|
195
|
+
innerMap.getSafeBool("sendFeatureResult")
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
map.getMap("sdcBack")?.let { innerMap ->
|
|
200
|
+
this.withBackSDC(
|
|
201
|
+
innerMap.getSafeBool("enabled"),
|
|
202
|
+
innerMap.getSafeBool("enableFileUpload"),
|
|
203
|
+
innerMap.getSafeBool("sendFeatureResult")
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
map.getMap("sdcFront")?.let { innerMap ->
|
|
208
|
+
this.withFrontSDC(
|
|
209
|
+
innerMap.getSafeBool("enabled"),
|
|
210
|
+
innerMap.getSafeBool("showIntro"),
|
|
211
|
+
innerMap.getSafeBool("enableFileUpload")
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
map.getMap("nfc")?.let { innerMap ->
|
|
216
|
+
this.withNFC(
|
|
217
|
+
innerMap.getSafeBool("enabled"),
|
|
218
|
+
innerMap.getSafeBool("enableFileUpload"),
|
|
219
|
+
innerMap.getSafeBool("sendFeatureResult")
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
map.getMap("pfl")?.let { innerMap ->
|
|
224
|
+
this.withPFL(
|
|
225
|
+
innerMap.getSafeBool("enabled"),
|
|
226
|
+
innerMap.getSafeBool("showIntro"),
|
|
227
|
+
innerMap.getSafeBool("sendFeatureResult")
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
map.getMap("poa")?.let { innerMap ->
|
|
232
|
+
this.withPOA(
|
|
233
|
+
innerMap.getSafeBool("enabled"),
|
|
234
|
+
innerMap.getSafeBool("showIntro"),
|
|
235
|
+
innerMap.getSafeBool("enableFileUpload"),
|
|
236
|
+
innerMap.getSafeBool("sendFeatureResult")
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
map.getMap("videoSession")?.let { innerMap ->
|
|
241
|
+
this.withVideoSession(
|
|
242
|
+
innerMap.getSafeBool("enabled"),
|
|
243
|
+
innerMap.getSafeBool("showIntro"),
|
|
244
|
+
innerMap.getSafeBool("sendFeatureResult")
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
map.getMap("voiceConsent")?.let { voiceMap ->
|
|
249
|
+
this.withVoiceConsent(
|
|
250
|
+
voiceMap.getSafeBool("enabled"),
|
|
251
|
+
voiceMap.getSafeBool("showIntro"),
|
|
252
|
+
voiceMap.getSafeBool("sendFeatureResult")
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private fun createConfig(map: ReadableMap) = map.run {
|
|
258
|
+
|
|
259
|
+
val suspiciousConfig = map.getMap("suspiciousConfig")?.let {
|
|
260
|
+
createSuspiciousConfig(it)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
SMConfig(
|
|
264
|
+
p0 = map.getSafeBool("withPflDetectionDelay"),
|
|
265
|
+
p1 = map.getSafeInt("pflDelaySecs"),
|
|
266
|
+
p2 = map.getSafeBool("sendResults"),
|
|
267
|
+
p3 = map.getSafeString("voiceConsentText"),
|
|
268
|
+
p4 = map.getSafeInt("voiceConsentSessionTime"),
|
|
269
|
+
p5 = map.getSafeInt("videoSessionConsentTime"),
|
|
270
|
+
p6 = map.getSafeInt("videoSessionIDTime"),
|
|
271
|
+
p7 = map.getSafeBool("videoSessionAskUserConsent"),
|
|
272
|
+
p8 = suspiciousConfig
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private fun createSuspiciousConfig(map: ReadableMap): SuspiciousConfig {
|
|
277
|
+
return SuspiciousConfig().apply {
|
|
278
|
+
|
|
279
|
+
map.getSafeInt("checkInterval").let {
|
|
280
|
+
this.checkInterval = it
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
map.getSafeFloat("fastFilterThreshold")?.let {
|
|
284
|
+
this.fastFilterThreshold = it
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
map.getSafeFloat("pixelPerfectThreshold")?.let {
|
|
288
|
+
this.pixelPerfectThreshold = it
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
map.getSafeFloat("preFilterThreshold")?.let {
|
|
292
|
+
this.preFilterThreshold = it
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
map.getSafeFloat("stillDeviceThreshold")?.let {
|
|
296
|
+
this.stillDeviceThreshold = it
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private fun close() {
|
|
302
|
+
activity?.runOnUiThread {
|
|
303
|
+
if (isAdded) {
|
|
304
|
+
dismissAllowingStateLoss()
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
//
|
|
2
|
+
// DictionaryExtensions.swift
|
|
3
|
+
// SecuremeSdk
|
|
4
|
+
//
|
|
5
|
+
// Created by Ihor Konfedrat on 28.12.2025.
|
|
6
|
+
// Copyright © 2025 Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
extension NSDictionary {
|
|
10
|
+
|
|
11
|
+
func getSafeBool(_ key: String, defaultVal: Bool = false) -> Bool {
|
|
12
|
+
if let val = self[key] as? Bool {
|
|
13
|
+
return val
|
|
14
|
+
}
|
|
15
|
+
if let val = self[key] as? NSNumber {
|
|
16
|
+
return val.boolValue
|
|
17
|
+
}
|
|
18
|
+
return defaultVal
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func getSafeInt(_ key: String, defaultVal: Int = 0) -> Int {
|
|
22
|
+
if let val = self[key] as? Int {
|
|
23
|
+
return val
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if let valStr = self[key] as? String, let valInt = Int(valStr) {
|
|
27
|
+
return valInt
|
|
28
|
+
}
|
|
29
|
+
return defaultVal
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func getSafeString(_ key: String) -> String? {
|
|
33
|
+
if let stringValue = self[key] as? String {
|
|
34
|
+
return stringValue
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if let numberValue = self[key] as? NSNumber {
|
|
38
|
+
return numberValue.stringValue
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return nil
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func getSafeFloat(_ key: String, defaultVal: Float = 0.0) -> Float {
|
|
45
|
+
if let val = self[key] as? Float {
|
|
46
|
+
return val
|
|
47
|
+
}
|
|
48
|
+
if let val = self[key] as? NSNumber {
|
|
49
|
+
return val.floatValue
|
|
50
|
+
}
|
|
51
|
+
return defaultVal
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
func getSafeDouble(_ key: String, defaultVal: Double = 0.0) -> Double {
|
|
55
|
+
if let val = self[key] as? Double {
|
|
56
|
+
return val
|
|
57
|
+
}
|
|
58
|
+
if let val = self[key] as? NSNumber {
|
|
59
|
+
return val.doubleValue
|
|
60
|
+
}
|
|
61
|
+
return defaultVal
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func getSafeTimeInterval(_ key: String) -> TimeInterval? {
|
|
65
|
+
if let val = self[key] as? TimeInterval {
|
|
66
|
+
return val
|
|
67
|
+
}
|
|
68
|
+
if let number = self[key] as? NSNumber {
|
|
69
|
+
return number.doubleValue
|
|
70
|
+
}
|
|
71
|
+
if let str = self[key] as? String, let doubleVal = Double(str) {
|
|
72
|
+
return TimeInterval(doubleVal)
|
|
73
|
+
}
|
|
74
|
+
return nil
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func getSafeTimeInterval(_ key: String, defaultVal: TimeInterval = 0.0) -> TimeInterval {
|
|
78
|
+
return getSafeTimeInterval(key) ?? defaultVal
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func getSafeCGFloat(_ key: String, defaultVal: CGFloat = 0.0) -> CGFloat {
|
|
82
|
+
if let val = self[key] as? CGFloat {
|
|
83
|
+
return val
|
|
84
|
+
}
|
|
85
|
+
if let val = self[key] as? NSNumber {
|
|
86
|
+
return CGFloat(val.doubleValue)
|
|
87
|
+
}
|
|
88
|
+
return defaultVal
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SecureMeExtensions.swift
|
|
3
|
+
// SecuremeSdk
|
|
4
|
+
//
|
|
5
|
+
// Created by Ihor Konfedrat on 12.12.2025.
|
|
6
|
+
// Copyright © 2025 Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
import Au10tixCore
|
|
12
|
+
import Au10tixSecureMeKit
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
extension SecureMeFlowConfig {
|
|
16
|
+
init(dict: NSDictionary) {
|
|
17
|
+
var susConfig: SuspiciousBehaviorConfig? = nil
|
|
18
|
+
if let susDict = dict["suspiciousBehaviorConfig"] as? NSDictionary {
|
|
19
|
+
susConfig = SuspiciousBehaviorConfig(dict: susDict)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
self.init(
|
|
23
|
+
showIntro: dict.getSafeBool("showIntro", defaultVal: true),
|
|
24
|
+
enableFileUpload: dict.getSafeBool("enableFileUpload", defaultVal: true),
|
|
25
|
+
sendFeatureResult: dict
|
|
26
|
+
.getSafeBool("sendFeatureResult", defaultVal: true),
|
|
27
|
+
localClassification: dict.getSafeBool("localClassification"),
|
|
28
|
+
suspiciousBehaviorConfig: susConfig
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
extension SuspiciousBehaviorConfig {
|
|
34
|
+
init(dict: NSDictionary) {
|
|
35
|
+
self.init(
|
|
36
|
+
similarityThreshold: dict.getSafeFloat("similarityThreshold", defaultVal: 0.009),
|
|
37
|
+
stillDeviceThreshold: dict.getSafeDouble("stillDeviceThreshold", defaultVal: 0.01),
|
|
38
|
+
rectangleDriftDelta: dict.getSafeCGFloat("rectangleDriftDelta", defaultVal: 0.01),
|
|
39
|
+
minimumConfidence: dict.getSafeFloat("minimumConfidence", defaultVal: 0.1),
|
|
40
|
+
minimumAspectRatio: dict.getSafeFloat("minimumAspectRatio", defaultVal: 0.3),
|
|
41
|
+
checkInterval: dict.getSafeInt("checkInterval", defaultVal: 5),
|
|
42
|
+
riskThreshold: dict.getSafeFloat("riskThreshold", defaultVal: 45.0),
|
|
43
|
+
visualSimilarityWeight: dict.getSafeFloat("visualSimilarityWeight", defaultVal: 35.0),
|
|
44
|
+
motionAnomaliesWeight: dict.getSafeFloat("motionAnomaliesWeight", defaultVal: 30.0),
|
|
45
|
+
spatialConsistencyWeight: dict.getSafeFloat("spatialConsistencyWeight", defaultVal: 20.0),
|
|
46
|
+
temporalPatternsWeight: dict.getSafeFloat("temporalPatternsWeight", defaultVal: 15.0),
|
|
47
|
+
treatMissingSensorsAsSuspicious: dict.getSafeBool("treatMissingSensorsAsSuspicious", defaultVal: true),
|
|
48
|
+
missingSensorRiskScore: dict.getSafeFloat("missingSensorRiskScore", defaultVal: 25.0),
|
|
49
|
+
enableSpatialAnalysis: dict.getSafeBool("enableSpatialAnalysis", defaultVal: true),
|
|
50
|
+
spatialSuspicionThreshold: dict.getSafeFloat("spatialSuspicionThreshold", defaultVal: 0.5),
|
|
51
|
+
spatialGridSize: dict.getSafeInt("spatialGridSize", defaultVal: 4),
|
|
52
|
+
temporalWindowSize: dict.getSafeInt("temporalWindowSize", defaultVal: 30),
|
|
53
|
+
timingVarianceThreshold: dict.getSafeDouble("timingVarianceThreshold", defaultVal: 0.001),
|
|
54
|
+
enableDebugLogging: dict.getSafeBool("enableDebugLogging", defaultVal: false)
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
extension SecureMeFeaturesConfig {
|
|
60
|
+
init(dict: NSDictionary) {
|
|
61
|
+
|
|
62
|
+
let pflEnabled = dict.getSafeBool("pflDetectionDelayEnabled", defaultVal: false)
|
|
63
|
+
let pflDelay = dict.getSafeTimeInterval("pflDelay", defaultVal: 0)
|
|
64
|
+
let sendResults = dict.getSafeBool("sendResults", defaultVal: true)
|
|
65
|
+
let voiceText = dict.getSafeString("voiceConsentText")
|
|
66
|
+
let voiceTime = dict.getSafeInt("voiceConsentSessionTime", defaultVal: 20)
|
|
67
|
+
let videoText = dict.getSafeString("videoSessionText")
|
|
68
|
+
let videoIdDuration = dict.getSafeInt("videoSessionIdSessionDuration", defaultVal: 5)
|
|
69
|
+
let videoVoiceDuration = dict.getSafeInt("videoSessionVoiceSessionDuration", defaultVal: 0)
|
|
70
|
+
|
|
71
|
+
self.init(
|
|
72
|
+
pflDetectionDelayEnabled: pflEnabled,
|
|
73
|
+
pflDelay: pflDelay,
|
|
74
|
+
sendResults: sendResults,
|
|
75
|
+
voiceConsentText: voiceText,
|
|
76
|
+
voiceConsentSessionTime: voiceTime,
|
|
77
|
+
videoSessionText: videoText,
|
|
78
|
+
videoSessionIdSessionDuration: videoIdDuration,
|
|
79
|
+
videoSessionVoiceSessionDuration: videoVoiceDuration
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SDKError.swift
|
|
3
|
+
// SecuremeSdk
|
|
4
|
+
//
|
|
5
|
+
// Created by Ihor Konfedrat on 12.12.2025.
|
|
6
|
+
// Copyright © 2025 Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
enum SDKError: LocalizedError {
|
|
12
|
+
|
|
13
|
+
case jsonParse(String)
|
|
14
|
+
case secureMeFailure(String)
|
|
15
|
+
|
|
16
|
+
var code: String {
|
|
17
|
+
switch self {
|
|
18
|
+
case .jsonParse: return "ERROR_JSON_PARSE"
|
|
19
|
+
case .secureMeFailure: return "SECURE_ME_FAILURE"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
var errorDescription: String? {
|
|
24
|
+
switch self {
|
|
25
|
+
case .secureMeFailure(let msg): return msg
|
|
26
|
+
case .jsonParse(let msg): return msg
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var nsErrorCode: Int {
|
|
31
|
+
switch self {
|
|
32
|
+
case .jsonParse: return 1001
|
|
33
|
+
case .secureMeFailure: return 1002
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|