@trustchex/react-native-sdk 1.488.0 → 1.490.1
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/ios/ImageDecoder/ImageDecoderModule.m +12 -0
- package/ios/ImageDecoder/ImageDecoderModule.swift +43 -0
- package/lib/module/Screens/Static/ResultScreen.js +1 -0
- package/lib/module/Shared/Components/DiagnosticReportButton.js +16 -14
- package/lib/module/Shared/Components/EIDScanner.js +5 -1
- package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +22 -2
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +1 -1
- package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +7 -7
- package/lib/module/Shared/EIDReader/eidReader.js +15 -3
- package/lib/module/Shared/Libs/diagnosticAuth.js +36 -0
- package/lib/module/Shared/Libs/jp2Decode.js +43 -0
- package/lib/module/Shared/Libs/sendDiagnosticReport.js +83 -103
- package/lib/module/Translation/Resources/en.js +6 -7
- package/lib/module/Translation/Resources/tr.js +6 -7
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/DiagnosticReportButton.d.ts +9 -6
- package/lib/typescript/src/Shared/Components/DiagnosticReportButton.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +11 -0
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/diagnosticAuth.d.ts +8 -0
- package/lib/typescript/src/Shared/Libs/diagnosticAuth.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/jp2Decode.d.ts +13 -0
- package/lib/typescript/src/Shared/Libs/jp2Decode.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/sendDiagnosticReport.d.ts +26 -10
- package/lib/typescript/src/Shared/Libs/sendDiagnosticReport.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +4 -5
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +4 -5
- 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 -5
- package/src/Screens/Static/ResultScreen.tsx +1 -0
- package/src/Shared/Components/DiagnosticReportButton.tsx +23 -14
- package/src/Shared/Components/EIDScanner.tsx +5 -1
- package/src/Shared/Components/IdentityDocumentCamera.flows.ts +22 -2
- package/src/Shared/Components/IdentityDocumentCamera.tsx +1 -2
- package/src/Shared/Components/IdentityDocumentCamera.utils.ts +6 -8
- package/src/Shared/EIDReader/eidReader.ts +19 -4
- package/src/Shared/Libs/diagnosticAuth.ts +47 -0
- package/src/Shared/Libs/jp2Decode.ts +48 -0
- package/src/Shared/Libs/sendDiagnosticReport.ts +91 -118
- package/src/Translation/Resources/en.ts +6 -9
- package/src/Translation/Resources/tr.ts +6 -9
- package/src/version.ts +1 -1
|
@@ -2,18 +2,21 @@ import React from 'react';
|
|
|
2
2
|
import { type DiagnosticImage } from '../Libs/sendDiagnosticReport';
|
|
3
3
|
import type { ScanDataForReport } from '../Libs/diagnosticReport';
|
|
4
4
|
export interface DiagnosticReportButtonProps {
|
|
5
|
-
|
|
5
|
+
/** Backend base URL the SDK was initialised with. */
|
|
6
|
+
baseUrl: string;
|
|
6
7
|
sessionId?: string;
|
|
8
|
+
scan: ScanDataForReport;
|
|
7
9
|
images?: DiagnosticImage[];
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* "Report a scanning issue" button for the result screen.
|
|
11
13
|
*
|
|
12
|
-
* Shows a brief notice describing what will be shared (
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Shows a brief notice describing what will be shared (acting as the user's
|
|
15
|
+
* consent step), then uploads the diagnostic bundle (technical signals +
|
|
16
|
+
* scanned data + captured images) to the backend, encrypted in transit and at
|
|
17
|
+
* rest. Operators view and download the reports from the dashboard.
|
|
18
|
+
*
|
|
19
|
+
* Hidden when there's no session/baseUrl to upload to (e.g. before init).
|
|
17
20
|
*/
|
|
18
21
|
declare const DiagnosticReportButton: React.FC<DiagnosticReportButtonProps>;
|
|
19
22
|
export default DiagnosticReportButton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiagnosticReportButton.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/DiagnosticReportButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,OAAO,
|
|
1
|
+
{"version":3,"file":"DiagnosticReportButton.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/DiagnosticReportButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,MAAM,WAAW,2BAA2B;IAC1C,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,QAAA,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAsDjE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EIDScanner.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/EIDScanner.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiBpD,UAAU,eAAe;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,SAAS,EAClB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,KACtB,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAED,QAAA,MAAM,UAAU,GAAI,6FAOjB,eAAe,
|
|
1
|
+
{"version":3,"file":"EIDScanner.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/EIDScanner.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiBpD,UAAU,eAAe;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,SAAS,EAClB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,KACtB,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAED,QAAA,MAAM,UAAU,GAAI,6FAOjB,eAAe,4CAywBjB,CAAC;AA4NF,eAAe,UAAU,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentCamera.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.tsx"],"names":[],"mappings":"AAyEA,OAAO,KAAK,EACV,mBAAmB,EACnB,SAAS,EACT,2BAA2B,EAK5B,MAAM,gCAAgC,CAAC;AAGxC,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,2BAA2B,EAAE,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAMnE,QAAA,MAAM,sBAAsB,GAAI,uDAI7B,2BAA2B,
|
|
1
|
+
{"version":3,"file":"IdentityDocumentCamera.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.tsx"],"names":[],"mappings":"AAyEA,OAAO,KAAK,EACV,mBAAmB,EACnB,SAAS,EACT,2BAA2B,EAK5B,MAAM,gCAAgC,CAAC;AAGxC,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,2BAA2B,EAAE,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAMnE,QAAA,MAAM,sBAAsB,GAAI,uDAI7B,2BAA2B,4CAmjF7B,CAAC;AAiIF,eAAe,sBAAsB,CAAC"}
|
|
@@ -83,6 +83,17 @@ export declare function handleIDBackFlow(mrzText: string | null, mrzFields: MRZF
|
|
|
83
83
|
*
|
|
84
84
|
* PASSPORT: → COMPLETED (no back side)
|
|
85
85
|
* ID CARD: → SCAN_ID_BACK
|
|
86
|
+
*
|
|
87
|
+
* Routing is PASSPORT-BIASED on purpose: a passport has no back side, so if we
|
|
88
|
+
* route it to SCAN_ID_BACK it deadlocks forever waiting for a back that will
|
|
89
|
+
* never appear. We therefore only go to SCAN_ID_BACK when there is POSITIVE
|
|
90
|
+
* evidence the document is an ID card (a parsed MRZ document code that is
|
|
91
|
+
* present and not 'P'). When the type is ambiguous — e.g. the passport MRZ was
|
|
92
|
+
* never read as 'P' so the front step locked `detectedDocumentType` as
|
|
93
|
+
* 'ID_FRONT' (the torch/tilt during hologram capture makes the MRZ unreadable),
|
|
94
|
+
* or no MRZ code survived at all — we COMPLETE rather than wait for a
|
|
95
|
+
* non-existent back side. A two-sided ID card always yields an 'I'/'A'/'C'
|
|
96
|
+
* (non-'P') MRZ code, so genuine ID cards still route to SCAN_ID_BACK.
|
|
86
97
|
*/
|
|
87
98
|
export declare function getNextStepAfterHologram(detectedDocumentType: 'ID_FRONT' | 'ID_BACK' | 'PASSPORT' | 'UNKNOWN', currentFrameDocType: 'ID_FRONT' | 'ID_BACK' | 'PASSPORT' | 'UNKNOWN', mrzDocCode: string | undefined): 'COMPLETED' | 'SCAN_ID_BACK';
|
|
88
99
|
//# sourceMappingURL=IdentityDocumentCamera.flows.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentCamera.flows.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.flows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAUpD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EACP,mBAAmB,GACnB,cAAc,GACd,qBAAqB,GACrB,sBAAsB,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EACP,mBAAmB,GACnB,oBAAoB,GACpB,qBAAqB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,GAAG,kBAAkB,GAAG,sBAAsB,CAAC;CAC3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,iBAAiB,EAAE,OAAO,EAC1B,WAAW,EAAE,OAAO,EACpB,iBAAiB,EAAE,OAAO,EAC1B,YAAY,EAAE,OAAO,GACpB,kBAAkB,CAgEpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,UAAU,EAAE,MAAM,GACjB,iBAAiB,CA0EnB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,QAAQ,EAAE,OAAO,EACjB,iBAAiB,EAAE,OAAO,EAC1B,iBAAiB,EAAE,OAAO,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,WAAW,EAAE,OAAO,GACnB,gBAAgB,CA2DlB;AAED
|
|
1
|
+
{"version":3,"file":"IdentityDocumentCamera.flows.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.flows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAUpD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EACP,mBAAmB,GACnB,cAAc,GACd,qBAAqB,GACrB,sBAAsB,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EACP,mBAAmB,GACnB,oBAAoB,GACpB,qBAAqB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,GAAG,kBAAkB,GAAG,sBAAsB,CAAC;CAC3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,iBAAiB,EAAE,OAAO,EAC1B,WAAW,EAAE,OAAO,EACpB,iBAAiB,EAAE,OAAO,EAC1B,YAAY,EAAE,OAAO,GACpB,kBAAkB,CAgEpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,UAAU,EAAE,MAAM,GACjB,iBAAiB,CA0EnB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,QAAQ,EAAE,OAAO,EACjB,iBAAiB,EAAE,OAAO,EAC1B,iBAAiB,EAAE,OAAO,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,WAAW,EAAE,OAAO,GACnB,gBAAgB,CA2DlB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,oBAAoB,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,EACrE,mBAAmB,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,EACpE,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,WAAW,GAAG,cAAc,CAqB9B"}
|
|
@@ -42,7 +42,7 @@ export declare function transformBoundsToScreen(bounds: {
|
|
|
42
42
|
* Unified status message logic used by both voice guidance and render text.
|
|
43
43
|
* Returns the appropriate i18n key arguments for the current scan state.
|
|
44
44
|
*/
|
|
45
|
-
export declare function getStatusMessage(nextStep: ScanStep, status: ScanStatus, detectedDocumentType: DocumentType, isBrightnessLow: boolean, isFrameBlurry: boolean, allElementsDetected: boolean, elementsOutsideScanArea: string[], t: (key: string, params?: Record<string, unknown>) => string
|
|
45
|
+
export declare function getStatusMessage(nextStep: ScanStep, status: ScanStatus, detectedDocumentType: DocumentType, isBrightnessLow: boolean, isFrameBlurry: boolean, allElementsDetected: boolean, elementsOutsideScanArea: string[], t: (key: string, params?: Record<string, unknown>) => string): string;
|
|
46
46
|
/**
|
|
47
47
|
* Calculate angle from two points in degrees
|
|
48
48
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentCamera.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,IAAI,EACL,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAOpD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG7E;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM;;;;;EAmBpB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;;;;;sBAW9C,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM;EAIjE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC/D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM;;;;;EAQhB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,UAAU,EAClB,oBAAoB,EAAE,YAAY,EAClC,eAAe,EAAE,OAAO,EACxB,aAAa,EAAE,OAAO,EACtB,mBAAmB,EAAE,OAAO,EAC5B,uBAAuB,EAAE,MAAM,EAAE,EACjC,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,
|
|
1
|
+
{"version":3,"file":"IdentityDocumentCamera.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eidReader.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/EIDReader/eidReader.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"eidReader.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/EIDReader/eidReader.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAyY7C,QAAA,MAAM,SAAS,GACb,gBAAgB,MAAM,EACtB,aAAa,MAAM,EACnB,cAAc,MAAM,EACpB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,KAC5C,OAAO,CACN;IACE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GACD,SAAS,CA+XZ,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface DiagnosticSignature {
|
|
2
|
+
timestamp: string;
|
|
3
|
+
nonce: string;
|
|
4
|
+
signature: string;
|
|
5
|
+
}
|
|
6
|
+
/** Sign a raw JSON body for the demo-diagnostics endpoint. */
|
|
7
|
+
export declare const signDiagnosticBody: (rawBody: string) => DiagnosticSignature;
|
|
8
|
+
//# sourceMappingURL=diagnosticAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnosticAuth.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/diagnosticAuth.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,mBAapD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
/**
|
|
3
|
+
* Decode a JPEG2000 buffer to JPEG using the native iOS decoder.
|
|
4
|
+
*
|
|
5
|
+
* Returns the JPEG bytes + mime type on success, or null when native decode is
|
|
6
|
+
* unavailable (Android, or the module isn't linked) or fails — callers should
|
|
7
|
+
* fall back to their existing behaviour (keep raw JP2).
|
|
8
|
+
*/
|
|
9
|
+
export declare function decodeJp2ToJpeg(jp2Buffer: Buffer): Promise<{
|
|
10
|
+
base64: string;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
} | null>;
|
|
13
|
+
//# sourceMappingURL=jp2Decode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jp2Decode.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/jp2Decode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAsBhC;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAetD"}
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { type ScanDataForReport } from './diagnosticReport';
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Assembles and uploads the support diagnostic report to the backend.
|
|
3
|
+
*
|
|
4
|
+
* This runs from the SDK's DEMO flow only, which is simulated client-side and
|
|
5
|
+
* has no real verification session or account — so there's no session key to
|
|
6
|
+
* encrypt with and nothing to authenticate against. The report is POSTed
|
|
7
|
+
* unauthenticated to the global demo-diagnostics endpoint over HTTPS (encrypted
|
|
8
|
+
* in transit); the backend encrypts the PII fields at rest. Internal developers
|
|
9
|
+
* view and download the reports from a hidden dashboard page.
|
|
10
|
+
*
|
|
11
|
+
* Uploaded payload (one JSON body):
|
|
12
|
+
* - non-PII technical metadata (platform, sdkVersion, documentType,
|
|
13
|
+
* nfcErrorCode, paceFallbackReason, succeeded) for the list/filter,
|
|
14
|
+
* - `diagnosticsJson` — technical signals (device, camera, MRZ, NFC steps),
|
|
15
|
+
* - `scanDataJson` — the scanned identity data (PII),
|
|
16
|
+
* - `images` — the captured document/face images (base64, PII).
|
|
5
17
|
*/
|
|
6
|
-
|
|
18
|
+
import 'react-native-get-random-values';
|
|
19
|
+
import { type ScanDataForReport } from './diagnosticReport';
|
|
7
20
|
export interface DiagnosticImage {
|
|
8
21
|
/** Stable file name without extension, e.g. "mrz-side". */
|
|
9
22
|
name: string;
|
|
@@ -11,20 +24,23 @@ export interface DiagnosticImage {
|
|
|
11
24
|
mime: 'jpg' | 'png';
|
|
12
25
|
}
|
|
13
26
|
export interface SendDiagnosticParams {
|
|
27
|
+
/** Backend base URL (same value the SDK was initialised with). */
|
|
28
|
+
baseUrl: string;
|
|
29
|
+
/** Demo session id (informational; the endpoint is unauthenticated). */
|
|
30
|
+
sessionId?: string;
|
|
14
31
|
scan: ScanDataForReport;
|
|
15
32
|
sdkVersion: string;
|
|
16
|
-
sessionId?: string;
|
|
17
33
|
/** base64 images to attach (MRZ side / front / face / NFC chip face). */
|
|
18
34
|
images?: DiagnosticImage[];
|
|
19
35
|
}
|
|
20
36
|
export interface SendResult {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
dismissed?: boolean;
|
|
37
|
+
/** True when the report was uploaded and stored. */
|
|
38
|
+
uploaded: boolean;
|
|
24
39
|
}
|
|
25
40
|
/**
|
|
26
|
-
* Build the report
|
|
27
|
-
* {
|
|
41
|
+
* Build the report and upload it (over HTTPS) to the demo-diagnostics endpoint.
|
|
42
|
+
* Returns { uploaded } — false on any error (best-effort; a failed report must
|
|
43
|
+
* never disrupt the user's flow).
|
|
28
44
|
*/
|
|
29
45
|
export declare const sendDiagnosticReport: (params: SendDiagnosticParams) => Promise<SendResult>;
|
|
30
46
|
//# sourceMappingURL=sendDiagnosticReport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sendDiagnosticReport.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/sendDiagnosticReport.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sendDiagnosticReport.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/sendDiagnosticReport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,gCAAgC,CAAC;AAGxC,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAKD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,oBAAoB,KAC3B,OAAO,CAAC,UAAU,CA6EpB,CAAC"}
|
|
@@ -48,11 +48,10 @@ declare const _default: {
|
|
|
48
48
|
'diagnosticReport.noticeBody': string;
|
|
49
49
|
'diagnosticReport.continue': string;
|
|
50
50
|
'diagnosticReport.cancel': string;
|
|
51
|
-
'diagnosticReport.
|
|
52
|
-
'diagnosticReport.
|
|
53
|
-
'diagnosticReport.
|
|
54
|
-
'diagnosticReport.
|
|
55
|
-
'diagnosticReport.uploadFailed': string;
|
|
51
|
+
'diagnosticReport.sentTitle': string;
|
|
52
|
+
'diagnosticReport.sentBody': string;
|
|
53
|
+
'diagnosticReport.failedTitle': string;
|
|
54
|
+
'diagnosticReport.failedBody': string;
|
|
56
55
|
'livenessDetectionScreen.guideHeader': string;
|
|
57
56
|
'livenessDetectionScreen.guideText': string;
|
|
58
57
|
'livenessDetectionScreen.guidePoint1': 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,wBAgRE"}
|
|
@@ -48,11 +48,10 @@ declare const _default: {
|
|
|
48
48
|
'diagnosticReport.noticeBody': string;
|
|
49
49
|
'diagnosticReport.continue': string;
|
|
50
50
|
'diagnosticReport.cancel': string;
|
|
51
|
-
'diagnosticReport.
|
|
52
|
-
'diagnosticReport.
|
|
53
|
-
'diagnosticReport.
|
|
54
|
-
'diagnosticReport.
|
|
55
|
-
'diagnosticReport.uploadFailed': string;
|
|
51
|
+
'diagnosticReport.sentTitle': string;
|
|
52
|
+
'diagnosticReport.sentBody': string;
|
|
53
|
+
'diagnosticReport.failedTitle': string;
|
|
54
|
+
'diagnosticReport.failedBody': string;
|
|
56
55
|
'livenessDetectionScreen.guideHeader': string;
|
|
57
56
|
'livenessDetectionScreen.guideText': string;
|
|
58
57
|
'livenessDetectionScreen.guidePoint1': 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,wBAmRE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "1.
|
|
1
|
+
export declare const SDK_VERSION = "1.490.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trustchex/react-native-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.490.1",
|
|
4
4
|
"description": "Trustchex mobile app react native SDK for android or ios devices",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -169,7 +169,6 @@
|
|
|
169
169
|
"react-native-nfc-manager": ">=3.16.2",
|
|
170
170
|
"react-native-safe-area-context": ">=5.5.2",
|
|
171
171
|
"react-native-screens": ">=4.18.0",
|
|
172
|
-
"react-native-share": ">=12.0.0",
|
|
173
172
|
"react-native-sse": ">=1.1.0",
|
|
174
173
|
"react-native-svg": ">=15.12.0",
|
|
175
174
|
"react-native-tts": ">=4.1.1",
|
|
@@ -217,9 +216,6 @@
|
|
|
217
216
|
"react-native-screens": {
|
|
218
217
|
"optional": false
|
|
219
218
|
},
|
|
220
|
-
"react-native-share": {
|
|
221
|
-
"optional": true
|
|
222
|
-
},
|
|
223
219
|
"react-native-sse": {
|
|
224
220
|
"optional": false
|
|
225
221
|
},
|
|
@@ -4,44 +4,44 @@ import { useTranslation } from 'react-i18next';
|
|
|
4
4
|
import StyledButton from './StyledButton';
|
|
5
5
|
import {
|
|
6
6
|
sendDiagnosticReport,
|
|
7
|
-
isDiagnosticSharingAvailable,
|
|
8
7
|
type DiagnosticImage,
|
|
9
8
|
} from '../Libs/sendDiagnosticReport';
|
|
10
9
|
import type { ScanDataForReport } from '../Libs/diagnosticReport';
|
|
11
10
|
import { SDK_VERSION } from '../../version';
|
|
12
11
|
|
|
13
12
|
export interface DiagnosticReportButtonProps {
|
|
14
|
-
|
|
13
|
+
/** Backend base URL the SDK was initialised with. */
|
|
14
|
+
baseUrl: string;
|
|
15
15
|
sessionId?: string;
|
|
16
|
+
scan: ScanDataForReport;
|
|
16
17
|
images?: DiagnosticImage[];
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* "Report a scanning issue" button for the result screen.
|
|
21
22
|
*
|
|
22
|
-
* Shows a brief notice describing what will be shared (
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* Shows a brief notice describing what will be shared (acting as the user's
|
|
24
|
+
* consent step), then uploads the diagnostic bundle (technical signals +
|
|
25
|
+
* scanned data + captured images) to the backend, encrypted in transit and at
|
|
26
|
+
* rest. Operators view and download the reports from the dashboard.
|
|
27
|
+
*
|
|
28
|
+
* Hidden when there's no session/baseUrl to upload to (e.g. before init).
|
|
27
29
|
*/
|
|
28
30
|
const DiagnosticReportButton: React.FC<DiagnosticReportButtonProps> = ({
|
|
29
|
-
|
|
31
|
+
baseUrl,
|
|
30
32
|
sessionId,
|
|
33
|
+
scan,
|
|
31
34
|
images,
|
|
32
35
|
}) => {
|
|
33
36
|
const { t } = useTranslation();
|
|
34
37
|
const [sending, setSending] = useState(false);
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
// app hasn't installed it, so apps that don't want diagnostics see no UI.
|
|
38
|
-
if (!isDiagnosticSharingAvailable()) {
|
|
39
|
+
if (!baseUrl || !sessionId) {
|
|
39
40
|
return null;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
const onPress = () => {
|
|
43
44
|
if (sending) return;
|
|
44
|
-
// Brief notice — the share draft is the actual review/consent step.
|
|
45
45
|
Alert.alert(
|
|
46
46
|
t('diagnosticReport.noticeTitle'),
|
|
47
47
|
t('diagnosticReport.noticeBody'),
|
|
@@ -52,12 +52,21 @@ const DiagnosticReportButton: React.FC<DiagnosticReportButtonProps> = ({
|
|
|
52
52
|
onPress: async () => {
|
|
53
53
|
setSending(true);
|
|
54
54
|
try {
|
|
55
|
-
await sendDiagnosticReport({
|
|
55
|
+
const { uploaded } = await sendDiagnosticReport({
|
|
56
|
+
baseUrl,
|
|
57
|
+
sessionId,
|
|
56
58
|
scan,
|
|
57
59
|
sdkVersion: SDK_VERSION,
|
|
58
|
-
sessionId,
|
|
59
60
|
images,
|
|
60
61
|
});
|
|
62
|
+
Alert.alert(
|
|
63
|
+
uploaded
|
|
64
|
+
? t('diagnosticReport.sentTitle')
|
|
65
|
+
: t('diagnosticReport.failedTitle'),
|
|
66
|
+
uploaded
|
|
67
|
+
? t('diagnosticReport.sentBody')
|
|
68
|
+
: t('diagnosticReport.failedBody')
|
|
69
|
+
);
|
|
61
70
|
} finally {
|
|
62
71
|
setSending(false);
|
|
63
72
|
}
|
|
@@ -602,7 +602,11 @@ const EIDScanner = ({
|
|
|
602
602
|
<View style={styles.idCardPhotoFrame}>
|
|
603
603
|
{documentFaceImage &&
|
|
604
604
|
(documentFaceImageMimeType === 'image/jpeg' ||
|
|
605
|
-
documentFaceImageMimeType === 'image/png'
|
|
605
|
+
documentFaceImageMimeType === 'image/png' ||
|
|
606
|
+
// Android's <Image> decodes a raw JP2 data URI; on iOS
|
|
607
|
+
// the chip JP2 is converted to JPEG before this point
|
|
608
|
+
// (native ImageIO), so iOS never reaches here as jp2.
|
|
609
|
+
documentFaceImageMimeType === 'image/jp2') ? (
|
|
606
610
|
<Image
|
|
607
611
|
source={{
|
|
608
612
|
uri: `data:${documentFaceImageMimeType};base64,${documentFaceImage}`,
|
|
@@ -325,13 +325,24 @@ export function handleIDBackFlow(
|
|
|
325
325
|
*
|
|
326
326
|
* PASSPORT: → COMPLETED (no back side)
|
|
327
327
|
* ID CARD: → SCAN_ID_BACK
|
|
328
|
+
*
|
|
329
|
+
* Routing is PASSPORT-BIASED on purpose: a passport has no back side, so if we
|
|
330
|
+
* route it to SCAN_ID_BACK it deadlocks forever waiting for a back that will
|
|
331
|
+
* never appear. We therefore only go to SCAN_ID_BACK when there is POSITIVE
|
|
332
|
+
* evidence the document is an ID card (a parsed MRZ document code that is
|
|
333
|
+
* present and not 'P'). When the type is ambiguous — e.g. the passport MRZ was
|
|
334
|
+
* never read as 'P' so the front step locked `detectedDocumentType` as
|
|
335
|
+
* 'ID_FRONT' (the torch/tilt during hologram capture makes the MRZ unreadable),
|
|
336
|
+
* or no MRZ code survived at all — we COMPLETE rather than wait for a
|
|
337
|
+
* non-existent back side. A two-sided ID card always yields an 'I'/'A'/'C'
|
|
338
|
+
* (non-'P') MRZ code, so genuine ID cards still route to SCAN_ID_BACK.
|
|
328
339
|
*/
|
|
329
340
|
export function getNextStepAfterHologram(
|
|
330
341
|
detectedDocumentType: 'ID_FRONT' | 'ID_BACK' | 'PASSPORT' | 'UNKNOWN',
|
|
331
342
|
currentFrameDocType: 'ID_FRONT' | 'ID_BACK' | 'PASSPORT' | 'UNKNOWN',
|
|
332
343
|
mrzDocCode: string | undefined
|
|
333
344
|
): 'COMPLETED' | 'SCAN_ID_BACK' {
|
|
334
|
-
//
|
|
345
|
+
// Any positive passport signal → done (no back side).
|
|
335
346
|
const isPassport =
|
|
336
347
|
detectedDocumentType === 'PASSPORT' ||
|
|
337
348
|
currentFrameDocType === 'PASSPORT' ||
|
|
@@ -341,5 +352,14 @@ export function getNextStepAfterHologram(
|
|
|
341
352
|
return 'COMPLETED';
|
|
342
353
|
}
|
|
343
354
|
|
|
344
|
-
|
|
355
|
+
// Only continue to the back side when we have POSITIVE proof it's an ID card:
|
|
356
|
+
// a real MRZ document code that is present and not a passport. Without that
|
|
357
|
+
// proof, default to COMPLETED so a misclassified passport can't hang waiting
|
|
358
|
+
// for a back side that doesn't exist.
|
|
359
|
+
const hasIdCardMrzCode = !!mrzDocCode && mrzDocCode !== 'P';
|
|
360
|
+
if (hasIdCardMrzCode) {
|
|
361
|
+
return 'SCAN_ID_BACK';
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return 'COMPLETED';
|
|
345
365
|
}
|
|
@@ -96,19 +96,17 @@ export function getStatusMessage(
|
|
|
96
96
|
isFrameBlurry: boolean,
|
|
97
97
|
allElementsDetected: boolean,
|
|
98
98
|
elementsOutsideScanArea: string[],
|
|
99
|
-
t: (key: string, params?: Record<string, unknown>) => string
|
|
100
|
-
mrzReliable: boolean = false
|
|
99
|
+
t: (key: string, params?: Record<string, unknown>) => string
|
|
101
100
|
): string {
|
|
102
101
|
if (nextStep === 'COMPLETED') {
|
|
103
102
|
return t('identityDocumentCamera.scanCompleted');
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
// MRZ
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
105
|
+
// NOTE: the "MRZ detected — hold steady" message was intentionally removed
|
|
106
|
+
// (along with its former `mrzReliable` parameter). User-facing guidance
|
|
107
|
+
// should only describe the SCAN STEP (front side, back side, hologram, etc.),
|
|
108
|
+
// not low-level MRZ-detection state. We fall through to the step-specific
|
|
109
|
+
// messages below.
|
|
112
110
|
|
|
113
111
|
if (status === 'INCORRECT') {
|
|
114
112
|
if (nextStep === 'SCAN_ID_FRONT_OR_PASSPORT') {
|
|
@@ -12,6 +12,7 @@ import { MRZInfo } from './lds/icao/mrzInfo';
|
|
|
12
12
|
import { InputStream } from './java/inputStream';
|
|
13
13
|
import { debugLog } from '../Libs/debug.utils';
|
|
14
14
|
import { diagnostics } from '../Libs/diagnostics';
|
|
15
|
+
import { decodeJp2ToJpeg } from '../Libs/jp2Decode';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Extract an APDU status word (hex, e.g. "6982") from an error message if the
|
|
@@ -239,18 +240,32 @@ function pixelsToPng(
|
|
|
239
240
|
// gate BEFORE decoding. ~12 KB decodes fast; beyond that we keep the raw JP2.
|
|
240
241
|
const MAX_JP2_DECODE_BYTES = 12 * 1024;
|
|
241
242
|
|
|
242
|
-
function convertJP2IfNeeded(
|
|
243
|
+
async function convertJP2IfNeeded(
|
|
243
244
|
imageBuffer: Buffer,
|
|
244
245
|
mimeType: string
|
|
245
|
-
): { base64: string; mimeType: string } {
|
|
246
|
+
): Promise<{ base64: string; mimeType: string }> {
|
|
246
247
|
if (mimeType !== 'image/jp2') {
|
|
247
248
|
return { base64: imageBuffer.toString('base64'), mimeType };
|
|
248
249
|
}
|
|
249
250
|
|
|
251
|
+
// Prefer the native decoder (iOS ImageIO). It decodes JPEG2000 of any size
|
|
252
|
+
// without blocking the JS thread, so it both fixes the iOS preview (RN's
|
|
253
|
+
// <Image> can't render a raw image/jp2 data URI) and avoids the slow pure-JS
|
|
254
|
+
// decoder entirely. Returns null on Android / when unavailable → fall through.
|
|
255
|
+
const native = await decodeJp2ToJpeg(imageBuffer);
|
|
256
|
+
if (native) {
|
|
257
|
+
debugLog(
|
|
258
|
+
'EID',
|
|
259
|
+
`[EID] JP2 decoded natively → ${native.mimeType} (${native.base64.length} base64 chars)`
|
|
260
|
+
);
|
|
261
|
+
return native;
|
|
262
|
+
}
|
|
263
|
+
|
|
250
264
|
// Too large to decode synchronously without freezing the UI — keep the raw
|
|
251
265
|
// JP2. The face image is still captured (the verification backend / face-match
|
|
252
266
|
// accept JPEG2000); only the on-screen preview can't render it. This lets the
|
|
253
|
-
// NFC read COMPLETE instead of hanging.
|
|
267
|
+
// NFC read COMPLETE instead of hanging. (On Android the raw JP2 still renders
|
|
268
|
+
// in <Image>; on iOS the native path above normally handles it.)
|
|
254
269
|
if (imageBuffer.length > MAX_JP2_DECODE_BYTES) {
|
|
255
270
|
debugLog(
|
|
256
271
|
'EID',
|
|
@@ -739,7 +754,7 @@ const eidReader = async (
|
|
|
739
754
|
const buffer = Buffer.alloc(imageLength);
|
|
740
755
|
await imageInputStream.readBytesWithOffset(buffer, 0, imageLength);
|
|
741
756
|
const rawMimeType = faceImageInfo.getMimeType();
|
|
742
|
-
const converted = convertJP2IfNeeded(buffer, rawMimeType);
|
|
757
|
+
const converted = await convertJP2IfNeeded(buffer, rawMimeType);
|
|
743
758
|
imageAsBase64 = converted.base64;
|
|
744
759
|
mimeType = converted.mimeType;
|
|
745
760
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { hmac } from '@noble/hashes/hmac';
|
|
3
|
+
import { sha256 } from '@noble/hashes/sha2';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Authenticity signing for the demo-diagnostics upload.
|
|
7
|
+
*
|
|
8
|
+
* Demo reports have no session/account to authenticate against, so the SDK signs
|
|
9
|
+
* each upload with HMAC-SHA256 over `timestamp.nonce.rawBody` using a shared
|
|
10
|
+
* secret. The backend recomputes and rejects mismatches and stale timestamps
|
|
11
|
+
* (replay). The secret ships in the SDK, so it's an obfuscation barrier (paired
|
|
12
|
+
* with server rate limiting), not a true secret — rotate via the env var on both
|
|
13
|
+
* sides. MUST stay byte-for-byte in sync with web-app/src/lib/diagnostic-hmac.ts.
|
|
14
|
+
*/
|
|
15
|
+
const SECRET =
|
|
16
|
+
process.env.TRUSTCHEX_DIAGNOSTICS_SECRET ??
|
|
17
|
+
'tcx-diag-v1-2f9c4a7e8b1d4f63a05e9c7b3d61f8a2';
|
|
18
|
+
|
|
19
|
+
export interface DiagnosticSignature {
|
|
20
|
+
timestamp: string;
|
|
21
|
+
nonce: string;
|
|
22
|
+
signature: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const randomNonce = (): string => {
|
|
26
|
+
// 16 random bytes as hex. crypto.getRandomValues is polyfilled by
|
|
27
|
+
// react-native-get-random-values (already imported in crypto.utils).
|
|
28
|
+
const bytes = new Uint8Array(16);
|
|
29
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
30
|
+
return Buffer.from(bytes).toString('hex');
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Sign a raw JSON body for the demo-diagnostics endpoint. */
|
|
34
|
+
export const signDiagnosticBody = (rawBody: string): DiagnosticSignature => {
|
|
35
|
+
const timestamp = Date.now().toString();
|
|
36
|
+
const nonce = randomNonce();
|
|
37
|
+
const mac = hmac(
|
|
38
|
+
sha256,
|
|
39
|
+
Buffer.from(SECRET, 'utf-8'),
|
|
40
|
+
Buffer.from(`${timestamp}.${nonce}.${rawBody}`, 'utf-8')
|
|
41
|
+
);
|
|
42
|
+
return {
|
|
43
|
+
timestamp,
|
|
44
|
+
nonce,
|
|
45
|
+
signature: Buffer.from(mac).toString('hex'),
|
|
46
|
+
};
|
|
47
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
import { Buffer } from 'buffer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Native JPEG2000 decoder bridge.
|
|
6
|
+
*
|
|
7
|
+
* The passport chip portrait (DG2) is frequently stored as JPEG2000
|
|
8
|
+
* (image/jp2). React Native's <Image> renders a JP2 data URI on Android (its
|
|
9
|
+
* Fresco/Skia pipeline decodes it) but NOT on iOS (UIImage-backed <Image>
|
|
10
|
+
* refuses the data URI), so the chip photo showed as a placeholder on iOS.
|
|
11
|
+
*
|
|
12
|
+
* iOS's ImageIO *can* decode JPEG2000, so the native `ImageDecoderModule`
|
|
13
|
+
* round-trips the JP2 to JPEG. We only need this on iOS; on Android the raw
|
|
14
|
+
* JP2 already renders, so there is no native counterpart and we no-op.
|
|
15
|
+
*/
|
|
16
|
+
interface ImageDecoderNativeModule {
|
|
17
|
+
decodeJp2ToJpeg(base64Jp2: string): Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ImageDecoder = (
|
|
21
|
+
NativeModules as { ImageDecoderModule?: ImageDecoderNativeModule }
|
|
22
|
+
).ImageDecoderModule;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Decode a JPEG2000 buffer to JPEG using the native iOS decoder.
|
|
26
|
+
*
|
|
27
|
+
* Returns the JPEG bytes + mime type on success, or null when native decode is
|
|
28
|
+
* unavailable (Android, or the module isn't linked) or fails — callers should
|
|
29
|
+
* fall back to their existing behaviour (keep raw JP2).
|
|
30
|
+
*/
|
|
31
|
+
export async function decodeJp2ToJpeg(
|
|
32
|
+
jp2Buffer: Buffer
|
|
33
|
+
): Promise<{ base64: string; mimeType: string } | null> {
|
|
34
|
+
if (Platform.OS !== 'ios' || !ImageDecoder?.decodeJp2ToJpeg) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const jpegBase64 = await ImageDecoder.decodeJp2ToJpeg(
|
|
39
|
+
jp2Buffer.toString('base64')
|
|
40
|
+
);
|
|
41
|
+
if (!jpegBase64) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return { base64: jpegBase64, mimeType: 'image/jpeg' };
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|