@pagopa/io-react-native-cie 1.3.0-beta.0 → 1.3.0-experimental

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.
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
16
16
  s.source_files = "ios/**/*.{h,m,mm,swift}"
17
17
 
18
18
  # CieSDK dependency
19
- s.dependency "CieSDK", "~> 0.1.12"
19
+ s.dependency "CieSDK", "~> 0.1.15"
20
20
 
21
21
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
22
22
  # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
package/README.md CHANGED
@@ -73,14 +73,15 @@ More info in the [official Android documentation](https://developer.android.com/
73
73
  <string>We need to use NFC</string>
74
74
  ```
75
75
  [More info on Apple's doc](https://developer.apple.com/documentation/bundleresources/information-property-list/nfcreaderusagedescription?language=objc)
76
- 3. Add the required ISO7816 identifiers into your `info.plist`
76
+ 3. Add the required ISO7816 identifiers into your `info.plist`. **IMPORTART**: the NFC tags order is important!
77
77
  ```xml
78
78
  <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
79
79
  <array>
80
- <string>A0000000308000000009816001</string>
81
- <string>A00000000039</string>
82
- <string>A0000002471001</string>
83
- <string>00000000000000</string>
80
+ <string>A0000002471001</string>
81
+ <string>A0000000308000000009816001</string>
82
+ <string>A00000000039</string>
83
+ <string>A0000002472001</string>
84
+ <string>00000000000000</string>
84
85
  </array>
85
86
  ```
86
87
  [More info on Apple's doc](https://developer.apple.com/documentation/corenfc/nfciso7816tag).
@@ -97,22 +98,24 @@ To run the example app, follow the instructions in [example/README.md](./example
97
98
 
98
99
  List of available functions
99
100
 
100
- | Function | Return | Description |
101
- | :---------------------------------------------------------------------- | :----------------- | :----------------------------------------------------------------------------- |
102
- | `hasNFCFeature()` | `Promise<boolean>` | (Android) Checks if the device supports NFC feature |
103
- | `isNfcEnabled()` | `Promise<boolean>` | (Android) Checks if the NFC is currently enabled |
104
- | `isCieAuthenticationSupported()` | `Promise<boolean>` | (Android) Checks if the device supports CIE autentication |
105
- | `openNfcSettings()` | `Promise<void>` | (Android) Opens NFC system settings page |
106
- | `addListener(event: CieEvent, listener: CieEventHandlers)` | `() => void` | Adds a NFC event listener and returns a function to unsubscribe from the event |
107
- | `removeListener(event: CieEvent)` | `void` | Removes all listeners for the specified event |
108
- | `removeAllListeners()` | `void` | Removes all registered listeners |
109
- | `setCustomIdpUrl(url?: string)` | `void` | Updates IDP url, if `undefined` will use the default IDP url |
110
- | `setAlertMessage(key: AlertMessageKey, value: string)` | `void` | (iOS) Updates iOS NFC modal alert message |
111
- | `setCurrentAlertMessage(value: string)` | `void` | (iOS) Updates currently displayed iOS NFC modal alert message |
112
- | `startInternalAuthentication(challenge: string)` | `Promise<void>` | Start the CIE IAS/NIS Internal Authentication |
113
- | `startReadingAttributes(timeout: number)` | `Promise<void>` | Start the CIE attributes reading process |
114
- | `startReading(pin: string, authenticationUrl: string, timeout: number)` | `Promise<void>` | Start the CIE reading process fro authentication |
115
- | `stopReading()` | `Promise<void>` | (Android) Stops all reading process |
101
+ | Function | Return | Description |
102
+ | :------------------------------------------------------------------------------------------------------------------- | :----------------- | :----------------------------------------------------------------------------- |
103
+ | `hasNFCFeature()` | `Promise<boolean>` | (Android) Checks if the device supports NFC feature |
104
+ | `isNfcEnabled()` | `Promise<boolean>` | (Android) Checks if the NFC is currently enabled |
105
+ | `isCieAuthenticationSupported()` | `Promise<boolean>` | (Android) Checks if the device supports CIE autentication |
106
+ | `openNfcSettings()` | `Promise<void>` | (Android) Opens NFC system settings page |
107
+ | `addListener(event: CieEvent, listener: CieEventHandlers)` | `() => void` | Adds a NFC event listener and returns a function to unsubscribe from the event |
108
+ | `removeListener(event: CieEvent)` | `void` | Removes all listeners for the specified event |
109
+ | `removeAllListeners()` | `void` | Removes all registered listeners |
110
+ | `setCustomIdpUrl(url?: string)` | `void` | Updates IDP url, if `undefined` will use the default IDP url |
111
+ | `setAlertMessage(key: AlertMessageKey, value: string)` | `void` | (iOS) Updates iOS NFC modal alert message |
112
+ | `setCurrentAlertMessage(value: string)` | `void` | (iOS) Updates currently displayed iOS NFC modal alert message |
113
+ | `startInternalAuthentication(challenge: string, resultEncoding?: ResultEncoding, timeout?: number)` | `Promise<void>` | Start the CIE IAS/NIS Internal Authentication |
114
+ | `startMRTDReading(can: string, resultEncoding?: ResultEncoding, timeout?: number)` | `Promise<void>` | Start PACE MRTD reading (reads MRTD data using CAN) |
115
+ | `startInternalAuthAndMRTDReading(can: string, challenge: string, resultEncoding?: ResultEncoding, timeout?: number)` | `Promise<void>` | Start combined Internal Authentication + PACE MRTD reading |
116
+ | `startReadingAttributes(timeout: number)` | `Promise<void>` | Start the CIE attributes reading process |
117
+ | `startReading(pin: string, authenticationUrl: string, timeout: number)` | `Promise<void>` | Start the CIE reading process fro authentication |
118
+ | `stopReading()` | `Promise<void>` | (Android) Stops all reading process |
116
119
 
117
120
  ## Usage
118
121
 
@@ -394,6 +397,54 @@ type NfcError = {
394
397
 
395
398
  Error event that may be sent during the CIE reading process. Contains the name of the error and an optional message. Error names and order may vary based on the platform.
396
399
 
400
+ ```typescript
401
+ type InternalAuthResponse = {
402
+ nis: string,
403
+ publicKey: string,
404
+ sod: string,
405
+ signedChallenge: string,
406
+ });
407
+ ```
408
+
409
+ Represent the CIE response coming from NIS Internal Auth.
410
+ All string value are Hex, Base64 or Base64 url encoded
411
+
412
+ ```typescript
413
+ type MrtdResponse = {
414
+ dg1: string,
415
+ dg11: string,
416
+ sod: string,
417
+ });
418
+ ```
419
+
420
+ Represent the CIE response coming from MRTD with PACE reading
421
+ All string value are Hex, Base64 or Base64 url encoded.
422
+
423
+ ```typescript
424
+ type InternalAuthAndMrtdResponse = {
425
+ nis_data: {
426
+ nis: string,
427
+ publicKey: string,
428
+ sod: string,
429
+ signedChallenge: string,
430
+ },
431
+ mrtd_data: {
432
+ dg1: string,
433
+ dg11: string,
434
+ sod: string,
435
+ },
436
+ });
437
+ ```
438
+
439
+ Represent the CIE response coming from NIS Internal Auth and MRTD with PACE reading during the same NFC session.
440
+ All string value are Hex, Base64 or Base64 url encoded.
441
+
442
+ ```typescript
443
+ type ResultEncoding = 'hex' | 'base64' | 'base64url';
444
+ ```
445
+
446
+ Supported types of encoding for Internal Auth and Mrtd reponse payloads.
447
+
397
448
  ## Errors
398
449
 
399
450
  The CIE reading function may throw exceptions if the reading process cannot be initiated. These exceptions indicate issues with input validation or system compatibility.
@@ -78,6 +78,6 @@ dependencies {
78
78
  implementation "com.facebook.react:react-android"
79
79
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
80
80
  // CIE SDK
81
- implementation "it.pagopa.io.app.cie:cie:0.1.5"
81
+ implementation "it.pagopa.io.app.cie:cie:0.1.8"
82
82
  }
83
83
 
@@ -5,18 +5,26 @@ import com.facebook.react.bridge.Promise
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.bridge.ReactContextBaseJavaModule
7
7
  import com.facebook.react.bridge.ReactMethod
8
- import com.facebook.react.bridge.WritableMap
9
8
  import com.facebook.react.bridge.WritableNativeMap
10
9
  import com.facebook.react.modules.core.DeviceEventManagerModule
11
10
  import com.pagopa.ioreactnativecie.cie.Atr
12
11
  import it.pagopa.io.app.cie.CieLogger
13
12
  import it.pagopa.io.app.cie.CieSDK
13
+ import it.pagopa.io.app.cie.IntAuthMRTDResponse
14
+ import it.pagopa.io.app.cie.NisAndPaceCallback
15
+ import it.pagopa.io.app.cie.cie.CertificateData
14
16
  import it.pagopa.io.app.cie.cie.CieAtrCallback
15
17
  import it.pagopa.io.app.cie.cie.NfcError
16
18
  import it.pagopa.io.app.cie.cie.NfcEvent
17
19
  import it.pagopa.io.app.cie.network.NetworkCallback
18
20
  import it.pagopa.io.app.cie.network.NetworkError
19
21
  import it.pagopa.io.app.cie.nfc.NfcEvents
22
+ import it.pagopa.io.app.cie.nis.InternalAuthenticationResponse
23
+ import it.pagopa.io.app.cie.nis.NisCallback
24
+ import it.pagopa.io.app.cie.pace.MRTDResponse
25
+ import it.pagopa.io.app.cie.pace.PaceCallback
26
+ import it.pagopa.io.app.cie.toHex
27
+ import it.pagopa.io.app.cie.cie.CieCertificateDataCallback
20
28
  import java.net.URL
21
29
 
22
30
  class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
@@ -34,17 +42,20 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
34
42
  * Lazy value ensures it is initialized with a valid activity when first used.
35
43
  */
36
44
  val cieSdk: CieSDK by lazy {
37
- CieSDK.withContext(reactApplicationContext.currentActivity)
38
- };
45
+ CieSDK.withContext(currentActivity)
46
+ }
39
47
 
48
+ @Suppress("unused")
40
49
  @ReactMethod
41
50
  fun addListener(eventName: String) {
42
51
  }
43
52
 
53
+ @Suppress("unused")
44
54
  @ReactMethod
45
55
  fun removeListeners(count: Int) {
46
56
  }
47
57
 
58
+ @Suppress("unused")
48
59
  @ReactMethod
49
60
  fun hasNfcFeature(promise: Promise) {
50
61
  try {
@@ -56,6 +67,7 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
56
67
  }
57
68
  }
58
69
 
70
+ @Suppress("unused")
59
71
  @ReactMethod
60
72
  fun isNfcEnabled(promise: Promise) {
61
73
  try {
@@ -67,6 +79,7 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
67
79
  }
68
80
  }
69
81
 
82
+ @Suppress("unused")
70
83
  @ReactMethod
71
84
  fun isCieAuthenticationSupported(promise: Promise) {
72
85
  cieSdk.isCieAuthenticationSupported().apply {
@@ -74,6 +87,7 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
74
87
  }
75
88
  }
76
89
 
90
+ @Suppress("unused")
77
91
  @ReactMethod
78
92
  fun openNfcSettings(promise: Promise) {
79
93
  try {
@@ -84,21 +98,205 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
84
98
  }
85
99
  }
86
100
 
101
+ @Suppress("unused")
87
102
  @ReactMethod
88
103
  fun setAlertMessage(key: String, value: String) {
89
104
  // Android does not support alert messages for NFC reading
90
105
  }
91
106
 
107
+ @Suppress("unused")
92
108
  @ReactMethod
93
109
  fun setCurrentAlertMessage(value: String) {
94
110
  // Android does not support alert messages for NFC reading
95
111
  }
96
112
 
113
+ @Suppress("unused")
97
114
  @ReactMethod
98
115
  fun setCustomIdpUrl(url: String) {
99
116
  cieSdk.withCustomIdpUrl(url)
100
117
  }
101
118
 
119
+ @Suppress("unused")
120
+ @ReactMethod
121
+ fun startInternalAuthentication(
122
+ challenge: String,
123
+ resultEncoding: String,
124
+ timeout: Int = 10000,
125
+ promise: Promise,
126
+ ) {
127
+ val encoding: ResultEncoding = ResultEncoding.fromString(resultEncoding)
128
+ try {
129
+ cieSdk.startReadingNis(challenge, timeout, object : NfcEvents {
130
+ override fun event(event: NfcEvent) {
131
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
132
+ .emit(EventType.EVENT.value, WritableNativeMap().apply {
133
+ putString("name", event.name)
134
+ putDouble(
135
+ "progress",
136
+ (event.numeratorForNis.toDouble() / NfcEvent.totalNisOfNumeratorEvent.toDouble())
137
+ )
138
+ })
139
+ }
140
+
141
+ override fun error(error: NfcError) {
142
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
143
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
144
+ putString("name", mapNfcError(error).name)
145
+ error.msg?.let { putString("message", it) }
146
+ })
147
+
148
+ }
149
+ }, object : NisCallback {
150
+ override fun onSuccess(nisAuth: InternalAuthenticationResponse) {
151
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
152
+ .emit(EventType.INTERNAL_AUTHENTICATION_SUCCESS.value, WritableNativeMap().apply {
153
+ putString("nis", encoding.encode(nisAuth.nis))
154
+ putString("publicKey", encoding.encode(nisAuth.kpubIntServ))
155
+ putString("sod", encoding.encode(nisAuth.sod))
156
+ putString("signedChallenge", encoding.encode(nisAuth.challengeSigned))
157
+ })
158
+ }
159
+
160
+ override fun onError(error: NfcError) {
161
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
162
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
163
+ putString("name", mapNfcError(error).name)
164
+ error.msg?.let { putString("message", it) }
165
+ })
166
+ }
167
+ })
168
+ promise.resolve(null)
169
+ } catch (e: Exception) {
170
+ promise.reject(ModuleException.UNKNOWN_EXCEPTION, e.message, e)
171
+ }
172
+ }
173
+
174
+ @Suppress("unused")
175
+ @ReactMethod
176
+ fun startMRTDReading(
177
+ can: String,
178
+ resultEncoding: String,
179
+ timeout: Int = 10000,
180
+ promise: Promise,
181
+ ) {
182
+ val encoding: ResultEncoding = ResultEncoding.fromString(resultEncoding)
183
+ try {
184
+ cieSdk.startDoPace(can, timeout, object : NfcEvents {
185
+ override fun event(event: NfcEvent) {
186
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
187
+ .emit(EventType.EVENT.value, WritableNativeMap().apply {
188
+ putString("name", event.name)
189
+ putDouble(
190
+ "progress",
191
+ (event.numeratorForPace.toDouble() / NfcEvent.totalPaceOfNumeratorEvent.toDouble())
192
+ )
193
+ })
194
+ }
195
+
196
+ override fun error(error: NfcError) {
197
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
198
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
199
+ putString("name", mapNfcError(error).name)
200
+ error.msg?.let { putString("message", it) }
201
+ })
202
+
203
+ }
204
+ }, object : PaceCallback {
205
+ override fun onSuccess(eMRTDResponse: MRTDResponse) {
206
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
207
+ .emit(EventType.MRTD_WITH_PACE_SUCCESS.value, WritableNativeMap().apply {
208
+ putString("dg1", encoding.encode(eMRTDResponse.dg1))
209
+ putString("dg11", encoding.encode(eMRTDResponse.dg11))
210
+ putString("sod", encoding.encode(eMRTDResponse.sod))
211
+ })
212
+ }
213
+
214
+ override fun onError(error: NfcError) {
215
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
216
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
217
+ putString("name", mapNfcError(error).name)
218
+ error.msg?.let { putString("message", it) }
219
+ })
220
+ }
221
+ })
222
+ promise.resolve(null)
223
+ } catch (e: Exception) {
224
+ promise.reject(ModuleException.UNKNOWN_EXCEPTION, e.message, e)
225
+ }
226
+ }
227
+
228
+ @Suppress("unused")
229
+ @ReactMethod
230
+ fun startInternalAuthAndMRTDReading(
231
+ can: String,
232
+ challenge: String,
233
+ resultEncoding: String,
234
+ timeout: Int = 10000,
235
+ promise: Promise,
236
+ ) {
237
+ val encoding: ResultEncoding = ResultEncoding.fromString(resultEncoding)
238
+ try {
239
+ cieSdk.startNisAndPace(challenge, can, timeout, object : NfcEvents {
240
+ override fun event(event: NfcEvent) {
241
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
242
+ .emit(EventType.EVENT.value, WritableNativeMap().apply {
243
+ putString("name", event.name)
244
+ putDouble(
245
+ "progress",
246
+ (event.numeratorForNisAndPace.toDouble() / NfcEvent.totalNisAndPaceOfNumeratorEvent.toDouble())
247
+ )
248
+ })
249
+ }
250
+
251
+ override fun error(error: NfcError) {
252
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
253
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
254
+ putString("name", mapNfcError(error).name)
255
+ error.msg?.let { putString("message", it) }
256
+ })
257
+
258
+ }
259
+ }, object : NisAndPaceCallback {
260
+ override fun onSuccess(intAuthMRTDResponse: IntAuthMRTDResponse) {
261
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
262
+ .emit(
263
+ EventType.INTERNAL_AUTH_AND_MRTD_WITH_PACE_SUCCESS.value,
264
+ WritableNativeMap().apply {
265
+ putMap("nis_data", WritableNativeMap().apply {
266
+ putString("nis", encoding.encode(intAuthMRTDResponse.internalAuthentication.nis))
267
+ putString(
268
+ "publicKey",
269
+ encoding.encode(intAuthMRTDResponse.internalAuthentication.kpubIntServ)
270
+ )
271
+ putString("sod", encoding.encode(intAuthMRTDResponse.internalAuthentication.sod))
272
+ putString(
273
+ "signedChallenge",
274
+ encoding.encode(intAuthMRTDResponse.internalAuthentication.challengeSigned)
275
+ )
276
+ })
277
+ putMap("mrtd_data", WritableNativeMap().apply {
278
+ putString("dg1", encoding.encode(intAuthMRTDResponse.mrtd.dg1))
279
+ putString("dg11", encoding.encode(intAuthMRTDResponse.mrtd.dg11))
280
+ putString("sod", encoding.encode(intAuthMRTDResponse.mrtd.sod))
281
+ })
282
+ })
283
+ }
284
+
285
+ override fun onError(error: NfcError) {
286
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
287
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
288
+ putString("name", mapNfcError(error).name)
289
+ error.msg?.let { putString("message", it) }
290
+ })
291
+ }
292
+ })
293
+ promise.resolve(null)
294
+ } catch (e: Exception) {
295
+ promise.reject(ModuleException.UNKNOWN_EXCEPTION, e.message, e)
296
+ }
297
+ }
298
+
299
+ @Suppress("unused")
102
300
  @ReactMethod
103
301
  fun startReadingAttributes(
104
302
  timeout: Int = 10000,
@@ -148,6 +346,7 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
148
346
  }
149
347
  }
150
348
 
349
+ @Suppress("unused")
151
350
  @ReactMethod
152
351
  fun startReading(
153
352
  pin: String,
@@ -159,7 +358,7 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
159
358
  cieSdk.setPin(pin)
160
359
  } catch (e: Exception) {
161
360
  promise.reject(ModuleException.PIN_REGEX_NOT_VALID, e.message, e)
162
- return;
361
+ return
163
362
  }
164
363
 
165
364
  try {
@@ -210,6 +409,67 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
210
409
  }
211
410
  }
212
411
 
412
+ @Suppress("unused")
413
+ @ReactMethod
414
+ fun startReadingCertificate(
415
+ pin: String,
416
+ timeout: Int = 10000,
417
+ promise: Promise,
418
+ ) {
419
+ try {
420
+ cieSdk.setPin(pin)
421
+ } catch (e: Exception) {
422
+ promise.reject(ModuleException.PIN_REGEX_NOT_VALID, e.message, e)
423
+ return
424
+ }
425
+
426
+ try {
427
+ cieSdk.startReadingCertificate(timeout, object : NfcEvents {
428
+ override fun event(event: NfcEvent) {
429
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
430
+ .emit(EventType.EVENT.value, WritableNativeMap().apply {
431
+ putString("name", event.name)
432
+ putDouble(
433
+ "progress", (event.numerator.toDouble() / NfcEvent.totalNumeratorEvent.toDouble())
434
+ )
435
+ })
436
+ }
437
+
438
+ override fun error(error: NfcError) {
439
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
440
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
441
+ putString("name", mapNfcError(error).name)
442
+ error.msg?.let { putString("msg", it) }
443
+ error.numberOfAttempts?.let { putInt("attemptsLeft", it) }
444
+ })
445
+
446
+ }
447
+ }, object : CieCertificateDataCallback {
448
+ override fun onSuccess(data: CertificateData) {
449
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
450
+ .emit(EventType.CERTIFICATE_SUCCESS.value, WritableNativeMap().apply {
451
+ putString("name", data.name)
452
+ putString("surname", data.surname)
453
+ putString("fiscalCode", data.fiscalCode)
454
+ putString("docSerialNumber", data.docSerialNumber)
455
+ })
456
+ }
457
+
458
+ override fun onError(error: NfcError) {
459
+ this@IoReactNativeCieModule.reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
460
+ .emit(EventType.ERROR.value, WritableNativeMap().apply {
461
+ putString("name", mapNfcError(error).name)
462
+ error.msg?.let { putString("message", it) }
463
+ })
464
+ }
465
+ })
466
+ promise.resolve(null)
467
+ } catch (e: Exception) {
468
+ promise.reject(ModuleException.UNKNOWN_EXCEPTION, e.message, e)
469
+ }
470
+ }
471
+
472
+ @Suppress("unused")
213
473
  @ReactMethod
214
474
  fun stopReading() {
215
475
  cieSdk.stopNFCListening()
@@ -239,13 +499,39 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
239
499
 
240
500
  companion object {
241
501
  const val NAME = "IoReactNativeCie"
242
- const val ERROR_USER_INFO_KEY = "error"
502
+
503
+ enum class ResultEncoding(val value: String) {
504
+ HEX("hex"),
505
+ BASE64("base64"),
506
+ BASE64URL("base64url");
507
+
508
+ fun encode(data: ByteArray): String = when (this) {
509
+ HEX -> data.toHex().uppercase()
510
+ BASE64 -> Base64.encodeToString(data, Base64.DEFAULT or Base64.NO_WRAP)
511
+ BASE64URL -> Base64.encodeToString(data, Base64.URL_SAFE or Base64.NO_WRAP)
512
+ }
513
+
514
+ companion object {
515
+ fun fromString(value: String?): ResultEncoding {
516
+ return when (value) {
517
+ "hex" -> HEX
518
+ "base64" -> BASE64
519
+ "base64url" -> BASE64URL
520
+ else -> BASE64 // Default
521
+ }
522
+ }
523
+ }
524
+ }
243
525
 
244
526
  enum class EventType(val value: String) {
245
527
  EVENT("onEvent"),
246
528
  ERROR("onError"),
247
529
  ATTRIBUTES_SUCCESS("onAttributesSuccess"),
248
- SUCCESS("onSuccess")
530
+ INTERNAL_AUTHENTICATION_SUCCESS("onInternalAuthenticationSuccess"),
531
+ MRTD_WITH_PACE_SUCCESS("onMRTDWithPaceSuccess"),
532
+ INTERNAL_AUTH_AND_MRTD_WITH_PACE_SUCCESS("onInternalAuthAndMRTDWithPaceSuccess"),
533
+ SUCCESS("onSuccess"),
534
+ CERTIFICATE_SUCCESS("onCertificateSuccess")
249
535
  }
250
536
 
251
537
  enum class ErrorType {
@@ -262,9 +548,9 @@ class IoReactNativeCieModule(reactContext: ReactApplicationContext) :
262
548
  }
263
549
 
264
550
  private object ModuleException {
265
- const val PIN_REGEX_NOT_VALID = "PIN_REGEX_NOT_VALID";
266
- const val INVALID_AUTH_URL = "INVALID_AUTH_URL";
267
- const val UNKNOWN_EXCEPTION = "UNKNOWN_EXCEPTION";
551
+ const val PIN_REGEX_NOT_VALID = "PIN_REGEX_NOT_VALID"
552
+ const val INVALID_AUTH_URL = "INVALID_AUTH_URL"
553
+ const val UNKNOWN_EXCEPTION = "UNKNOWN_EXCEPTION"
268
554
  }
269
555
  }
270
556
  }
@@ -9,9 +9,9 @@ import Foundation
9
9
 
10
10
  extension Data {
11
11
 
12
- /// Converts the data to a lowercase hexadecimal string.
12
+ /// Converts the data to an uppercase hexadecimal string.
13
13
  func toHexString() -> String {
14
- return self.map { String(format: "%02x", $0) }.joined()
14
+ return self.map { String(format: "%02X", $0) }.joined()
15
15
  }
16
16
 
17
17
  /// Converts the data to a base64url encoded string (RFC 7515), without padding.
@@ -32,6 +32,11 @@ extension Array where Element == UInt8 {
32
32
  return Data(self).toHexString()
33
33
  }
34
34
 
35
+ /// Converts the byte array to a base64 encoded string.
36
+ func base64EncodedString() -> String {
37
+ return Data(self).base64EncodedString()
38
+ }
39
+
35
40
  /// Converts the byte array to a base64url encoded string.
36
41
  func base64UrlEncodedString() -> String {
37
42
  return Data(self).base64UrlEncodedString()
@@ -42,6 +47,8 @@ extension Array where Element == UInt8 {
42
47
  case .HEX:
43
48
  return Data(self).toHexString()
44
49
  case .BASE64:
50
+ return Data(self).base64EncodedString()
51
+ case .BASE64URL:
45
52
  return Data(self).base64UrlEncodedString()
46
53
  }
47
54
  }
@@ -8,6 +8,7 @@
8
8
  enum DataEncoding: String, Sendable {
9
9
  case HEX = "HEX"
10
10
  case BASE64 = "BASE64"
11
+ case BASE64URL = "BASE64URL"
11
12
 
12
13
  static func from(string: String?) -> DataEncoding {
13
14
  return DataEncoding(rawValue: string?.uppercased() ?? "") ?? .BASE64
@@ -31,6 +31,19 @@ RCT_EXTERN_METHOD(startInternalAuthentication: (NSString)challenge
31
31
  withResolver: (RCTPromiseResolveBlock)resolve
32
32
  withRejecter: (RCTPromiseRejectBlock)reject)
33
33
 
34
+ RCT_EXTERN_METHOD(startMRTDReading: (NSString)can
35
+ withResultEncoding: (NSString)encodingString
36
+ withTimeout: (NSNumber)timeout
37
+ withResolver: (RCTPromiseResolveBlock)resolve
38
+ withRejecter: (RCTPromiseRejectBlock)reject)
39
+
40
+ RCT_EXTERN_METHOD(startInternalAuthAndMRTDReading: (NSString)can
41
+ withChallenge: (NSString)challenge
42
+ withResultEncoding: (NSString)encodingString
43
+ withTimeout: (NSNumber)timeout
44
+ withResolver: (RCTPromiseResolveBlock)resolve
45
+ withRejecter: (RCTPromiseRejectBlock)reject)
46
+
34
47
  RCT_EXTERN_METHOD(startReadingAttributes: (NSNumber)timeout
35
48
  withResolver: (RCTPromiseResolveBlock)resolve
36
49
  withRejecter: (RCTPromiseRejectBlock)reject)
@@ -41,6 +54,11 @@ RCT_EXTERN_METHOD(startReading: (NSString)pin
41
54
  withResolver: (RCTPromiseResolveBlock)resolve
42
55
  withRejecter: (RCTPromiseRejectBlock)reject)
43
56
 
57
+ RCT_EXTERN_METHOD(startReadingCertificate: (NSString)pin
58
+ withTimeout: (NSNumber)timeout
59
+ withResolver: (RCTPromiseResolveBlock)resolve
60
+ withRejecter: (RCTPromiseRejectBlock)reject)
61
+
44
62
  + (BOOL)requiresMainQueueSetup
45
63
  {
46
64
  return NO;