@trustchex/react-native-sdk 1.409.0 → 1.472.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 (171) hide show
  1. package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKModule.kt +2 -8
  2. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +102 -4
  3. package/ios/Camera/TrustchexCameraView.swift +151 -18
  4. package/ios/Permission/PermissionModule.m +22 -0
  5. package/ios/Permission/PermissionModule.swift +67 -0
  6. package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
  7. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +1 -4
  8. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +17 -4
  9. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +125 -25
  10. package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
  11. package/lib/module/Screens/Dynamic/VideoCallScreen.js +10 -13
  12. package/lib/module/Screens/Static/ResultScreen.js +131 -22
  13. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
  14. package/lib/module/Shared/Animations/recording.json +1 -0
  15. package/lib/module/Shared/Components/DebugNavigationPanel.js +69 -71
  16. package/lib/module/Shared/Components/EIDScanner.js +222 -115
  17. package/lib/module/Shared/Components/FaceCamera.js +14 -8
  18. package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
  19. package/lib/module/Shared/Components/IdentityDocumentCamera.js +60 -42
  20. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
  21. package/lib/module/Shared/Components/NavigationManager.js +24 -16
  22. package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
  23. package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
  24. package/lib/module/Shared/EIDReader/bacKey.js +16 -2
  25. package/lib/module/Shared/EIDReader/eidReader.js +354 -13
  26. package/lib/module/Shared/EIDReader/eidService.js +25 -1
  27. package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
  28. package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
  29. package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
  30. package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
  31. package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
  32. package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
  33. package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
  34. package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
  35. package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
  36. package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
  37. package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
  38. package/lib/module/Shared/Libs/PERMISSIONS_MANAGER.md +268 -0
  39. package/lib/module/Shared/Libs/analytics.utils.js +4 -0
  40. package/lib/module/Shared/Libs/contains.js +1 -40
  41. package/lib/module/Shared/Libs/country-display.utils.js +34 -0
  42. package/lib/module/Shared/Libs/demo.utils.js +8 -0
  43. package/lib/module/Shared/Libs/index.js +20 -0
  44. package/lib/module/Shared/Libs/mrz.utils.js +3 -2
  45. package/lib/module/Shared/Libs/permissions.utils.js +199 -0
  46. package/lib/module/Shared/Libs/status-bar.utils.js +4 -2
  47. package/lib/module/Shared/Types/analytics.types.js +2 -0
  48. package/lib/module/Translation/Resources/en.js +42 -2
  49. package/lib/module/Translation/Resources/tr.js +42 -2
  50. package/lib/module/Trustchex.js +54 -20
  51. package/lib/module/version.js +1 -1
  52. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
  53. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
  54. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  55. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  56. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  57. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
  58. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
  59. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
  60. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  61. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  62. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  63. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  64. package/lib/typescript/src/Shared/Components/FaceCamera.d.ts.map +1 -1
  65. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  66. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
  67. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
  68. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
  69. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
  70. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  71. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
  72. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
  73. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
  74. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
  75. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
  76. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
  77. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
  78. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
  79. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
  80. package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
  81. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
  82. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
  83. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
  84. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
  85. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
  86. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
  87. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
  88. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
  89. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
  90. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
  91. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
  92. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
  93. package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
  94. package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
  95. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
  96. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
  97. package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
  98. package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
  99. package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
  100. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
  101. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
  102. package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
  103. package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
  104. package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
  105. package/lib/typescript/src/Shared/Libs/index.d.ts +20 -0
  106. package/lib/typescript/src/Shared/Libs/index.d.ts.map +1 -0
  107. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  108. package/lib/typescript/src/Shared/Libs/permissions.utils.d.ts +58 -0
  109. package/lib/typescript/src/Shared/Libs/permissions.utils.d.ts.map +1 -0
  110. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -1
  111. package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
  112. package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
  113. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +10 -1
  114. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  115. package/lib/typescript/src/Translation/Resources/en.d.ts +41 -1
  116. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  117. package/lib/typescript/src/Translation/Resources/tr.d.ts +41 -1
  118. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  119. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  120. package/lib/typescript/src/version.d.ts +1 -1
  121. package/package.json +7 -4
  122. package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
  123. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +1 -4
  124. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +21 -4
  125. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +165 -24
  126. package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
  127. package/src/Screens/Dynamic/VideoCallScreen.tsx +11 -20
  128. package/src/Screens/Static/ResultScreen.tsx +187 -31
  129. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +9 -0
  130. package/src/Shared/Animations/recording.json +1 -0
  131. package/src/Shared/Components/DebugNavigationPanel.tsx +73 -48
  132. package/src/Shared/Components/EIDScanner.tsx +280 -119
  133. package/src/Shared/Components/FaceCamera.tsx +19 -16
  134. package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
  135. package/src/Shared/Components/IdentityDocumentCamera.tsx +206 -191
  136. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
  137. package/src/Shared/Components/NavigationManager.tsx +27 -18
  138. package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
  139. package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
  140. package/src/Shared/EIDReader/bacKey.ts +24 -8
  141. package/src/Shared/EIDReader/eidReader.ts +398 -12
  142. package/src/Shared/EIDReader/eidService.ts +49 -1
  143. package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
  144. package/src/Shared/EIDReader/paceInfo.ts +159 -0
  145. package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
  146. package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
  147. package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
  148. package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
  149. package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
  150. package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
  151. package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
  152. package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
  153. package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
  154. package/src/Shared/Libs/PERMISSIONS_MANAGER.md +268 -0
  155. package/src/Shared/Libs/analytics.utils.ts +4 -0
  156. package/src/Shared/Libs/contains.ts +0 -53
  157. package/src/Shared/Libs/country-display.utils.ts +55 -0
  158. package/src/Shared/Libs/crypto.utils.ts +2 -2
  159. package/src/Shared/Libs/demo.utils.ts +10 -0
  160. package/src/Shared/Libs/http-client.ts +12 -4
  161. package/src/Shared/Libs/index.ts +63 -0
  162. package/src/Shared/Libs/mrz.utils.ts +3 -2
  163. package/src/Shared/Libs/permissions.utils.ts +251 -0
  164. package/src/Shared/Libs/status-bar.utils.ts +4 -2
  165. package/src/Shared/Services/VideoSessionService.ts +1 -1
  166. package/src/Shared/Types/analytics.types.ts +2 -0
  167. package/src/Shared/Types/identificationInfo.ts +11 -0
  168. package/src/Translation/Resources/en.ts +64 -3
  169. package/src/Translation/Resources/tr.ts +63 -3
  170. package/src/Trustchex.tsx +53 -17
  171. package/src/version.ts +1 -1
@@ -56,7 +56,7 @@ export class SecureMessagingWrapper {
56
56
  const dataOutputStream = Array.from(this.getEncodedSendSequenceCounter());
57
57
  const paddedData = cryptoUtils.pad(Buffer.from(rapdu), 0, rapdu.length - 2 - 8 - 2, this.getPadLength());
58
58
  dataOutputStream.push(...paddedData);
59
- let cc2 = Uint8Array.from(Buffer.from(cryptoUtils.computeMac(Buffer.from(dataOutputStream).toString('hex'), this.ksMac), 'hex'));
59
+ let cc2 = Uint8Array.from(Buffer.from(this.computeMAC(Buffer.from(dataOutputStream).toString('hex'), this.ksMac), 'hex'));
60
60
  if (cc2.length > 8 && cc.length === 8) {
61
61
  const newCC2 = new Uint8Array(8);
62
62
  for (let i = 0; i < 8; i++) {
@@ -70,6 +70,29 @@ export class SecureMessagingWrapper {
70
70
  return false;
71
71
  }
72
72
  }
73
+ /**
74
+ * Encrypt data using the session encryption key.
75
+ * Subclasses override for AES vs 3DES.
76
+ */
77
+ encrypt(dataHex, keyHex) {
78
+ return cryptoUtils.encryptWith3DES(dataHex, keyHex);
79
+ }
80
+
81
+ /**
82
+ * Decrypt data using the session encryption key.
83
+ * Subclasses override for AES vs 3DES.
84
+ */
85
+ decrypt(dataHex, keyHex) {
86
+ return cryptoUtils.decryptWith3DES(dataHex, keyHex);
87
+ }
88
+
89
+ /**
90
+ * Compute MAC over data using the session MAC key.
91
+ * Subclasses override for AES-CMAC vs 3DES MAC.
92
+ */
93
+ computeMAC(dataHex, keyHex) {
94
+ return cryptoUtils.computeMac(dataHex, keyHex);
95
+ }
73
96
  wrapCommandAPDU(commandAPDU) {
74
97
  const cla = commandAPDU.getCLA();
75
98
  const ins = commandAPDU.getINS();
@@ -88,7 +111,7 @@ export class SecureMessagingWrapper {
88
111
  }
89
112
  if (lc > 0) {
90
113
  const data = cryptoUtils.pad(Buffer.from(commandAPDU.getData()), 0, commandAPDU.getData().length, this.getPadLength());
91
- const ciphertext = Buffer.from(cryptoUtils.encryptWith3DES(Buffer.from(data).toString('hex'), this.ksEnc), 'hex');
114
+ const ciphertext = Buffer.from(this.encrypt(Buffer.from(data).toString('hex'), this.ksEnc), 'hex');
92
115
  output.push(hasDO85 ? 0x85 : 0x87);
93
116
  output.push(...TLVUtil.getLengthAsBytes(ciphertext.length + (hasDO85 ? 0 : 1)));
94
117
  if (!hasDO85) {
@@ -99,7 +122,7 @@ export class SecureMessagingWrapper {
99
122
  }
100
123
  output = [...this.getEncodedSendSequenceCounter(), ...paddedMaskedHeader, ...do8587, ...do97];
101
124
  const n = cryptoUtils.pad(Buffer.from(output), 0, output.length, this.getPadLength());
102
- const cc = Buffer.from(cryptoUtils.computeMac(Buffer.from(n).toString('hex'), this.ksMac), 'hex');
125
+ const cc = Buffer.from(this.computeMAC(Buffer.from(n).toString('hex'), this.ksMac), 'hex');
103
126
  let ccLength = cc.length;
104
127
  if (ccLength !== 8) {
105
128
  ccLength = 8;
@@ -194,7 +217,7 @@ export class SecureMessagingWrapper {
194
217
  }
195
218
  const ciphertext = Buffer.alloc(length);
196
219
  inputStream.readFully(ciphertext);
197
- const paddedData = Array.from(Buffer.from(cryptoUtils.decryptWith3DES(Buffer.from(ciphertext).toString('hex'), this.ksEnc), 'hex'));
220
+ const paddedData = Array.from(Buffer.from(this.decrypt(Buffer.from(ciphertext).toString('hex'), this.ksEnc), 'hex'));
198
221
  return cryptoUtils.unpad(paddedData);
199
222
  }
200
223
  async readDO99(inputStream) {
@@ -8,7 +8,8 @@ export class CommandAPDU {
8
8
  dataOffset = 0;
9
9
  constructor(cla, ins, p1, p2, data, dataOffset, dataLength, ne) {
10
10
  this.nc = dataLength || 0;
11
- this.ne = ne || 0;
11
+ // Java JMRTD uses -1 to mean "no Le field" (ne=0). Guard against negatives.
12
+ this.ne = ne == null || ne < 0 ? 0 : ne;
12
13
  this.apdu = this.buildAPDU(cla, ins, p1, p2, data, dataOffset || 0, this.nc, this.ne);
13
14
  }
14
15
  buildAPDU(cla, ins, p1, p2, data, dataOffset = 0, dataLength = 0, ne = 0) {
@@ -83,7 +83,7 @@ export class TLVHelpers extends ASN1Constants {
83
83
  static log(n, base) {
84
84
  let result = 0;
85
85
  while (n > 0) {
86
- n = n / base;
86
+ n = Math.floor(n / base);
87
87
  result++;
88
88
  }
89
89
  return result;
@@ -39,7 +39,7 @@ class TLVUtil extends TLVHelpers {
39
39
  try {
40
40
  const actualTag = await tlvInputStream.readTag();
41
41
  if (actualTag !== expectedTag) {
42
- throw new Error(`Expected tag ${expectedTag.toString(16)}, found tag ${actualTag.toString(16)}`);
42
+ throw new Error(`Expected TLV tag 0x${expectedTag.toString(16)}, found 0x${actualTag.toString(16)} in data: ${Buffer.from(wrappedData.slice(0, 16)).toString('hex')}`);
43
43
  }
44
44
  const length = await tlvInputStream.readLength();
45
45
  const value = await tlvInputStream.readValue();
@@ -49,8 +49,11 @@ class TLVUtil extends TLVHelpers {
49
49
  }
50
50
  return result;
51
51
  } catch (ioe) {
52
- // Never happens.
53
- throw new Error('Error reading from stream');
52
+ // Re-throw original error with context rather than masking it
53
+ if (ioe instanceof Error && ioe.message.includes('Expected TLV tag')) {
54
+ throw ioe;
55
+ }
56
+ throw new Error(`TLV unwrap error (expected tag 0x${expectedTag.toString(16)}): ${ioe instanceof Error ? ioe.message : String(ioe)}`);
54
57
  } finally {
55
58
  try {
56
59
  tlvInputStream.close();
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+
3
+ import CryptoJS from 'crypto-js';
4
+ import { Buffer } from 'buffer';
5
+ import 'react-native-get-random-values';
6
+
7
+ /**
8
+ * AES cryptographic utilities for PACE protocol.
9
+ */
10
+
11
+ /**
12
+ * Encrypt data using AES in CBC mode with zero IV.
13
+ */
14
+ export const aesEncryptCBC = (dataHex, keyHex, ivHex = '00000000000000000000000000000000') => {
15
+ const data = CryptoJS.enc.Hex.parse(dataHex);
16
+ const key = CryptoJS.enc.Hex.parse(keyHex);
17
+ const iv = CryptoJS.enc.Hex.parse(ivHex);
18
+ const encrypted = CryptoJS.AES.encrypt(data, key, {
19
+ mode: CryptoJS.mode.CBC,
20
+ padding: CryptoJS.pad.NoPadding,
21
+ iv
22
+ });
23
+ return encrypted.ciphertext.toString(CryptoJS.enc.Hex);
24
+ };
25
+
26
+ /**
27
+ * Decrypt data using AES in CBC mode with zero IV.
28
+ */
29
+ export const aesDecryptCBC = (dataHex, keyHex, ivHex = '00000000000000000000000000000000') => {
30
+ const data = CryptoJS.enc.Hex.parse(dataHex);
31
+ const key = CryptoJS.enc.Hex.parse(keyHex);
32
+ const iv = CryptoJS.enc.Hex.parse(ivHex);
33
+ const cipherParams = CryptoJS.lib.CipherParams.create({
34
+ ciphertext: data
35
+ });
36
+ const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
37
+ mode: CryptoJS.mode.CBC,
38
+ padding: CryptoJS.pad.NoPadding,
39
+ iv
40
+ });
41
+ return decrypted.toString(CryptoJS.enc.Hex);
42
+ };
43
+
44
+ /**
45
+ * Encrypt a single block with AES in ECB mode (for SSC encryption).
46
+ */
47
+ export const aesEncryptECB = (dataHex, keyHex) => {
48
+ const data = CryptoJS.enc.Hex.parse(dataHex);
49
+ const key = CryptoJS.enc.Hex.parse(keyHex);
50
+ const encrypted = CryptoJS.AES.encrypt(data, key, {
51
+ mode: CryptoJS.mode.ECB,
52
+ padding: CryptoJS.pad.NoPadding
53
+ });
54
+ return encrypted.ciphertext.toString(CryptoJS.enc.Hex);
55
+ };
56
+
57
+ /**
58
+ * Compute AES CMAC (OMAC1) as defined in RFC 4493.
59
+ */
60
+ export const aesCMAC = (dataHex, keyHex) => {
61
+ const key = Buffer.from(keyHex, 'hex');
62
+ const data = Buffer.from(dataHex, 'hex');
63
+ const blockSize = 16;
64
+
65
+ // Step 1: Generate subkeys
66
+ const zeroBlock = '00000000000000000000000000000000';
67
+ const L = Buffer.from(aesEncryptECB(zeroBlock, keyHex), 'hex');
68
+ const K1 = generateSubkey(L);
69
+ const K2 = generateSubkey(K1);
70
+
71
+ // Step 2: Determine if we need to pad
72
+ const n = data.length === 0 ? 1 : Math.ceil(data.length / blockSize);
73
+ const lastBlockComplete = data.length > 0 && data.length % blockSize === 0;
74
+
75
+ // Step 3: Process last block
76
+ const lastBlock = Buffer.alloc(blockSize);
77
+ if (lastBlockComplete) {
78
+ const start = (n - 1) * blockSize;
79
+ for (let i = 0; i < blockSize; i++) {
80
+ lastBlock[i] = data[start + i] ^ K1[i];
81
+ }
82
+ } else {
83
+ // Pad with 10*
84
+ const start = (n - 1) * blockSize;
85
+ const remaining = data.length - start;
86
+ const padded = Buffer.alloc(blockSize);
87
+ for (let i = 0; i < remaining; i++) {
88
+ padded[i] = data[start + i];
89
+ }
90
+ padded[remaining] = 0x80;
91
+ for (let i = 0; i < blockSize; i++) {
92
+ lastBlock[i] = padded[i] ^ K2[i];
93
+ }
94
+ }
95
+
96
+ // Step 4: CBC-MAC
97
+ let X = Buffer.alloc(blockSize);
98
+ for (let i = 0; i < n - 1; i++) {
99
+ const block = data.subarray(i * blockSize, (i + 1) * blockSize);
100
+ const Y = Buffer.alloc(blockSize);
101
+ for (let j = 0; j < blockSize; j++) {
102
+ Y[j] = X[j] ^ block[j];
103
+ }
104
+ X = Buffer.from(aesEncryptECB(Y.toString('hex'), keyHex), 'hex');
105
+ }
106
+
107
+ // Process last block
108
+ const Y = Buffer.alloc(blockSize);
109
+ for (let j = 0; j < blockSize; j++) {
110
+ Y[j] = X[j] ^ lastBlock[j];
111
+ }
112
+ const T = aesEncryptECB(Y.toString('hex'), keyHex);
113
+ return T;
114
+ };
115
+ function generateSubkey(input) {
116
+ const blockSize = 16;
117
+ const Rb = Buffer.alloc(blockSize);
118
+ Rb[blockSize - 1] = 0x87;
119
+
120
+ // Left shift by 1
121
+ const output = Buffer.alloc(blockSize);
122
+ const msb = (input[0] & 0x80) !== 0;
123
+ for (let i = 0; i < blockSize - 1; i++) {
124
+ output[i] = (input[i] << 1 | input[i + 1] >> 7) & 0xff;
125
+ }
126
+ output[blockSize - 1] = input[blockSize - 1] << 1 & 0xff;
127
+ if (msb) {
128
+ for (let i = 0; i < blockSize; i++) {
129
+ output[i] ^= Rb[i];
130
+ }
131
+ }
132
+ return output;
133
+ }
134
+
135
+ /**
136
+ * Derive AES key from shared secret using KDF as per TR-SAC.
137
+ *
138
+ * @param sharedSecretHex the shared secret bytes as hex
139
+ * @param cipherAlg 'AES' or 'DESede'
140
+ * @param keyLength 128, 192, or 256
141
+ * @param mode 1 = ENC, 2 = MAC, 3 = PACE
142
+ */
143
+ export const deriveKey = (sharedSecretHex, cipherAlg, keyLength, mode) => {
144
+ const input = sharedSecretHex + '000000' + mode.toString(16).padStart(2, '0');
145
+ let hash;
146
+ if (cipherAlg === 'AES' && keyLength > 128) {
147
+ // Use SHA-256 for AES-192 and AES-256
148
+ hash = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(input)).toString(CryptoJS.enc.Hex);
149
+ } else {
150
+ // Use SHA-1 for DESede and AES-128
151
+ hash = CryptoJS.SHA1(CryptoJS.enc.Hex.parse(input)).toString(CryptoJS.enc.Hex);
152
+ }
153
+ if (cipherAlg === 'DESede') {
154
+ // 3DES: 24-byte key (K1 || K2 || K1)
155
+ const ka = hash.substring(0, 16);
156
+ const kb = hash.substring(16, 32);
157
+ return ka + kb + ka;
158
+ } else {
159
+ // AES: return first keyLength/8 bytes
160
+ const keyBytes = keyLength / 4; // hex chars = keyLength / 8 * 2
161
+ return hash.substring(0, keyBytes);
162
+ }
163
+ };
164
+
165
+ /**
166
+ * Pad data using ISO 9797-1 method 2 with given block size.
167
+ */
168
+ export const padISO9797 = (data, blockSize = 16) => {
169
+ const n = data.length;
170
+ const padLength = blockSize - n % blockSize;
171
+ const out = Buffer.alloc(n + padLength);
172
+ data.copy(out);
173
+ out[n] = 0x80;
174
+ return out;
175
+ };
176
+
177
+ /**
178
+ * Unpad ISO 9797-1 method 2.
179
+ */
180
+ export const unpadISO9797 = data => {
181
+ let i = data.length - 1;
182
+ while (i >= 0 && data[i] === 0x00) {
183
+ i--;
184
+ }
185
+ if (i >= 0 && data[i] === 0x80) {
186
+ return data.subarray(0, i);
187
+ }
188
+ return data;
189
+ };
@@ -0,0 +1,268 @@
1
+ # PermissionManager Documentation
2
+
3
+ ## Overview
4
+
5
+ `PermissionManager` is a centralized utility for handling all platform-specific permission requests (camera, microphone, NFC, etc.) in the React Native SDK. It abstracts away platform differences (iOS vs Android) and provides a clean, consistent API.
6
+
7
+ ## Location
8
+
9
+ - **File**: `src/Shared/Libs/permissions.utils.ts`
10
+ - **Export**: Can be imported from `src/Shared/Libs/index.ts`
11
+
12
+ ## Supported Permissions
13
+
14
+ ```typescript
15
+ type PermissionType = 'camera' | 'microphone' | 'nfc';
16
+ ```
17
+
18
+ | Permission | iOS | Android | Notes |
19
+ | ------------ | --- | ------- | ---------------------------------------- |
20
+ | `camera` | ✅ | ✅ | Camera access for video recording |
21
+ | `microphone` | ✅ | ✅ | Microphone access for audio recording |
22
+ | `nfc` | ✅ | ✅ | NFC chip reading (document verification) |
23
+
24
+ ## API Reference
25
+
26
+ ### Request Methods
27
+
28
+ #### `requestPermission(permission: PermissionType): Promise<boolean>`
29
+
30
+ Request a single permission. Returns `true` if granted, `false` if denied.
31
+
32
+ ```typescript
33
+ import PermissionManager from '../../Shared/Libs/permissions.utils';
34
+
35
+ const hasCamera = await PermissionManager.requestPermission('camera');
36
+ if (!hasCamera) {
37
+ console.log('Camera permission denied');
38
+ }
39
+ ```
40
+
41
+ #### `requestPermissions(permissions: PermissionType[]): Promise<Map<PermissionType, boolean>>`
42
+
43
+ Request multiple permissions at once. Returns a Map with permission status for each.
44
+
45
+ ```typescript
46
+ const results = await PermissionManager.requestPermissions([
47
+ 'camera',
48
+ 'microphone',
49
+ ]);
50
+ const hasCamera = results.get('camera') ?? false;
51
+ const hasMicrophone = results.get('microphone') ?? false;
52
+ ```
53
+
54
+ #### `requestCameraAndMicrophone(): Promise<boolean>`
55
+
56
+ **⭐ Convenience method** — Request camera and microphone together (common for video recording). Returns `true` only if BOTH are granted.
57
+
58
+ ```typescript
59
+ const hasBothPermissions = await PermissionManager.requestCameraAndMicrophone();
60
+ if (!hasBothPermissions) {
61
+ showError('Camera and microphone access required for video call');
62
+ }
63
+ ```
64
+
65
+ #### `requestCamera(): Promise<boolean>`
66
+
67
+ Request camera permission only.
68
+
69
+ ```typescript
70
+ const hasCamera = await PermissionManager.requestCamera();
71
+ ```
72
+
73
+ #### `requestMicrophone(): Promise<boolean>`
74
+
75
+ Request microphone permission only.
76
+
77
+ ```typescript
78
+ const hasMicrophone = await PermissionManager.requestMicrophone();
79
+ ```
80
+
81
+ #### `requestNFC(): Promise<boolean>`
82
+
83
+ Request NFC permission for document verification.
84
+
85
+ ```typescript
86
+ const hasNFC = await PermissionManager.requestNFC();
87
+ ```
88
+
89
+ #### `requestWithFallback(permission: PermissionType, onDenied?: () => void): Promise<boolean>`
90
+
91
+ Request permission with custom callback when denied.
92
+
93
+ ```typescript
94
+ const granted = await PermissionManager.requestWithFallback('camera', () => {
95
+ showAlert('Camera access is required for verification');
96
+ });
97
+ ```
98
+
99
+ ### Check Methods (Non-requesting)
100
+
101
+ Check if a permission is already granted without requesting.
102
+
103
+ #### `checkPermission(permission: PermissionType): Promise<boolean>`
104
+
105
+ Check a single permission status.
106
+
107
+ ```typescript
108
+ const hasCamera = await PermissionManager.checkPermission('camera');
109
+ ```
110
+
111
+ #### `hasCameraAndMicrophone(): Promise<boolean>`
112
+
113
+ Check if both camera and microphone are granted.
114
+
115
+ ```typescript
116
+ const ready = await PermissionManager.hasCameraAndMicrophone();
117
+ ```
118
+
119
+ #### `hasCamera(): Promise<boolean>`
120
+
121
+ Check if camera is granted.
122
+
123
+ ```typescript
124
+ const hasCamera = await PermissionManager.hasCamera();
125
+ ```
126
+
127
+ #### `hasMicrophone(): Promise<boolean>`
128
+
129
+ Check if microphone is granted.
130
+
131
+ ```typescript
132
+ const hasMicrophone = await PermissionManager.hasMicrophone();
133
+ ```
134
+
135
+ #### `hasNFC(): Promise<boolean>`
136
+
137
+ Check if NFC is granted.
138
+
139
+ ```typescript
140
+ const hasNFC = await PermissionManager.hasNFC();
141
+ ```
142
+
143
+ ## Common Patterns
144
+
145
+ ### Pattern 1: Video Call Setup (Camera + Microphone)
146
+
147
+ ```typescript
148
+ import PermissionManager from '../../Shared/Libs/permissions.utils';
149
+
150
+ async function initializeVideoCall() {
151
+ const hasBothPermissions =
152
+ await PermissionManager.requestCameraAndMicrophone();
153
+
154
+ if (!hasBothPermissions) {
155
+ setConnectionState('permissions_denied');
156
+ return;
157
+ }
158
+
159
+ // Proceed with video call initialization
160
+ const stream = await service.initialize();
161
+ setLocalStream(stream);
162
+ }
163
+ ```
164
+
165
+ ### Pattern 2: Document Verification (NFC)
166
+
167
+ ```typescript
168
+ const hasNFC = await PermissionManager.requestNFC();
169
+
170
+ if (!hasNFC) {
171
+ showError('NFC access required to read document');
172
+ return;
173
+ }
174
+
175
+ const result = await readNFCChip();
176
+ ```
177
+
178
+ ### Pattern 3: Check Before Requesting
179
+
180
+ ```typescript
181
+ // First check if permission is already granted
182
+ const alreadyHasCamera = await PermissionManager.checkPermission('camera');
183
+
184
+ if (alreadyHasCamera) {
185
+ // Skip request dialog
186
+ startCamera();
187
+ } else {
188
+ // Request permission (shows OS dialog)
189
+ const granted = await PermissionManager.requestCamera();
190
+ if (granted) {
191
+ startCamera();
192
+ } else {
193
+ showErrorMessage('Camera access required');
194
+ }
195
+ }
196
+ ```
197
+
198
+ ## Platform Implementation Details
199
+
200
+ ### iOS
201
+
202
+ Uses the `react-native-permissions` library with `RNPermissions` module.
203
+
204
+ **Permissions layout location**: `ios/App.xcodeproj/Info.plist`
205
+
206
+ Required Info.plist keys:
207
+
208
+ - `NSCameraUsageDescription` — Camera access explanation
209
+ - `NSMicrophoneUsageDescription` — Microphone access explanation
210
+ - `NFCReaderUsageDescription` — NFC access explanation
211
+
212
+ ### Android
213
+
214
+ Uses built-in `PermissionsAndroid` from React Native core.
215
+
216
+ **Permissions manifest location**: `android/app/src/main/AndroidManifest.xml`
217
+
218
+ Required manifest permissions:
219
+
220
+ - `android.permission.CAMERA` — Camera access
221
+ - `android.permission.RECORD_AUDIO` — Microphone access
222
+ - `android.permission.NFC` — NFC chip reading
223
+
224
+ ## Error Handling
225
+
226
+ The PermissionManager handles errors internally and logs them using the debug utility. All methods return clear boolean or Map results so you can check status directly:
227
+
228
+ ```typescript
229
+ const granted = await PermissionManager.requestCamera();
230
+
231
+ // Simple check
232
+ if (!granted) {
233
+ // Handle permission denied
234
+ }
235
+ ```
236
+
237
+ ## Best Practices
238
+
239
+ 1. ✅ **Use convenience methods** — `requestCameraAndMicrophone()` instead of manually requesting both
240
+ 2. ✅ **Request at the right time** — Request permissions when the feature is about to be used
241
+ 3. ✅ **Check before requesting** — Use `checkPermission()` if you want to skip the OS dialog
242
+ 4. ✅ **Handle denial gracefully** — Always provide clear error messages when permissions are denied
243
+ 5. ✅ **Use the centralized manager** — Never import React Native permissions directly; always use PermissionManager
244
+
245
+ ## Troubleshooting
246
+
247
+ ### Permission request dialog not appearing
248
+
249
+ - Check that you're using `request*` methods, not `check*` methods
250
+ - Verify the permission is in the app's manifest (Android) or Info.plist (iOS)
251
+ - Test on a device where the permission hasn't been granted yet
252
+
253
+ ### Camera/Microphone not working after permission granted
254
+
255
+ - Check that you're handling successful permission grant and initializing the feature
256
+ - Verify other features aren't holding exclusive access to the device
257
+
258
+ ### NFC not working on iOS
259
+
260
+ - Ensure `NFCReaderUsageDescription` is set in Info.plist
261
+ - The app must be signed with proper entitlements for NFC
262
+ - NFC requires iPhone XS or later
263
+
264
+ ## Related Files
265
+
266
+ - `src/Screens/Dynamic/VideoCallScreen.tsx` — Example usage with video calls
267
+ - `src/Shared/Libs/index.ts` — Exported for easy importing
268
+ - `src/Shared/Libs/debug.utils.ts` — Used internally for debug logging
@@ -189,6 +189,10 @@ const STEP_EVENT_MAP = {
189
189
  started: AnalyticsEventName.LIVENESS_CHECK_STARTED,
190
190
  completed: AnalyticsEventName.LIVENESS_CHECK_COMPLETED
191
191
  },
192
+ verbal_consent: {
193
+ started: AnalyticsEventName.VERBAL_CONSENT_VIDEO_STARTED,
194
+ completed: AnalyticsEventName.VERBAL_CONSENT_VIDEO_COMPLETED
195
+ },
192
196
  video_call: {
193
197
  started: AnalyticsEventName.VIDEO_CALL_STARTED,
194
198
  completed: AnalyticsEventName.VIDEO_CALL_COMPLETED
@@ -1,40 +1 @@
1
- "use strict";
2
-
3
- export function contains({
4
- outside,
5
- inside
6
- }) {
7
- const outsideMaxX = outside.minX + outside.width;
8
- const insideMaxX = inside.minX + inside.width;
9
- const outsideMaxY = outside.minY + outside.height;
10
- const insideMaxY = inside.minY + inside.height;
11
- if (inside.minX < outside.minX) {
12
- return false;
13
- }
14
- if (insideMaxX > outsideMaxX) {
15
- return false;
16
- }
17
- if (inside.minY < outside.minY) {
18
- return false;
19
- }
20
- if (insideMaxY > outsideMaxY) {
21
- return false;
22
- }
23
- return true;
24
- }
25
- export function contains2({
26
- outside,
27
- inside
28
- }) {
29
- const outsideMaxX = outside.minX + outside.width;
30
- const insideMaxX = inside.minX + inside.width;
31
- const outsideMaxY = outside.minY + outside.height;
32
- const insideMaxY = inside.minY + inside.height;
33
- const xIntersect = Math.max(0, Math.min(insideMaxX, outsideMaxX) - Math.max(inside.minX, outside.minX));
34
- const yIntersect = Math.max(0, Math.min(insideMaxY, outsideMaxY) - Math.max(inside.minY, outside.minY));
35
- const intersectArea = xIntersect * yIntersect;
36
- const insideArea = inside.width * inside.height;
37
- const outsideArea = outside.width * outside.height;
38
- const unionArea = insideArea + outsideArea - intersectArea;
39
- return unionArea === outsideArea;
40
- }
1
+ "use strict";
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ import { ISOCountry } from "../EIDReader/data/isoCountry.js";
4
+ import { UnicodeCountry } from "../EIDReader/data/unicodeCountry.js";
5
+ const COUNTRY_NAME_OVERRIDES = {
6
+ TUR: 'Türkiye'
7
+ };
8
+ const findCountryByAlpha3 = alpha3Code => {
9
+ return [...UnicodeCountry.VALUES, ...ISOCountry.VALUES].find(country => country.toAlpha3Code() === alpha3Code);
10
+ };
11
+ export const getLocalizedCountryName = (alpha3Code, _language) => {
12
+ if (!alpha3Code) return '';
13
+ const normalizedCode = alpha3Code.trim().toUpperCase();
14
+ const overrideName = COUNTRY_NAME_OVERRIDES[normalizedCode];
15
+ if (overrideName) {
16
+ return overrideName;
17
+ }
18
+ const country = findCountryByAlpha3(normalizedCode);
19
+ if (!country) {
20
+ return normalizedCode;
21
+ }
22
+ if (typeof Intl !== 'undefined' && 'Locale' in Intl && typeof Intl.Locale === 'function' && 'DisplayNames' in Intl && typeof Intl.DisplayNames === 'function') {
23
+ const nativeLanguage = new Intl.Locale(`und-${country.toAlpha2Code()}`).maximize().language;
24
+ if (nativeLanguage) {
25
+ const nativeName = new Intl.DisplayNames([nativeLanguage], {
26
+ type: 'region'
27
+ }).of(country.toAlpha2Code());
28
+ if (nativeName) {
29
+ return nativeName;
30
+ }
31
+ }
32
+ }
33
+ return country.getName();
34
+ };
@@ -28,6 +28,14 @@ const demoSession = {
28
28
  }
29
29
  }
30
30
  }
31
+ }, {
32
+ type: 'VERBAL_CONSENT',
33
+ required: false,
34
+ data: {
35
+ voiceGuidanceActive: true,
36
+ verbalConsentTitle: 'Verbal Consent',
37
+ verbalConsentText: 'I hereby provide my verbal consent for identity verification purposes. I confirm that all information provided is accurate and complete.'
38
+ }
31
39
  }, {
32
40
  type: 'IDENTITY_DOCUMENT_SCAN',
33
41
  required: false,
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ // Export utility modules with validated symbols only.
4
+ export { default as PermissionManager } from "./permissions.utils.js";
5
+ export { SignalingClient } from "./SignalingClient.js";
6
+ export { setDebugMode, setLogLevel, isDebugEnabled, getLogLevel, traceLog, debugLog, infoLog, debugWarn, debugError, logError, logWarn } from "./debug.utils.js";
7
+ export { default as HTTPClient, HttpClientError, UnauthorizedError, ForbiddenError, NotFoundError, BadRequestError, TooManyRequestsError, InternalServerError } from "./http-client.js";
8
+ export * from "./analytics.utils.js";
9
+ export { getLocalizedCountryName } from "./country-display.utils.js";
10
+ export { getSessionKey, encryptWithAes, decryptWithAes } from "./crypto.utils.js";
11
+ export { default as debounce } from "./debounce.utils.js";
12
+ export { handleDeepLink } from "./deeplink.utils.js";
13
+ export { getSimulatedDemoData, isDemoSession } from "./demo.utils.js";
14
+ export { default as MRZUtils } from "./mrz.utils.js";
15
+ export { NativeDeviceInfo } from "./native-device-info.utils.js";
16
+ export { default as getDeviceInfo } from "./native-device-info.utils.js";
17
+ export { useKeepAwake, enableKeepAwake, disableKeepAwake, isKeepAwakeCurrentlyActive, getKeepAwakeStats } from "./native-keep-awake.utils.js";
18
+ export { runWithRetry } from "./promise.utils.js";
19
+ export { configureStatusBarForWhiteBackground, useStatusBarWhiteBackground } from "./status-bar.utils.js";
20
+ export { speak, speakWithDebounce, stopSpeaking, resetLastMessage, initializeTTS } from "./tts.utils.js";