@trustchex/react-native-sdk 1.486.0 → 1.488.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/Shared/Components/EIDScanner.js +97 -37
- package/lib/module/Shared/Components/IdentityDocumentCamera.constants.js +9 -1
- package/lib/module/Shared/EIDReader/cardFileInputStream.js +25 -2
- package/lib/module/Shared/EIDReader/defaultFileSystem.js +56 -6
- package/lib/module/Shared/EIDReader/eidReader.js +124 -14
- package/lib/module/Shared/EIDReader/lds/icao/dg11File.js +23 -6
- package/lib/module/Shared/EIDReader/nfcManagerCardService.js +79 -9
- package/lib/module/Shared/EIDReader/protocol/paceDH.js +101 -0
- package/lib/module/Shared/EIDReader/protocol/paceErrors.js +34 -0
- package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +53 -4
- package/lib/module/Shared/EIDReader/protocol/readBinaryAPDUSender.js +7 -3
- package/lib/module/Shared/Libs/country-display.utils.js +13 -1
- package/lib/module/Shared/Libs/diagnosticReport.js +24 -1
- package/lib/module/Shared/Libs/diagnostics.js +30 -8
- package/lib/module/Shared/Libs/mrz.utils.js +172 -25
- package/lib/module/Shared/Libs/mrzFrameAggregator.js +29 -1
- package/lib/module/Shared/Libs/mrzTransliteration.js +14 -1
- package/lib/module/Translation/Resources/en.js +12 -0
- package/lib/module/Translation/Resources/tr.js +12 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.constants.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/cardFileInputStream.d.ts +3 -0
- package/lib/typescript/src/Shared/EIDReader/cardFileInputStream.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/defaultFileSystem.d.ts +4 -0
- package/lib/typescript/src/Shared/EIDReader/defaultFileSystem.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/lds/icao/dg11File.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts +9 -1
- package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/protocol/paceDH.d.ts +56 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceDH.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceErrors.d.ts +26 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceErrors.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/protocol/readBinaryAPDUSender.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/diagnosticReport.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/diagnostics.d.ts +9 -1
- package/lib/typescript/src/Shared/Libs/diagnostics.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts +1 -0
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrzFrameAggregator.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrzTransliteration.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +12 -0
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +12 -0
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/Shared/Components/EIDScanner.tsx +149 -68
- package/src/Shared/Components/IdentityDocumentCamera.constants.ts +9 -1
- package/src/Shared/EIDReader/cardFileInputStream.ts +30 -6
- package/src/Shared/EIDReader/defaultFileSystem.ts +75 -17
- package/src/Shared/EIDReader/eidReader.ts +154 -21
- package/src/Shared/EIDReader/lds/icao/dg11File.ts +28 -13
- package/src/Shared/EIDReader/nfcManagerCardService.ts +91 -13
- package/src/Shared/EIDReader/protocol/paceDH.ts +183 -0
- package/src/Shared/EIDReader/protocol/paceErrors.ts +41 -0
- package/src/Shared/EIDReader/protocol/paceProtocol.ts +72 -6
- package/src/Shared/EIDReader/protocol/readBinaryAPDUSender.ts +7 -4
- package/src/Shared/Libs/country-display.utils.ts +12 -1
- package/src/Shared/Libs/diagnosticReport.ts +32 -1
- package/src/Shared/Libs/diagnostics.ts +38 -14
- package/src/Shared/Libs/mrz.utils.ts +193 -28
- package/src/Shared/Libs/mrzFrameAggregator.ts +38 -3
- package/src/Shared/Libs/mrzTransliteration.ts +16 -3
- package/src/Translation/Resources/en.ts +19 -0
- package/src/Translation/Resources/tr.ts +19 -0
- package/src/version.ts +1 -1
|
@@ -38,7 +38,9 @@ export interface NfcDiagnostics {
|
|
|
38
38
|
/** PACE object identifier string when PACE was attempted. */
|
|
39
39
|
paceOid?: string;
|
|
40
40
|
/** Why PACE wasn't used / fell back: 'no_card_access' | 'no_pace_info' |
|
|
41
|
-
* 'pace_failed'
|
|
41
|
+
* 'pace_failed' | 'pace_unsupported_<agreement|mapping|curve|cipher>'.
|
|
42
|
+
* The pace_unsupported_* reasons mark a CAPABILITY gap (this build can't run
|
|
43
|
+
* the variant the chip advertises) vs pace_failed (a runtime failure). */
|
|
42
44
|
paceFallbackReason?: string;
|
|
43
45
|
steps: NfcStep[];
|
|
44
46
|
/** Name of the first failing step, if any. */
|
|
@@ -131,6 +133,12 @@ export declare class DiagnosticsCollector {
|
|
|
131
133
|
nfcPaceFellBackToBac(reason?: string): void;
|
|
132
134
|
/** Record one completed step. Keep messages short and free of PII. */
|
|
133
135
|
nfcStep(step: NfcStep): void;
|
|
136
|
+
/** The first NFC step that failed in the current attempt (e.g. 'paceAuth',
|
|
137
|
+
* 'readDG2'), or undefined. Lets the caller build a step-specific error code
|
|
138
|
+
* without taking a full snapshot. */
|
|
139
|
+
getFailureStep(): string | undefined;
|
|
140
|
+
/** APDU status word recorded for the failing step, if any (e.g. '6982'). */
|
|
141
|
+
getFailureStatusWord(): string | undefined;
|
|
134
142
|
nfcResult(succeeded: boolean, errorCategory?: string): void;
|
|
135
143
|
addError(e: {
|
|
136
144
|
code?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,sEAAsE;AACtE,MAAM,WAAW,OAAO;IACtB;sDACkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,kFAAkF;IAClF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;kEAC8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACtC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,6 +33,7 @@ declare const _default: {
|
|
|
33
33
|
isValidOCRBPattern: (text: string) => boolean;
|
|
34
34
|
applyOCRBCorrections: (text: string) => string;
|
|
35
35
|
convertMRZDateToISODate: (mrzDate?: string | null) => string | null;
|
|
36
|
+
normalizeDocumentCode: (code: string | null | undefined) => string | null;
|
|
36
37
|
};
|
|
37
38
|
export default _default;
|
|
38
39
|
//# sourceMappingURL=mrz.utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mrz.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/mrz.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"mrz.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/mrz.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AA4EpD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;;sBAOwB,MAAM,KAAG,MAAM;2BA+oC7B,MAAM,gBACF,OAAO,KACnB,mBAAmB;0CAwKuB,MAAM,KAAG,mBAAmB;wCApnC9B,MAAM,KAAG,MAAM,EAAE,EAAE;wCA8nCnB,MAAM,KAAG,MAAM;gCAmDvB,MAAM;;;;;+BA/1BP,MAAM,KAAG,OAAO;iCA4Bd,MAAM,KAAG,MAAM;wCAi1BR,MAAM,GAAG,IAAI,KAAG,MAAM,GAAG,IAAI;kCAn9ChE,MAAM,GAAG,IAAI,GAAG,SAAS,KAC9B,MAAM,GAAG,IAAI;;AAk+ChB,wBAWE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mrzFrameAggregator.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/mrzFrameAggregator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAkCvD,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,+EAA+E;IAC/E,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACvC,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"mrzFrameAggregator.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/mrzFrameAggregator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAkCvD,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,+EAA+E;IAC/E,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACvC,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqHD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAInC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,cAAc,CAAK;gBAEf,OAAO,GAAE,yBAA8B;IAMnD,KAAK,IAAI,IAAI;IAQb;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;IA0B5B,iCAAiC;IACjC,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,OAAO,CAAC,WAAW;IAUnB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY;IA+C5C,+EAA+E;IAC/E,OAAO,CAAC,KAAK;IAab;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAiB1B,4DAA4D;IAC5D,OAAO,CAAC,cAAc;IA8BtB,2EAA2E;IAC3E,gBAAgB,IAAI,YAAY;CAiEjC;AAED,eAAe,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mrzTransliteration.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/mrzTransliteration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAyFhE,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACvC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,YAAY,
|
|
1
|
+
{"version":3,"file":"mrzTransliteration.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/mrzTransliteration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAyFhE,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACvC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,YAAY,CAgDd"}
|
|
@@ -48,6 +48,11 @@ declare const _default: {
|
|
|
48
48
|
'diagnosticReport.noticeBody': string;
|
|
49
49
|
'diagnosticReport.continue': string;
|
|
50
50
|
'diagnosticReport.cancel': string;
|
|
51
|
+
'diagnosticReport.shareFailedTitle': string;
|
|
52
|
+
'diagnosticReport.shareFailedBody': string;
|
|
53
|
+
'diagnosticReport.uploadAction': string;
|
|
54
|
+
'diagnosticReport.uploadSuccess': string;
|
|
55
|
+
'diagnosticReport.uploadFailed': string;
|
|
51
56
|
'livenessDetectionScreen.guideHeader': string;
|
|
52
57
|
'livenessDetectionScreen.guideText': string;
|
|
53
58
|
'livenessDetectionScreen.guidePoint1': string;
|
|
@@ -70,6 +75,13 @@ declare const _default: {
|
|
|
70
75
|
'eidScannerScreen.guideHeader': string;
|
|
71
76
|
'eidScannerScreen.guideText': string;
|
|
72
77
|
'eidScannerScreen.invalidMRZFields': string;
|
|
78
|
+
'eidScannerScreen.error': string;
|
|
79
|
+
'eidScannerScreen.errorCode': string;
|
|
80
|
+
'eidScannerScreen.nfcGenericError': string;
|
|
81
|
+
'eidScannerScreen.nfcReadFailed': string;
|
|
82
|
+
'eidScannerScreen.nfcAuthFailed': string;
|
|
83
|
+
'eidScannerScreen.nfcTagLost': string;
|
|
84
|
+
'eidScannerScreen.nfcTimeout': string;
|
|
73
85
|
'eidScannerScreen.faceImageNotFound': string;
|
|
74
86
|
'eidScannerScreen.documentCode': string;
|
|
75
87
|
'eidScannerScreen.nationality': string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../../../../src/Translation/Resources/en.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../../../../src/Translation/Resources/en.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wBAmRE"}
|
|
@@ -48,6 +48,11 @@ declare const _default: {
|
|
|
48
48
|
'diagnosticReport.noticeBody': string;
|
|
49
49
|
'diagnosticReport.continue': string;
|
|
50
50
|
'diagnosticReport.cancel': string;
|
|
51
|
+
'diagnosticReport.shareFailedTitle': string;
|
|
52
|
+
'diagnosticReport.shareFailedBody': string;
|
|
53
|
+
'diagnosticReport.uploadAction': string;
|
|
54
|
+
'diagnosticReport.uploadSuccess': string;
|
|
55
|
+
'diagnosticReport.uploadFailed': string;
|
|
51
56
|
'livenessDetectionScreen.guideHeader': string;
|
|
52
57
|
'livenessDetectionScreen.guideText': string;
|
|
53
58
|
'livenessDetectionScreen.guidePoint1': string;
|
|
@@ -70,6 +75,13 @@ declare const _default: {
|
|
|
70
75
|
'eidScannerScreen.guideHeader': string;
|
|
71
76
|
'eidScannerScreen.guideText': string;
|
|
72
77
|
'eidScannerScreen.invalidMRZFields': string;
|
|
78
|
+
'eidScannerScreen.error': string;
|
|
79
|
+
'eidScannerScreen.errorCode': string;
|
|
80
|
+
'eidScannerScreen.nfcGenericError': string;
|
|
81
|
+
'eidScannerScreen.nfcReadFailed': string;
|
|
82
|
+
'eidScannerScreen.nfcAuthFailed': string;
|
|
83
|
+
'eidScannerScreen.nfcTagLost': string;
|
|
84
|
+
'eidScannerScreen.nfcTimeout': string;
|
|
73
85
|
'eidScannerScreen.faceImageNotFound': string;
|
|
74
86
|
'eidScannerScreen.documentCode': string;
|
|
75
87
|
'eidScannerScreen.nationality': string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tr.d.ts","sourceRoot":"","sources":["../../../../../src/Translation/Resources/tr.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tr.d.ts","sourceRoot":"","sources":["../../../../../src/Translation/Resources/tr.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wBAsRE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "1.
|
|
1
|
+
export declare const SDK_VERSION = "1.488.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -4,12 +4,14 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
4
4
|
import NFCManager from 'react-native-nfc-manager';
|
|
5
5
|
import DeviceInfo from 'react-native-device-info';
|
|
6
6
|
import PermissionManager from '../Libs/permissions.utils';
|
|
7
|
+
import mrzUtils from '../Libs/mrz.utils';
|
|
7
8
|
import { debugError } from '../Libs/debug.utils';
|
|
8
9
|
import { MRZInfo } from '../EIDReader/lds/icao/mrzInfo';
|
|
9
10
|
import { eidReader } from '../EIDReader/eidReader';
|
|
10
11
|
import NativeProgressBar from './NativeProgressBar';
|
|
11
12
|
import type { MRZFields } from '../Types/mrzFields';
|
|
12
13
|
import { buildDocumentName } from '../Libs/mrzTransliteration';
|
|
14
|
+
import type { DocumentName } from '../Types/documentReadResult';
|
|
13
15
|
import { normalizeFromMRZInfo } from '../Libs/documentDataNormalizer';
|
|
14
16
|
import { useTranslation } from 'react-i18next';
|
|
15
17
|
import AppContext from '../Contexts/AppContext';
|
|
@@ -54,13 +56,20 @@ const EIDScanner = ({
|
|
|
54
56
|
const [documentMRZInfo, setDocumentMRZInfo] = React.useState<MRZInfo>();
|
|
55
57
|
const [documentFaceImageMimeType, setDocumentFaceImageMimeType] =
|
|
56
58
|
React.useState<string>();
|
|
57
|
-
const [documentName, setDocumentName] = React.useState<
|
|
59
|
+
const [documentName, setDocumentName] = React.useState<DocumentName>();
|
|
58
60
|
const [progress, setProgress] = React.useState(0);
|
|
59
61
|
const [progressStage, setProgressStage] = React.useState<string>('');
|
|
60
62
|
|
|
61
63
|
// Animation for pulse indicator
|
|
62
64
|
const pulseAnim = useRef(new Animated.Value(1)).current;
|
|
63
65
|
|
|
66
|
+
// Strip MRZ filler (`<`) and trim; returns '' for empty/filler-only input so
|
|
67
|
+
// the UI can hide fields the chip didn't actually provide.
|
|
68
|
+
const cleanField = useCallback((value?: string | null): string => {
|
|
69
|
+
if (!value) return '';
|
|
70
|
+
return value.replace(/</g, ' ').replace(/\s+/g, ' ').trim();
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
64
73
|
// Format date from YYMMDD to DD/MM/YYYY (matching Flutter SDK)
|
|
65
74
|
const formatDate = useCallback((dateStr?: string | null) => {
|
|
66
75
|
if (!dateStr) return '';
|
|
@@ -136,20 +145,30 @@ const EIDScanner = ({
|
|
|
136
145
|
const [voiceGuidanceMessage, setVoiceGuidanceMessage] = useState<string>();
|
|
137
146
|
const [attemptNumber, setAttemptNumber] = useState<number>(0);
|
|
138
147
|
|
|
139
|
-
const getFieldsFromMRZ = useCallback(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
const getFieldsFromMRZ = useCallback(
|
|
149
|
+
(mrz: MRZInfo, name?: DocumentName | null) => {
|
|
150
|
+
// Prefer the resolved name (DG11 printed name / transliteration) over the
|
|
151
|
+
// raw DG1 split. Some chips — notably Turkish PACE passports — return a DG1
|
|
152
|
+
// name field with no `<<` separator, so getPrimaryIdentifier() holds the
|
|
153
|
+
// FULL name and getSecondaryIdentifier() is empty ("name as surname"). The
|
|
154
|
+
// resolved name corrects that; fall back to the raw split when absent.
|
|
155
|
+
const firstName = name?.displayFirst || mrz.getSecondaryIdentifier();
|
|
156
|
+
const lastName = name?.displayLast || mrz.getPrimaryIdentifier();
|
|
157
|
+
return {
|
|
158
|
+
documentCode: mrzUtils.normalizeDocumentCode(mrz.getDocumentCode()),
|
|
159
|
+
personalNumber: mrz.getPersonalNumber() || mrz.getOptionalData1(),
|
|
160
|
+
documentNumber: mrz.getDocumentNumber(),
|
|
161
|
+
firstName,
|
|
162
|
+
lastName,
|
|
163
|
+
birthDate: mrz.getDateOfBirth(),
|
|
164
|
+
expirationDate: mrz.getDateOfExpiry(),
|
|
165
|
+
issuingState: mrz.getIssuingState(),
|
|
166
|
+
sex: mrz.getGender().getStrCode(),
|
|
167
|
+
nationality: mrz.getNationality(),
|
|
168
|
+
} satisfies MRZFields;
|
|
169
|
+
},
|
|
170
|
+
[]
|
|
171
|
+
);
|
|
153
172
|
|
|
154
173
|
const readNFC = useCallback(async () => {
|
|
155
174
|
const startTime = Date.now();
|
|
@@ -267,7 +286,7 @@ const EIDScanner = ({
|
|
|
267
286
|
|
|
268
287
|
if (appContext.skipNfcResultScreen && onScanSuccess) {
|
|
269
288
|
onScanSuccess(
|
|
270
|
-
getFieldsFromMRZ(passportData.mrz),
|
|
289
|
+
getFieldsFromMRZ(passportData.mrz, builtName),
|
|
271
290
|
passportData.faceImage,
|
|
272
291
|
passportData.mimeType
|
|
273
292
|
);
|
|
@@ -348,7 +367,42 @@ const EIDScanner = ({
|
|
|
348
367
|
).catch(() => {});
|
|
349
368
|
|
|
350
369
|
console.debug('NFC scan error:', error);
|
|
351
|
-
|
|
370
|
+
|
|
371
|
+
// Surface an accurate message instead of failing silently. eidReader
|
|
372
|
+
// attaches `nfcCategory` + `nfcCode`.
|
|
373
|
+
// - User-correctable failures (wrong doc data, card moved/too slow, NFC
|
|
374
|
+
// off) get a specific, actionable message and NO code — there's a clear
|
|
375
|
+
// action to take, a support code would just be noise.
|
|
376
|
+
// - Everything else is an unexpected/system error: show a generic message
|
|
377
|
+
// plus the reportable code (e.g. NFC-READ-6A82) so the user can quote it.
|
|
378
|
+
// - user_cancelled stays silent (the user dismissed the native NFC sheet).
|
|
379
|
+
const tagged = error as
|
|
380
|
+
| { nfcCategory?: string; nfcCode?: string }
|
|
381
|
+
| undefined;
|
|
382
|
+
const category = tagged?.nfcCategory ?? errorType;
|
|
383
|
+
|
|
384
|
+
// category -> actionable message key for the user-mistake cases.
|
|
385
|
+
const ACTIONABLE: Record<string, string> = {
|
|
386
|
+
auth_failed: 'eidScannerScreen.nfcAuthFailed',
|
|
387
|
+
tag_lost: 'eidScannerScreen.nfcTagLost',
|
|
388
|
+
timeout: 'eidScannerScreen.nfcTimeout',
|
|
389
|
+
not_enabled: 'eidScannerScreen.nfcNotEnabled',
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
if (category !== 'user_cancelled') {
|
|
393
|
+
const actionableKey = ACTIONABLE[category];
|
|
394
|
+
if (actionableKey) {
|
|
395
|
+
// Clear user action available — meaningful message, no support code.
|
|
396
|
+
Alert.alert(t('eidScannerScreen.error'), t(actionableKey));
|
|
397
|
+
} else {
|
|
398
|
+
// Unexpected/system error — generic message + reportable support code.
|
|
399
|
+
const errorCode = tagged?.nfcCode ?? 'NFC-READ';
|
|
400
|
+
const message = `${t('eidScannerScreen.nfcGenericError')}\n\n${t(
|
|
401
|
+
'eidScannerScreen.errorCode'
|
|
402
|
+
)}: ${errorCode}`;
|
|
403
|
+
Alert.alert(t('eidScannerScreen.error'), message);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
352
406
|
} finally {
|
|
353
407
|
setIsScanning(false);
|
|
354
408
|
setProgress(0);
|
|
@@ -566,59 +620,86 @@ const EIDScanner = ({
|
|
|
566
620
|
</View>
|
|
567
621
|
</View>
|
|
568
622
|
|
|
569
|
-
{/* Right column: all fields as grid
|
|
623
|
+
{/* Right column: all fields as grid. Each field renders only
|
|
624
|
+
when the chip actually provided a value — filler-only /
|
|
625
|
+
empty fields are hidden rather than shown blank. */}
|
|
570
626
|
<View style={styles.idCardFields}>
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
label={t('eidScannerScreen.expirationDate')}
|
|
589
|
-
value={formatDate(documentMRZInfo.getDateOfExpiry())}
|
|
590
|
-
/>
|
|
591
|
-
<IDCardField
|
|
592
|
-
label={t('eidScannerScreen.gender')}
|
|
593
|
-
value={formatGender(
|
|
627
|
+
{(() => {
|
|
628
|
+
const surname =
|
|
629
|
+
documentName?.displayLast ??
|
|
630
|
+
cleanField(documentMRZInfo.getPrimaryIdentifier());
|
|
631
|
+
const givenNames =
|
|
632
|
+
documentName?.displayFirst ??
|
|
633
|
+
cleanField(documentMRZInfo.getSecondaryIdentifier());
|
|
634
|
+
const docNumber = cleanField(
|
|
635
|
+
documentMRZInfo.getDocumentNumber()
|
|
636
|
+
);
|
|
637
|
+
const birthDate = formatDate(
|
|
638
|
+
documentMRZInfo.getDateOfBirth()
|
|
639
|
+
);
|
|
640
|
+
const expiry = formatDate(
|
|
641
|
+
documentMRZInfo.getDateOfExpiry()
|
|
642
|
+
);
|
|
643
|
+
const gender = formatGender(
|
|
594
644
|
documentMRZInfo.getGender().getStrCode()
|
|
595
|
-
)
|
|
596
|
-
|
|
597
|
-
<IDCardField
|
|
598
|
-
label={t('eidScannerScreen.nationality')}
|
|
599
|
-
value={formatNationality(
|
|
645
|
+
);
|
|
646
|
+
const nationality = formatNationality(
|
|
600
647
|
documentMRZInfo.getNationality()
|
|
601
|
-
)
|
|
602
|
-
|
|
603
|
-
<IDCardField
|
|
604
|
-
label={t('eidScannerScreen.issuingState')}
|
|
605
|
-
value={formatNationality(
|
|
648
|
+
);
|
|
649
|
+
const issuingState = formatNationality(
|
|
606
650
|
documentMRZInfo.getIssuingState()
|
|
607
|
-
)
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
<
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
651
|
+
);
|
|
652
|
+
const personalNumber = cleanField(
|
|
653
|
+
documentMRZInfo.getPersonalNumber() ||
|
|
654
|
+
documentMRZInfo.getOptionalData1()
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
const fields: Array<{ label: string; value: string }> = [
|
|
658
|
+
{
|
|
659
|
+
label: t('eidScannerScreen.surname'),
|
|
660
|
+
value: surname,
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
label: t('eidScannerScreen.name'),
|
|
664
|
+
value: givenNames,
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
label: t('eidScannerScreen.documentNumber'),
|
|
668
|
+
value: docNumber,
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
label: t('eidScannerScreen.birthDate'),
|
|
672
|
+
value: birthDate,
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
label: t('eidScannerScreen.expirationDate'),
|
|
676
|
+
value: expiry,
|
|
677
|
+
},
|
|
678
|
+
{ label: t('eidScannerScreen.gender'), value: gender },
|
|
679
|
+
{
|
|
680
|
+
label: t('eidScannerScreen.nationality'),
|
|
681
|
+
value: nationality,
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
label: t('eidScannerScreen.issuingState'),
|
|
685
|
+
value: issuingState,
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
label: t('eidScannerScreen.personalNumber'),
|
|
689
|
+
value: personalNumber,
|
|
690
|
+
},
|
|
691
|
+
];
|
|
692
|
+
|
|
693
|
+
return fields
|
|
694
|
+
.filter((f) => f.value && f.value.trim().length > 0)
|
|
695
|
+
.map((f) => (
|
|
696
|
+
<IDCardField
|
|
697
|
+
key={f.label}
|
|
698
|
+
label={f.label}
|
|
699
|
+
value={f.value}
|
|
700
|
+
/>
|
|
701
|
+
));
|
|
702
|
+
})()}
|
|
622
703
|
</View>
|
|
623
704
|
</View>
|
|
624
705
|
</View>
|
|
@@ -636,7 +717,7 @@ const EIDScanner = ({
|
|
|
636
717
|
documentFaceImageMimeType
|
|
637
718
|
) {
|
|
638
719
|
onScanSuccess(
|
|
639
|
-
getFieldsFromMRZ(documentMRZInfo),
|
|
720
|
+
getFieldsFromMRZ(documentMRZInfo, documentName),
|
|
640
721
|
documentFaceImage,
|
|
641
722
|
documentFaceImageMimeType
|
|
642
723
|
);
|
|
@@ -723,7 +804,7 @@ const EIDScanner = ({
|
|
|
723
804
|
documentFaceImageMimeType
|
|
724
805
|
) {
|
|
725
806
|
onScanSuccess(
|
|
726
|
-
getFieldsFromMRZ(documentMRZInfo),
|
|
807
|
+
getFieldsFromMRZ(documentMRZInfo, documentName),
|
|
727
808
|
documentFaceImage,
|
|
728
809
|
documentFaceImageMimeType
|
|
729
810
|
);
|
|
@@ -17,7 +17,15 @@ export const REQUIRED_CONSISTENT_DOCTYPE_DETECTIONS = 3;
|
|
|
17
17
|
export const SIGNATURE_REGEX = /s[gi]g?n[au]?t[u]?r|imz[a]s?/i;
|
|
18
18
|
export const SIGNATURE_TEXT_REGEX = /signature|imza|İmza/i;
|
|
19
19
|
export const MRZ_BLOCK_PATTERN = /[A-Z0-9<]{8,}.*</i;
|
|
20
|
-
|
|
20
|
+
// Matches the line-1 start of ANY ICAO TD3 passport MRZ, so the camera routes
|
|
21
|
+
// every passport variant into the passport flow (not the ID-card back-side
|
|
22
|
+
// flow). Per ICAO 9303 Part 4: `P` + a type char (filler `<` or a subtype
|
|
23
|
+
// letter — `P<`, `PP` German, `PD`/`PS`/`PO` diplomatic/service/official) +
|
|
24
|
+
// the issuing state (3 letters, OR the German 1-letter `D` padded with filler,
|
|
25
|
+
// e.g. `P<D<<` / `PPD<<`). Previously only `P<[A-Z]{3}` matched, so German `PP`
|
|
26
|
+
// and 1-letter-issuer passports fell through to the ID-card flow and were
|
|
27
|
+
// wrongly asked for a back side.
|
|
28
|
+
export const PASSPORT_MRZ_PATTERN = /P[A-Z<](?:[A-Z]{3}|[A-Z]<<)[A-Z<]*<</;
|
|
21
29
|
|
|
22
30
|
// BDDK Madde 7 - Security Feature Validation
|
|
23
31
|
// When NFC chip reading unavailable, must verify at least 4 visual security features
|
|
@@ -4,6 +4,10 @@ import type { FileSystemStructured } from './smartcards/fileSystemStructured';
|
|
|
4
4
|
import { Buffer } from 'buffer';
|
|
5
5
|
|
|
6
6
|
export class CardFileInputStream extends InputStream {
|
|
7
|
+
/** Max re-issues of a single block read before failing — mitigates transient
|
|
8
|
+
* iOS NFC transceive drops during large-file reads (e.g. DG2). */
|
|
9
|
+
private static readonly MAX_BLOCK_READ_RETRIES = 5;
|
|
10
|
+
|
|
7
11
|
private path!: FileInfo[];
|
|
8
12
|
private buffer!: Buffer;
|
|
9
13
|
private bufferLength!: number;
|
|
@@ -69,12 +73,32 @@ export class CardFileInputStream extends InputStream {
|
|
|
69
73
|
newOffsetBufferInFile = this.offsetBufferInFile + this.bufferLength;
|
|
70
74
|
let newOffsetInBuffer = 0;
|
|
71
75
|
let newBufferLength = 0;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
// Retry a failed block read. The iOS NFC stack (react-native-nfc-manager)
|
|
77
|
+
// throws transient "READ BINARY" transceive errors during the many
|
|
78
|
+
// block reads of a large file like DG2 (face image); a single drop
|
|
79
|
+
// previously aborted the whole read with "Could not read file". Re-issue
|
|
80
|
+
// the SAME block (offset unchanged) a few times before giving up — this
|
|
81
|
+
// is idempotent (no secure-messaging state advances on a failed read).
|
|
82
|
+
let attempt = 0;
|
|
83
|
+
for (;;) {
|
|
84
|
+
try {
|
|
85
|
+
newBufferLength = 0;
|
|
86
|
+
while (newBufferLength === 0) {
|
|
87
|
+
newBufferLength = await this.fillBufferFromFile(
|
|
88
|
+
this.path,
|
|
89
|
+
newOffsetBufferInFile,
|
|
90
|
+
le
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
} catch (blockError) {
|
|
95
|
+
if (++attempt >= CardFileInputStream.MAX_BLOCK_READ_RETRIES) {
|
|
96
|
+
throw blockError;
|
|
97
|
+
}
|
|
98
|
+
// Brief backoff: an immediate re-issue after a transient NFC drop
|
|
99
|
+
// usually fails again; a short pause lets the RF field re-stabilise.
|
|
100
|
+
await new Promise((r) => setTimeout(r, 80 * attempt));
|
|
101
|
+
}
|
|
78
102
|
}
|
|
79
103
|
|
|
80
104
|
this.offsetBufferInFile = newOffsetBufferInFile;
|
|
@@ -6,10 +6,12 @@ import { FileInfo } from './fileInfo';
|
|
|
6
6
|
import { ISO7816_SW } from './smartcards/iso7816';
|
|
7
7
|
import { SecureMessagingWrapper } from './secureMessagingWrapper';
|
|
8
8
|
import { TripleDesSecureMessagingWrapper } from './tripleDesSecureMessagingWrapper';
|
|
9
|
+
import { AESSecureMessagingWrapper } from './aesSecureMessagingWrapper';
|
|
9
10
|
import type { APDUWrapper } from './smartcards/apduWrapper';
|
|
10
11
|
import { TLVInputStream } from './tlv/tlvInputStream';
|
|
11
12
|
import { CVCAFile } from './lds/cvcaFile';
|
|
12
13
|
import { Buffer } from 'buffer';
|
|
14
|
+
import { Platform } from 'react-native';
|
|
13
15
|
import type { FileSystemStructured } from './smartcards/fileSystemStructured';
|
|
14
16
|
|
|
15
17
|
export class DefaultFileSystem implements FileSystemStructured {
|
|
@@ -37,7 +39,37 @@ export class DefaultFileSystem implements FileSystemStructured {
|
|
|
37
39
|
this.isSelected = false;
|
|
38
40
|
this.isSFIEnabled = isSFIEnabled;
|
|
39
41
|
this.fidToSFI = fidToSFI;
|
|
40
|
-
|
|
42
|
+
// iOS CoreNFC (via react-native-nfc-manager's sendCommandAPDUIOS) does not
|
|
43
|
+
// accept the EXTENDED-length APDU byte form this code emits when ne > 256
|
|
44
|
+
// (a 7-byte "00 XX XX" Le). Such a READ BINARY is rejected outright, so on
|
|
45
|
+
// iOS EVERY DG2 read failed ("Exception during READ BINARY") even though
|
|
46
|
+
// PACE — which only used short Le=256 — succeeded. Start at a short-form
|
|
47
|
+
// length on iOS (ne <= 256) so every READ BINARY stays in the short APDU
|
|
48
|
+
// form. Android's transceive() handles extended APDUs, so keep extended
|
|
49
|
+
// there for speed. JMRTD/NFCPassportReader likewise read in small blocks.
|
|
50
|
+
this.maxReadBinaryLength =
|
|
51
|
+
Platform.OS === 'ios'
|
|
52
|
+
? EID_CONSTANTS.DEFAULT_MAX_BLOCKSIZE // 223 → short-form Le, SM-safe
|
|
53
|
+
: EID_CONSTANTS.EXTENDED_MAX_TRANSCEIVE_LENGTH;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Deep-copy a secure-messaging wrapper PRESERVING its cipher type (AES vs
|
|
57
|
+
* 3DES), so the SSC can be rewound for a retry without changing the MAC/enc
|
|
58
|
+
* algorithm. Non-SM wrappers are returned as-is. */
|
|
59
|
+
private cloneWrapper(wrapper: APDUWrapper): APDUWrapper {
|
|
60
|
+
if (!(wrapper instanceof SecureMessagingWrapper)) {
|
|
61
|
+
return wrapper;
|
|
62
|
+
}
|
|
63
|
+
const args: [string, string, number, boolean, bigint] = [
|
|
64
|
+
wrapper.getEncryptionKey(),
|
|
65
|
+
wrapper.getMACKey(),
|
|
66
|
+
wrapper.getMaxTransceiveLength(),
|
|
67
|
+
wrapper.getShouldCheckMAC(),
|
|
68
|
+
wrapper.getSendSequenceCounter(),
|
|
69
|
+
];
|
|
70
|
+
return wrapper.getType() === 'AES'
|
|
71
|
+
? new AESSecureMessagingWrapper(...args)
|
|
72
|
+
: new TripleDesSecureMessagingWrapper(...args);
|
|
41
73
|
}
|
|
42
74
|
|
|
43
75
|
public setWrapper(wrapper: APDUWrapper): void {
|
|
@@ -131,19 +163,49 @@ export class DefaultFileSystem implements FileSystemStructured {
|
|
|
131
163
|
|
|
132
164
|
return result;
|
|
133
165
|
} catch (error) {
|
|
134
|
-
|
|
166
|
+
// Only APDU-level errors expose getSW(); a transient native NFC transceive
|
|
167
|
+
// error does NOT, so calling it unguarded threw a TypeError and masked the
|
|
168
|
+
// real failure. Guard it before testing for the WRONG_LENGTH downgrade.
|
|
169
|
+
const sw =
|
|
170
|
+
typeof (error as { getSW?: () => number }).getSW === 'function'
|
|
171
|
+
? (error as { getSW: () => number }).getSW()
|
|
172
|
+
: undefined;
|
|
173
|
+
const isWrongLength =
|
|
174
|
+
sw != null &&
|
|
175
|
+
(sw & ISO7816_SW.WRONG_LENGTH) === ISO7816_SW.WRONG_LENGTH;
|
|
176
|
+
|
|
177
|
+
// Downgrade the read size and signal a retry (empty result) when EITHER:
|
|
178
|
+
// - the chip returned 6Cxx WRONG_LENGTH (the standard JMRTD path), OR
|
|
179
|
+
// - the read failed transiently with NO status word while we were still
|
|
180
|
+
// at extended length. iOS CoreNFC (via react-native-nfc-manager) drops
|
|
181
|
+
// the connection on too-large extended-length READ BINARY on some chips
|
|
182
|
+
// (e.g. German passport DG2) instead of returning 6Cxx, so the chip
|
|
183
|
+
// never gets to ask for a smaller length. Dropping to the conservative
|
|
184
|
+
// 223-byte block makes the next read succeed. Reference readers
|
|
185
|
+
// (JMRTD, NFCPassportReader) read large files in small blocks (~0xA0).
|
|
186
|
+
// Restore the pre-send secure-messaging wrapper. A failed wrapped READ
|
|
187
|
+
// BINARY still advanced the send-sequence-counter, so a retry MUST reset
|
|
188
|
+
// it or every subsequent read fails the MAC. (This is why the read
|
|
189
|
+
// previously stalled partway through DG2: each retry reused a desynced
|
|
190
|
+
// SSC.) JMRTD does the same reset on its downgrade path.
|
|
191
|
+
this.wrapper = this.oldWrapper;
|
|
192
|
+
|
|
135
193
|
if (
|
|
136
|
-
(sw
|
|
194
|
+
(isWrongLength || sw == null) &&
|
|
137
195
|
this.maxReadBinaryLength > EID_CONSTANTS.DEFAULT_MAX_BLOCKSIZE
|
|
138
196
|
) {
|
|
139
|
-
this.wrapper = this.oldWrapper;
|
|
140
197
|
this.maxReadBinaryLength = EID_CONSTANTS.DEFAULT_MAX_BLOCKSIZE;
|
|
141
198
|
return new Uint8Array(0);
|
|
142
199
|
}
|
|
143
200
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
201
|
+
// Preserve the original error (a transient transceive failure at an
|
|
202
|
+
// already-small block size) so the retry layer above can recognise and
|
|
203
|
+
// re-issue it, instead of flattening every cause into one opaque string.
|
|
204
|
+
throw error instanceof Error
|
|
205
|
+
? error
|
|
206
|
+
: new Error(
|
|
207
|
+
`Read binary failed on file ${fileInfo == null ? this.selectedFID.toString(16) : fileInfo}`
|
|
208
|
+
);
|
|
147
209
|
}
|
|
148
210
|
}
|
|
149
211
|
|
|
@@ -216,16 +278,12 @@ export class DefaultFileSystem implements FileSystemStructured {
|
|
|
216
278
|
le: number,
|
|
217
279
|
isTLVEncodedOffsetNeeded: boolean
|
|
218
280
|
) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
this.wrapper.getShouldCheckMAC(),
|
|
226
|
-
this.wrapper.getSendSequenceCounter()
|
|
227
|
-
)
|
|
228
|
-
: this.wrapper;
|
|
281
|
+
// Snapshot the wrapper BEFORE the send so a failed read can rewind the SSC.
|
|
282
|
+
// The copy MUST preserve the actual wrapper type — PACE sessions are AES
|
|
283
|
+
// (the German passport uses AES-CMAC). Previously this always built a 3DES
|
|
284
|
+
// wrapper, so an AES session's retry used a 3DES wrapper with AES keys and
|
|
285
|
+
// every subsequent read failed the MAC — the cause of the DG2 stall.
|
|
286
|
+
this.oldWrapper = this.cloneWrapper(this.wrapper);
|
|
229
287
|
return this.service.sendReadBinary(
|
|
230
288
|
this.wrapper,
|
|
231
289
|
DefaultFileSystem.NO_SFI,
|