@sanctum-key/react-native-sdk 1.0.9 → 1.0.10
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/build/package.json +1 -1
- package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.js +259 -63
- package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +222 -69
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js +160 -21
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js.map +1 -1
- package/build/src/config/region_mapping.json +727 -0
- package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/src/modules/api/CardAuthentification.js +3 -7
- package/build/src/modules/api/CardAuthentification.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +1 -2
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +106 -59
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/package.json +1 -1
- package/src/components/KYCElements/CountrySelection.tsx +300 -74
- package/src/components/KYCElements/IDCardCapture.tsx +310 -156
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +201 -29
- package/src/modules/api/CardAuthentification.ts +5 -8
- package/src/modules/api/KYCService.ts +167 -105
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { GovernmentDocumentType, GovernmentDocumentTypeShorted, OrientationVideoResponse } from '../../types/KYC.types';
|
|
3
|
-
import { CheckTemplateTypeResponse
|
|
3
|
+
import { CheckTemplateTypeResponse } from '../../components/OverLay/type';
|
|
4
4
|
import { SessionResponse, VerificationResult, VerificationSessionRequest } from './types';
|
|
5
5
|
import { KycEnvironment } from '../../types/env.types';
|
|
6
6
|
import { logger } from '../../utils/logger';
|
|
@@ -60,9 +60,9 @@ export class KYCService {
|
|
|
60
60
|
private baseURL: string;
|
|
61
61
|
private apiKey: string;
|
|
62
62
|
// Additional service base URLs (fixed as per current infra)
|
|
63
|
-
private faceServiceURL = 'https://
|
|
64
|
-
private textExtractionServiceURL = 'https://
|
|
65
|
-
private mrzServiceURL = 'https://
|
|
63
|
+
private faceServiceURL = 'https://face-infera.sanctumkey.com:8000';
|
|
64
|
+
private textExtractionServiceURL = 'https://text-infera.sanctumkey.com:8006';
|
|
65
|
+
private mrzServiceURL = 'https://mrz-infera.sanctumkey.com:8002';
|
|
66
66
|
private barcodeServiceURL = 'https://kyc-engine.transfergratis.net:8000';
|
|
67
67
|
private orientationServiceURL = 'http://18.188.180.154:8080';
|
|
68
68
|
|
|
@@ -239,8 +239,8 @@ export class KYCService {
|
|
|
239
239
|
const formData = new FormData();
|
|
240
240
|
await appendFileToFormData(formData, 'file', idCardImageUri, 'id_card_photo.jpg', 'image/jpeg');
|
|
241
241
|
|
|
242
|
-
const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType];
|
|
243
|
-
|
|
242
|
+
const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType] || docType;
|
|
243
|
+
|
|
244
244
|
// Log metadata, NOT the FormData object
|
|
245
245
|
logger.log('detectFaceOnId Request:', { docTypeShorted, imageUri: idCardImageUri });
|
|
246
246
|
|
|
@@ -305,7 +305,7 @@ export class KYCService {
|
|
|
305
305
|
logger.log('checkTemplateType res', JSON.stringify(res.data, null, 2));
|
|
306
306
|
return res.data;
|
|
307
307
|
} catch (e: any) {
|
|
308
|
-
logger.error('Error
|
|
308
|
+
logger.error('Error checkingg template type:', JSON.stringify(e));
|
|
309
309
|
throw e;
|
|
310
310
|
}
|
|
311
311
|
|
|
@@ -379,78 +379,104 @@ export class KYCService {
|
|
|
379
379
|
|
|
380
380
|
// STEP 3 - MRZ TEXT EXTRACTION
|
|
381
381
|
async extractMrzText(
|
|
382
|
-
params: {
|
|
383
|
-
fileUri: string;
|
|
384
|
-
docType: string;
|
|
385
|
-
docRegion: string;
|
|
386
|
-
postfix?: string;
|
|
387
|
-
token: string;
|
|
388
|
-
template_path: string;
|
|
389
|
-
mrz_type?: string;
|
|
390
|
-
},
|
|
382
|
+
params: {
|
|
383
|
+
fileUri: string;
|
|
384
|
+
docType: string;
|
|
385
|
+
docRegion: string;
|
|
386
|
+
postfix?: string;
|
|
387
|
+
token: string;
|
|
388
|
+
template_path: string;
|
|
389
|
+
mrz_type?: string;
|
|
390
|
+
},
|
|
391
391
|
env: KycEnvironment = 'PRODUCTION'
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
392
|
+
): Promise<any> {
|
|
393
|
+
// SANDBOX mode
|
|
394
|
+
if (env === 'SANDBOX') {
|
|
395
|
+
console.log("SANDBOX mode: Skipping AI MRZ extraction");
|
|
396
|
+
const { docType, docRegion, postfix = 'back', mrz_type } = params;
|
|
397
|
+
return {
|
|
398
|
+
success: true,
|
|
399
|
+
parsed_data: {
|
|
400
|
+
status: 'success',
|
|
401
|
+
document_type: docType,
|
|
402
|
+
mrz_type: mrz_type || 'TD1',
|
|
403
|
+
doc_region: docRegion,
|
|
404
|
+
postfix: postfix
|
|
405
|
+
},
|
|
406
|
+
card_obb: { x: 50, y: 50, width: 200, height: 200 }
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const { fileUri, docType, docRegion, postfix = 'back', token, template_path, mrz_type } = params;
|
|
411
|
+
|
|
412
|
+
// 1. Build the FormData ONLY for the file
|
|
413
|
+
const formData = new FormData();
|
|
414
|
+
const filePayload = {
|
|
415
|
+
uri: fileUri,
|
|
416
|
+
type: 'image/jpeg',
|
|
417
|
+
name: `id_card_${postfix}.jpg`,
|
|
418
|
+
};
|
|
419
|
+
formData.append('file', filePayload as any);
|
|
420
|
+
|
|
421
|
+
const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType] || docType;
|
|
422
|
+
const safeMrzType = mrz_type && mrz_type.trim() !== '' ? mrz_type : 'TD1';
|
|
423
|
+
|
|
424
|
+
logger.log("docTypeShorted", docTypeShorted, docRegion, postfix);
|
|
425
|
+
|
|
426
|
+
// 🚨 THE FIX: Pass all required text parameters in the URL query string for FastAPI
|
|
427
|
+
const queryParams = new URLSearchParams({
|
|
428
|
+
doc_type: docTypeShorted,
|
|
429
|
+
doc_region: docRegion,
|
|
430
|
+
postfix: postfix,
|
|
431
|
+
template_path: template_path,
|
|
432
|
+
mrz_type: safeMrzType,
|
|
433
|
+
reset_cache: 'true'
|
|
434
|
+
}).toString();
|
|
435
|
+
|
|
436
|
+
const url = `${this.mrzServiceURL}/extract_mrz_text/?${queryParams}`;
|
|
437
|
+
logger.log("url", url);
|
|
438
|
+
|
|
439
|
+
try {
|
|
440
|
+
const response = await fetch(url, {
|
|
441
|
+
method: 'POST',
|
|
442
|
+
headers: {
|
|
443
|
+
'Authorization': `Bearer ${token}`,
|
|
444
|
+
'Accept': 'application/json'
|
|
406
445
|
},
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
446
|
+
body: formData, // Only the file goes in the body
|
|
447
|
+
});
|
|
410
448
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
449
|
+
if (!response.ok) {
|
|
450
|
+
const errorText = await response.text();
|
|
451
|
+
logger.error('Backend MRZ Error Details:', errorText);
|
|
452
|
+
throw new Error(`Erreur serveur: ${response.status}`);
|
|
453
|
+
}
|
|
416
454
|
|
|
417
|
-
const
|
|
418
|
-
logger.log(
|
|
455
|
+
// const data = await response.json();
|
|
456
|
+
// logger.log('extractMrzText res', JSON.stringify(data, null, 2));
|
|
419
457
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (mrz_type && mrz_type.trim() !== '') {
|
|
423
|
-
url += `&mrz_type=${encodeURIComponent(mrz_type)}`;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
logger.log("url", url);
|
|
458
|
+
// if (Object.keys(data).length === 0) throw new Error('No data found');
|
|
459
|
+
// if (data?.success === false) throw new Error(data.parsed_data?.status || 'Échec de l\'extraction MRZ');
|
|
427
460
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
headers: { 'Content-Type': 'multipart/form-data', 'Authorization': `Bearer ${token}` },
|
|
432
|
-
// Note: Reduced timeout to 10000ms (10s) based on our earlier network fix to prevent infinite hanging!
|
|
433
|
-
timeout: 10000,
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
logger.log('extractMrzText res', JSON.stringify(res.data, null, 2));
|
|
437
|
-
|
|
438
|
-
if (Object.keys(res.data).length === 0) throw new Error('No data found');
|
|
439
|
-
if (res.data?.success === false) throw new Error(res.data.parsed_data?.status || 'Échec de l\'extraction MRZ');
|
|
440
|
-
|
|
441
|
-
return res.data;
|
|
442
|
-
} catch (e: any) {
|
|
443
|
-
throw new Error(e?.message || 'Erreur de détection du MRZ');
|
|
444
|
-
}
|
|
445
|
-
};
|
|
461
|
+
// return data;
|
|
462
|
+
const data = await response.json();
|
|
463
|
+
logger.log('extractMrzText res', JSON.stringify(data, null, 2));
|
|
446
464
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
465
|
+
if (Object.keys(data).length === 0) throw new Error('No data found');
|
|
466
|
+
|
|
467
|
+
// 🚨 UPDATE THIS LINE to grab the actual status_message:
|
|
468
|
+
if (data?.success === false) {
|
|
469
|
+
const serverMessage = data.parsed_data?.status_message || data.parsed_data?.status || 'Échec de l\'extraction MRZ';
|
|
470
|
+
throw new Error(`Lecture MRZ refusée: ${serverMessage}`);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return data;
|
|
474
|
+
|
|
475
|
+
} catch (error: any) {
|
|
476
|
+
logger.error("MRZ Fetch Error: ", error?.message || error);
|
|
477
|
+
throw new Error(error?.message || 'Erreur de connexion lors de l\'extraction MRZ');
|
|
478
|
+
}
|
|
479
|
+
}
|
|
454
480
|
|
|
455
481
|
// STEP 2 - SELFIE VALIDATION
|
|
456
482
|
async recognizeFace(params: { idPhotoUri: string; selfiePhotoUri: string }, env: KycEnvironment = 'PRODUCTION'): Promise<{ is_match: boolean; similarity: number; id_bbox?: number[]; selfie_bbox?: number[] }> {
|
|
@@ -627,49 +653,85 @@ export class KYCService {
|
|
|
627
653
|
auth?: { apiKey?: string; token?: string }
|
|
628
654
|
): Promise<unknown> {
|
|
629
655
|
const url = `${KYCConfig.getBackendUrl()}/accounts/send-whatsapp-verification/`;
|
|
630
|
-
const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
|
|
631
656
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
657
|
+
// 1. Formatting (Ensure consistency with verification step)
|
|
658
|
+
const formattedPhoneNumber = phoneNumber.replace(/^\+/, '');
|
|
659
|
+
|
|
660
|
+
// 2. Prepare Payload
|
|
661
|
+
const payload = {
|
|
635
662
|
session_id: sessionId,
|
|
636
|
-
phone_number:
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
663
|
+
phone_number: formattedPhoneNumber
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
|
|
669
|
+
const headers = {
|
|
670
|
+
'Content-Type': 'application/json',
|
|
671
|
+
...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
const res = await axios.post(url, payload, { headers });
|
|
678
|
+
|
|
679
|
+
logger.log("✅ WhatsApp Send Success:", res.data);
|
|
680
|
+
return res.data;
|
|
681
|
+
|
|
682
|
+
} catch (error: any) {
|
|
683
|
+
if (error.response) {
|
|
684
|
+
logger.error("🛑 WhatsApp Send Failed (Server Response):", {
|
|
685
|
+
status: error.response.status,
|
|
686
|
+
data: error.response.data,
|
|
687
|
+
headers: error.response.headers
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
throw error;
|
|
691
|
+
}
|
|
646
692
|
}
|
|
647
693
|
|
|
648
|
-
/** Verify WhatsApp code with OTP. POST /api/v1/accounts/verify-whatsapp-verification/ */
|
|
649
694
|
async verifyWhatsAppCode(
|
|
650
695
|
sessionId: string,
|
|
651
696
|
otp: string,
|
|
697
|
+
phoneNumber: string,
|
|
652
698
|
auth?: { apiKey?: string; token?: string }
|
|
653
699
|
): Promise<unknown> {
|
|
654
|
-
|
|
655
|
-
const url = `${KYCConfig.getBackendUrl()}/accounts/verify-whatsapp-verification/`;
|
|
656
|
-
const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
|
|
700
|
+
const url = `${KYCConfig.getBackendUrl()}/accounts/verify-whatsapp-code/`;
|
|
657
701
|
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
702
|
+
const formattedPhoneNumber = phoneNumber.replace(/^\+/, '');
|
|
703
|
+
|
|
704
|
+
const payload = {
|
|
661
705
|
session_id: sessionId,
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
706
|
+
verification_code: otp,
|
|
707
|
+
phone_number: formattedPhoneNumber
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
|
|
713
|
+
const headers = {
|
|
714
|
+
'Content-Type': 'application/json',
|
|
715
|
+
...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
try {
|
|
720
|
+
const res = await axios.post(url, payload, { headers });
|
|
721
|
+
|
|
722
|
+
return res.data;
|
|
723
|
+
|
|
724
|
+
} catch (error: any) {
|
|
725
|
+
if (error.response) {
|
|
726
|
+
logger.error("🛑 WhatsApp Verification Failed (Server Response):", {
|
|
727
|
+
status: error.response.status,
|
|
728
|
+
data: error.response.data,
|
|
729
|
+
headers: error.response.headers
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
throw error;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
673
735
|
}
|
|
674
736
|
|
|
675
737
|
const kycService = new KYCService("", "");
|
|
@@ -719,7 +781,7 @@ export const authentification = async (): Promise<string> => {
|
|
|
719
781
|
const params = 'client_id=kyc_frontend&client_secret=QhgAmvKgmwODzsEp98dnA4PeUEMMaFHd&grant_type=client_credentials';
|
|
720
782
|
|
|
721
783
|
const res = await axios.post(
|
|
722
|
-
`https://
|
|
784
|
+
`https://idms.sanctumkey.com/realms/kyc/protocol/openid-connect/token`,
|
|
723
785
|
params,
|
|
724
786
|
{
|
|
725
787
|
headers: {
|