@trustchex/react-native-sdk 1.409.0 → 1.464.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 (156) 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 +59 -1
  3. package/ios/Camera/TrustchexCameraView.swift +9 -1
  4. package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
  5. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +1 -4
  6. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +17 -4
  7. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +102 -23
  8. package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
  9. package/lib/module/Screens/Dynamic/VideoCallScreen.js +3 -1
  10. package/lib/module/Screens/Static/ResultScreen.js +128 -22
  11. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
  12. package/lib/module/Shared/Animations/recording.json +1 -0
  13. package/lib/module/Shared/Components/DebugNavigationPanel.js +69 -71
  14. package/lib/module/Shared/Components/EIDScanner.js +212 -108
  15. package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
  16. package/lib/module/Shared/Components/IdentityDocumentCamera.js +53 -36
  17. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
  18. package/lib/module/Shared/Components/NavigationManager.js +24 -16
  19. package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
  20. package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
  21. package/lib/module/Shared/EIDReader/bacKey.js +16 -2
  22. package/lib/module/Shared/EIDReader/eidReader.js +354 -13
  23. package/lib/module/Shared/EIDReader/eidService.js +25 -1
  24. package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
  25. package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
  26. package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
  27. package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
  28. package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
  29. package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
  30. package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
  31. package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
  32. package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
  33. package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
  34. package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
  35. package/lib/module/Shared/Libs/analytics.utils.js +4 -0
  36. package/lib/module/Shared/Libs/contains.js +1 -40
  37. package/lib/module/Shared/Libs/country-display.utils.js +34 -0
  38. package/lib/module/Shared/Libs/demo.utils.js +8 -0
  39. package/lib/module/Shared/Libs/mrz.utils.js +3 -2
  40. package/lib/module/Shared/Libs/status-bar.utils.js +4 -2
  41. package/lib/module/Shared/Types/analytics.types.js +2 -0
  42. package/lib/module/Translation/Resources/en.js +41 -2
  43. package/lib/module/Translation/Resources/tr.js +41 -2
  44. package/lib/module/Trustchex.js +54 -20
  45. package/lib/module/version.js +1 -1
  46. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
  47. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
  48. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  49. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  50. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  51. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
  52. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
  53. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
  54. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  55. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  56. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  57. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  58. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  59. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
  60. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
  61. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
  62. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
  63. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  64. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
  65. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
  66. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
  67. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
  68. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
  69. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
  70. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
  71. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
  72. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
  73. package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
  74. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
  75. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
  76. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
  77. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
  78. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
  79. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
  80. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
  81. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
  82. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
  83. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
  84. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
  85. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
  86. package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
  87. package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
  88. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
  89. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
  90. package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
  91. package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
  92. package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
  93. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
  94. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
  95. package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
  96. package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
  97. package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
  98. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  99. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -1
  100. package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
  101. package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
  102. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +10 -1
  103. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  104. package/lib/typescript/src/Translation/Resources/en.d.ts +40 -1
  105. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  106. package/lib/typescript/src/Translation/Resources/tr.d.ts +40 -1
  107. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  108. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  109. package/lib/typescript/src/version.d.ts +1 -1
  110. package/package.json +7 -4
  111. package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
  112. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +1 -4
  113. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +21 -4
  114. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +124 -23
  115. package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
  116. package/src/Screens/Dynamic/VideoCallScreen.tsx +3 -1
  117. package/src/Screens/Static/ResultScreen.tsx +183 -31
  118. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +9 -0
  119. package/src/Shared/Animations/recording.json +1 -0
  120. package/src/Shared/Components/DebugNavigationPanel.tsx +73 -48
  121. package/src/Shared/Components/EIDScanner.tsx +222 -111
  122. package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
  123. package/src/Shared/Components/IdentityDocumentCamera.tsx +199 -184
  124. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
  125. package/src/Shared/Components/NavigationManager.tsx +27 -18
  126. package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
  127. package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
  128. package/src/Shared/EIDReader/bacKey.ts +24 -8
  129. package/src/Shared/EIDReader/eidReader.ts +398 -12
  130. package/src/Shared/EIDReader/eidService.ts +49 -1
  131. package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
  132. package/src/Shared/EIDReader/paceInfo.ts +159 -0
  133. package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
  134. package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
  135. package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
  136. package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
  137. package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
  138. package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
  139. package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
  140. package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
  141. package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
  142. package/src/Shared/Libs/analytics.utils.ts +4 -0
  143. package/src/Shared/Libs/contains.ts +0 -53
  144. package/src/Shared/Libs/country-display.utils.ts +55 -0
  145. package/src/Shared/Libs/crypto.utils.ts +2 -2
  146. package/src/Shared/Libs/demo.utils.ts +10 -0
  147. package/src/Shared/Libs/http-client.ts +12 -4
  148. package/src/Shared/Libs/mrz.utils.ts +3 -2
  149. package/src/Shared/Libs/status-bar.utils.ts +4 -2
  150. package/src/Shared/Services/VideoSessionService.ts +1 -1
  151. package/src/Shared/Types/analytics.types.ts +2 -0
  152. package/src/Shared/Types/identificationInfo.ts +11 -0
  153. package/src/Translation/Resources/en.ts +63 -3
  154. package/src/Translation/Resources/tr.ts +62 -3
  155. package/src/Trustchex.tsx +53 -17
  156. 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
+ };
@@ -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,
@@ -108,8 +108,9 @@ const fixMRZ = rawText => {
108
108
  // Must contain filler characters
109
109
  if (!/<+/.test(line)) return false;
110
110
 
111
- // Prioritize lines starting with I< (document code)
112
- if (line.startsWith('I<')) return true;
111
+ // Lines starting with a valid MRZ document code (ICAO 9303):
112
+ // I (ID cards), A (residence permits, admin docs), C (crew), P (passport), V (visa)
113
+ if (/^[IACPV][<A-Z]/.test(line)) return true;
113
114
 
114
115
  // Or lines with numbers and fillers (second line of TD1: birth date, expiry, etc.)
115
116
  if (/\d{5,}/.test(line) && /<{3,}/.test(line)) return true;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- import { StatusBar } from 'react-native';
3
+ import { Platform, StatusBar } from 'react-native';
4
4
  import { useEffect } from 'react';
5
5
 
6
6
  /**
@@ -8,7 +8,9 @@ import { useEffect } from 'react';
8
8
  */
9
9
  export const configureStatusBarForWhiteBackground = () => {
10
10
  StatusBar.setBarStyle('dark-content', true);
11
- StatusBar.setBackgroundColor('#ffffff', true);
11
+ if (Platform.OS === 'android') {
12
+ StatusBar.setBackgroundColor('#ffffff', true);
13
+ }
12
14
  };
13
15
 
14
16
  /**
@@ -68,6 +68,8 @@ export let AnalyticsEventName = /*#__PURE__*/function (AnalyticsEventName) {
68
68
  AnalyticsEventName["IDENTITY_DOCUMENT_EID_SCAN_COMPLETED"] = "identity_document_eid_scan_completed";
69
69
  AnalyticsEventName["LIVENESS_CHECK_STARTED"] = "liveness_check_started";
70
70
  AnalyticsEventName["LIVENESS_CHECK_COMPLETED"] = "liveness_check_completed";
71
+ AnalyticsEventName["VERBAL_CONSENT_VIDEO_STARTED"] = "verbal_consent_video_started";
72
+ AnalyticsEventName["VERBAL_CONSENT_VIDEO_COMPLETED"] = "verbal_consent_video_completed";
71
73
  AnalyticsEventName["VIDEO_CALL_STARTED"] = "video_call_started";
72
74
  AnalyticsEventName["VIDEO_CALL_COMPLETED"] = "video_call_completed";
73
75
  // NFC Scan Events (used by trackNFCScan* helpers)
@@ -41,6 +41,9 @@ export default {
41
41
  'resultScreen.demoImageHologram': 'Hologram',
42
42
  'resultScreen.demoLivenessDetection': 'Liveness Detection',
43
43
  'resultScreen.demoVideo': 'Video',
44
+ 'resultScreen.demoVerbalConsent': 'Verbal Consent',
45
+ 'resultScreen.demoVerbalConsentTitle': 'Title',
46
+ 'resultScreen.demoVerbalConsentText': 'Text',
44
47
  'resultScreen.demoStartOver': 'Start Over',
45
48
  'livenessDetectionScreen.guideHeader': 'Face Verification',
46
49
  'livenessDetectionScreen.guideText': 'Please ensure the following for best results:',
@@ -64,9 +67,8 @@ export default {
64
67
  'eidScannerScreen.guideHeader': 'NFC Document Scan',
65
68
  'eidScannerScreen.guideText': 'When prompted, hold your document flat against the back of your device near the NFC antenna.',
66
69
  'eidScannerScreen.invalidMRZFields': 'Document information could not be read. Please try again.',
67
- 'eidScannerScreen.imageCannotBeShown': 'Photo data found but cannot be displayed.',
68
70
  'eidScannerScreen.faceImageNotFound': 'Photo data not found on document.',
69
- 'eidScannerScreen.documentCode': 'Document Code',
71
+ 'eidScannerScreen.documentCode': 'Document Type',
70
72
  'eidScannerScreen.nationality': 'Nationality',
71
73
  'eidScannerScreen.personalNumber': 'Personal Number',
72
74
  'eidScannerScreen.documentNumber': 'Document Number',
@@ -74,6 +76,13 @@ export default {
74
76
  'eidScannerScreen.surname': 'Surname',
75
77
  'eidScannerScreen.birthDate': 'Date of Birth',
76
78
  'eidScannerScreen.gender': 'Gender',
79
+ 'eidScannerScreen.genderMale': 'Male',
80
+ 'eidScannerScreen.genderFemale': 'Female',
81
+ 'eidScannerScreen.genderUnspecified': 'Unspecified',
82
+ 'eidScannerScreen.docTypePassport': 'Passport',
83
+ 'eidScannerScreen.docTypeID': 'ID Card',
84
+ 'eidScannerScreen.docTypeResidence': 'Residence Permit',
85
+ 'eidScannerScreen.docTypeVisa': 'Visa',
77
86
  'eidScannerScreen.expirationDate': 'Expiration Date',
78
87
  'eidScannerScreen.mrzText': 'MRZ Text',
79
88
  'eidScannerScreen.nfcNotSupported': 'This device does not support NFC functionality.',
@@ -147,6 +156,36 @@ export default {
147
156
  'videoCallScreen.closeSessionHint': 'You can close this session and start a new verification',
148
157
  'videoCallScreen.agentInstructions': 'Instructions from Agent',
149
158
  'videoCallScreen.callNotCompleted': 'Video call was not completed. This step is required to proceed.',
159
+ 'verbalConsentVideoScreen.title': 'Verbal Consent',
160
+ 'verbalConsentVideoScreen.description': 'Read the text below clearly while recording your video.',
161
+ 'verbalConsentVideoScreen.guideHeader': 'Prepare for verbal consent recording',
162
+ 'verbalConsentVideoScreen.guideText': 'Before you start recording, please ensure the following:',
163
+ 'verbalConsentVideoScreen.guidePoint1': 'Stay in a quiet environment with minimal background noise',
164
+ 'verbalConsentVideoScreen.guidePoint2': 'Keep your full face visible in good lighting',
165
+ 'verbalConsentVideoScreen.guidePoint3': 'Read the consent text clearly and without rushing',
166
+ 'verbalConsentVideoScreen.guidePoint4': 'Keep your phone steady until recording completes',
167
+ 'verbalConsentVideoScreen.defaultConsentText': 'I confirm my identity and give my explicit consent to the processing of my personal data for digital identity verification. I acknowledge that my biometric data will be used solely for this purpose. I understand that I can withdraw this consent at any time.',
168
+ 'verbalConsentVideoScreen.startRecording': 'Start Recording',
169
+ 'verbalConsentVideoScreen.stopRecording': 'Stop Recording',
170
+ 'verbalConsentVideoScreen.recordAgain': 'Record Again',
171
+ 'verbalConsentVideoScreen.tryAgain': 'Try Again',
172
+ 'verbalConsentVideoScreen.submit': 'Continue',
173
+ 'verbalConsentVideoScreen.recordingProgress': 'Recording: {{current}}s',
174
+ 'verbalConsentVideoScreen.readNowPrompt': 'Read the text aloud — touch screen to pause.',
175
+ 'verbalConsentVideoScreen.scrollReadStopHint': 'Scroll to the end to enable Stop Recording.',
176
+ 'verbalConsentVideoScreen.scrollCompletedStopHint': 'Great. You reached the end. You can stop recording after finishing the full text.',
177
+ 'verbalConsentVideoScreen.recordingIndicator': 'Recording',
178
+ 'verbalConsentVideoScreen.recordingStartedBanner': 'Recording started. Read the full text and scroll to the end.',
179
+ 'verbalConsentVideoScreen.keepHeadInCirclePrompt': 'Place your head inside the circle and keep it there until recording is complete.',
180
+ 'verbalConsentVideoScreen.readThenStopPrompt': 'Read the text shown on screen, then stop recording.',
181
+ 'verbalConsentVideoScreen.readProgress': 'Read progress (estimated): {{current}}/{{target}}s',
182
+ 'verbalConsentVideoScreen.stopHintPending': 'Keep reading the full text before stopping.',
183
+ 'verbalConsentVideoScreen.stopHintReady': 'Looks complete. You can stop recording now.',
184
+ 'verbalConsentVideoScreen.faceAligned': 'Face aligned. You can start recording.',
185
+ 'verbalConsentVideoScreen.previewTitle': 'Review your recording and make sure the text is clear before continuing.',
186
+ 'verbalConsentVideoScreen.analytics.recordingFailed': 'Video recording failed',
187
+ 'verbalConsentVideoScreen.analytics.identificationIdMissing': 'Identification ID is missing before upload',
188
+ 'verbalConsentVideoScreen.analytics.uploadFailed': 'Consent video upload failed',
150
189
  'navigationManager.skipStepWarning': 'Completing this step is recommended for successful verification. Skip anyway?',
151
190
  'navigationManager.skipStepLabel': 'Skip This Step'
152
191
  };
@@ -41,6 +41,9 @@ export default {
41
41
  'resultScreen.demoImageHologram': 'Hologram',
42
42
  'resultScreen.demoLivenessDetection': 'Canlılık Tespiti',
43
43
  'resultScreen.demoVideo': 'Video',
44
+ 'resultScreen.demoVerbalConsent': 'Sözlü onay',
45
+ 'resultScreen.demoVerbalConsentTitle': 'Başlık',
46
+ 'resultScreen.demoVerbalConsentText': 'Metin',
44
47
  'resultScreen.demoStartOver': 'Baştan Başla',
45
48
  'livenessDetectionScreen.guideHeader': 'Yüz Doğrulaması',
46
49
  'livenessDetectionScreen.guideText': 'En iyi sonuç için lütfen şunları sağlayın:',
@@ -64,9 +67,8 @@ export default {
64
67
  'eidScannerScreen.guideHeader': 'NFC Belge Taraması',
65
68
  'eidScannerScreen.guideText': 'İstendiğinde, belgenizi cihazınızın arka tarafındaki NFC antenine düz bir şekilde yaklaştırın.',
66
69
  'eidScannerScreen.invalidMRZFields': 'Belge bilgileri okunamadı. Lütfen tekrar deneyin.',
67
- 'eidScannerScreen.imageCannotBeShown': 'Fotoğraf verisi bulundu ancak gösterilemiyor.',
68
70
  'eidScannerScreen.faceImageNotFound': 'Belgede fotoğraf verisi bulunamadı.',
69
- 'eidScannerScreen.documentCode': 'Belge Kodu',
71
+ 'eidScannerScreen.documentCode': 'Belge Türü',
70
72
  'eidScannerScreen.nationality': 'Uyruk',
71
73
  'eidScannerScreen.personalNumber': 'Vatandaşlık No',
72
74
  'eidScannerScreen.documentNumber': 'Belge No',
@@ -74,6 +76,13 @@ export default {
74
76
  'eidScannerScreen.surname': 'Soyad',
75
77
  'eidScannerScreen.birthDate': 'Doğum Tarihi',
76
78
  'eidScannerScreen.gender': 'Cinsiyet',
79
+ 'eidScannerScreen.genderMale': 'Erkek',
80
+ 'eidScannerScreen.genderFemale': 'Kadın',
81
+ 'eidScannerScreen.genderUnspecified': 'Belirtilmemiş',
82
+ 'eidScannerScreen.docTypePassport': 'Pasaport',
83
+ 'eidScannerScreen.docTypeID': 'Kimlik Kartı',
84
+ 'eidScannerScreen.docTypeResidence': 'Oturma İzni',
85
+ 'eidScannerScreen.docTypeVisa': 'Vize',
77
86
  'eidScannerScreen.expirationDate': 'Geçerlilik Tarihi',
78
87
  'eidScannerScreen.mrzText': 'MRZ Metni',
79
88
  'eidScannerScreen.nfcNotSupported': 'Bu cihaz NFC işlevini desteklememektedir.',
@@ -147,6 +156,36 @@ export default {
147
156
  'videoCallScreen.closeSessionHint': 'Bu oturumu kapatıp yeni bir doğrulama başlatabilirsiniz',
148
157
  'videoCallScreen.agentInstructions': 'Temsilciden Talimatlar',
149
158
  'videoCallScreen.callNotCompleted': 'Görüntülü görüşme tamamlanmadı. Devam etmek için bu adım zorunludur.',
159
+ 'verbalConsentVideoScreen.title': 'Sözlü Onay',
160
+ 'verbalConsentVideoScreen.description': 'Aşağıdaki metni net bir şekilde okuyarak videonuzu kaydedin.',
161
+ 'verbalConsentVideoScreen.guideHeader': 'Sözlü onay kaydı için hazırlanın',
162
+ 'verbalConsentVideoScreen.guideText': 'Kayda başlamadan önce lütfen aşağıdakileri sağlayın:',
163
+ 'verbalConsentVideoScreen.guidePoint1': 'Arka plan gürültüsünün az olduğu sessiz bir ortam seçin',
164
+ 'verbalConsentVideoScreen.guidePoint2': 'Yüzünüzün tamamı iyi aydınlatılmış şekilde görünür olsun',
165
+ 'verbalConsentVideoScreen.guidePoint3': 'Onay metnini net ve acele etmeden okuyun',
166
+ 'verbalConsentVideoScreen.guidePoint4': 'Kayıt tamamlanana kadar telefonu sabit tutun',
167
+ 'verbalConsentVideoScreen.defaultConsentText': 'Dijital kimlik doğrulama amacıyla kimliğimi teyit ediyor ve kişisel verilerimin işlenmesine açık rızamı veriyorum. Biyometrik verilerimin yalnızca kimlik doğrulama amacıyla işleneceğini kabul ediyorum. Bu onayı istediğim zaman geri çekebileceğimi biliyorum.',
168
+ 'verbalConsentVideoScreen.startRecording': 'Kaydı Başlat',
169
+ 'verbalConsentVideoScreen.stopRecording': 'Kaydı Durdur',
170
+ 'verbalConsentVideoScreen.recordAgain': 'Tekrar Kaydet',
171
+ 'verbalConsentVideoScreen.tryAgain': 'Tekrar Dene',
172
+ 'verbalConsentVideoScreen.submit': 'Devam Et',
173
+ 'verbalConsentVideoScreen.recordingProgress': 'Kayıt: {{current}} sn',
174
+ 'verbalConsentVideoScreen.readNowPrompt': 'Metni sesli okuyun — duraklatmak için ekrana dokunun.',
175
+ 'verbalConsentVideoScreen.scrollReadStopHint': 'Kaydı durdurmak için metnin sonuna kadar kaydırın.',
176
+ 'verbalConsentVideoScreen.scrollCompletedStopHint': 'Harika. Sona ulaştınız. Metnin tamamını bitirdikten sonra kaydı durdurabilirsiniz.',
177
+ 'verbalConsentVideoScreen.recordingIndicator': 'Kayıt',
178
+ 'verbalConsentVideoScreen.recordingStartedBanner': 'Kayıt başladı. Metnin tamamını okuyun ve sona kadar kaydırın.',
179
+ 'verbalConsentVideoScreen.keepHeadInCirclePrompt': 'Başınızı dairenin içine yerleştirin ve kayıt tamamlanana kadar sabit tutun.',
180
+ 'verbalConsentVideoScreen.readThenStopPrompt': 'Ekrandaki metni okuyun, ardından kaydı durdurun.',
181
+ 'verbalConsentVideoScreen.readProgress': 'Okuma ilerlemesi (tahmini): {{current}}/{{target}} sn',
182
+ 'verbalConsentVideoScreen.stopHintPending': 'Kaydı durdurmadan önce metnin tamamını okuyun.',
183
+ 'verbalConsentVideoScreen.stopHintReady': 'Metin tamamlanmış görünüyor. Kaydı şimdi durdurabilirsiniz.',
184
+ 'verbalConsentVideoScreen.faceAligned': 'Yüz hizalaması tamam. Kayda başlayabilirsiniz.',
185
+ 'verbalConsentVideoScreen.previewTitle': 'Devam etmeden önce kaydı kontrol edin ve metnin net olduğundan emin olun.',
186
+ 'verbalConsentVideoScreen.analytics.recordingFailed': 'Video kaydi basarisiz oldu',
187
+ 'verbalConsentVideoScreen.analytics.identificationIdMissing': 'Yukleme oncesinde kimlik numarasi bulunamadi',
188
+ 'verbalConsentVideoScreen.analytics.uploadFailed': 'Sozlu onay videosu yuklenemedi',
150
189
  'navigationManager.skipStepWarning': 'Başarılı bir doğrulama için bu adımı tamamlamanız önerilir. Yine de atlamak istiyor musunuz?',
151
190
  'navigationManager.skipStepLabel': 'Bu Adımı Atla'
152
191
  };