@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.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +479 -0
  3. package/android/build.gradle +156 -0
  4. package/android/gradle.properties +4 -0
  5. package/android/src/main/AndroidManifest.xml +6 -0
  6. package/android/src/main/java/com/securemesdk/SecuremeSdkModule.kt +59 -0
  7. package/android/src/main/java/com/securemesdk/SecuremeSdkPackage.kt +17 -0
  8. package/android/src/main/java/com/securemesdk/helpers/ReadableMapExt.kt +51 -0
  9. package/android/src/main/java/com/securemesdk/helpers/SessionParser.kt +21 -0
  10. package/android/src/main/java/com/securemesdk/models/SDKError.kt +24 -0
  11. package/android/src/main/java/com/securemesdk/secureme/SecureMeBottomSheet.kt +308 -0
  12. package/ios/Extensions/DictionaryExtensions.swift +90 -0
  13. package/ios/Extensions/SecureMeExtensions.swift +82 -0
  14. package/ios/Models/SDKError.swift +36 -0
  15. package/ios/Secureme/SecuremeService.swift +261 -0
  16. package/ios/SecuremeSdk-Bridging-Header.h +2 -0
  17. package/ios/SecuremeSdk.m +14 -0
  18. package/ios/SecuremeSdk.swift +102 -0
  19. package/ios/SecuremeSdk.xcodeproj/project.pbxproj +317 -0
  20. package/ios/SecuremeSdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  21. package/lib/commonjs/index.js +103 -0
  22. package/lib/commonjs/index.js.map +1 -0
  23. package/lib/commonjs/package.json +1 -0
  24. package/lib/commonjs/types.js +2 -0
  25. package/lib/commonjs/types.js.map +1 -0
  26. package/lib/module/index.js +85 -0
  27. package/lib/module/index.js.map +1 -0
  28. package/lib/module/types.js +2 -0
  29. package/lib/module/types.js.map +1 -0
  30. package/lib/typescript/index.d.ts +32 -0
  31. package/lib/typescript/index.d.ts.map +1 -0
  32. package/lib/typescript/types.d.ts +95 -0
  33. package/lib/typescript/types.d.ts.map +1 -0
  34. package/package.json +164 -0
  35. package/secureme-sdk.podspec +27 -0
  36. package/src/index.tsx +119 -0
  37. 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
+ }