vesant-sdk 1.5.2 → 1.6.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/dist/{client-B8pFrXx_.d.ts → client-Bd9a5o0C.d.ts} +2 -0
- package/dist/{client-BZxzOidG.d.mts → client-C4g596fI.d.mts} +2 -0
- package/dist/compliance/index.d.mts +15 -2
- package/dist/compliance/index.d.ts +15 -2
- package/dist/compliance/index.js +200 -38
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +200 -38
- package/dist/compliance/index.mjs.map +1 -1
- package/dist/decisions/index.js +1 -1
- package/dist/decisions/index.js.map +1 -1
- package/dist/decisions/index.mjs +1 -1
- package/dist/decisions/index.mjs.map +1 -1
- package/dist/geolocation/index.d.mts +2 -2
- package/dist/geolocation/index.d.ts +2 -2
- package/dist/geolocation/index.js +1 -1
- package/dist/geolocation/index.js.map +1 -1
- package/dist/geolocation/index.mjs +1 -1
- package/dist/geolocation/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +200 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +200 -38
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.js +1 -1
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs +1 -1
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.js +1 -1
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs +1 -1
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1 -1
- package/dist/react.mjs.map +1 -1
- package/dist/risk-profile/index.js +1 -1
- package/dist/risk-profile/index.js.map +1 -1
- package/dist/risk-profile/index.mjs +1 -1
- package/dist/risk-profile/index.mjs.map +1 -1
- package/dist/scores/index.js +1 -1
- package/dist/scores/index.js.map +1 -1
- package/dist/scores/index.mjs +1 -1
- package/dist/scores/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -295,6 +295,8 @@ interface LocationVerification {
|
|
|
295
295
|
geofence_evaluation?: GeofenceEvaluation;
|
|
296
296
|
device_trust?: DeviceTrustResult;
|
|
297
297
|
record_id: string;
|
|
298
|
+
/** Whether GPS verification is required for this event type (based on tenant config) */
|
|
299
|
+
gps_required?: boolean;
|
|
298
300
|
}
|
|
299
301
|
interface ComplianceCheckResponse {
|
|
300
302
|
jurisdiction?: JurisdictionConfig;
|
|
@@ -295,6 +295,8 @@ interface LocationVerification {
|
|
|
295
295
|
geofence_evaluation?: GeofenceEvaluation;
|
|
296
296
|
device_trust?: DeviceTrustResult;
|
|
297
297
|
record_id: string;
|
|
298
|
+
/** Whether GPS verification is required for this event type (based on tenant config) */
|
|
299
|
+
gps_required?: boolean;
|
|
298
300
|
}
|
|
299
301
|
interface ComplianceCheckResponse {
|
|
300
302
|
jurisdiction?: JurisdictionConfig;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceFingerprintRequest, L as LocationVerification, T as LocationRequest, G as GeolocationClient, Y as LocationRequestFilters, Z as LocationRequestListResponse } from '../client-
|
|
2
|
-
export { W as CreateLocationRequestRequest, a0 as LocationCaptureRequest, a2 as LocationCaptureResponse, S as LocationRequestChannel, X as LocationRequestResult, R as LocationRequestStatus, a1 as LocationShareInfo, _ as ResendLocationRequestRequest } from '../client-
|
|
1
|
+
import { D as DeviceFingerprintRequest, L as LocationVerification, k as ValidateCipherTextResponse, T as LocationRequest, G as GeolocationClient, Y as LocationRequestFilters, Z as LocationRequestListResponse } from '../client-C4g596fI.mjs';
|
|
2
|
+
export { W as CreateLocationRequestRequest, a0 as LocationCaptureRequest, a2 as LocationCaptureResponse, S as LocationRequestChannel, X as LocationRequestResult, R as LocationRequestStatus, a1 as LocationShareInfo, _ as ResendLocationRequestRequest } from '../client-C4g596fI.mjs';
|
|
3
3
|
import { RiskProfileClient } from '../risk-profile/index.mjs';
|
|
4
4
|
import { V as VesantConfig, R as RequestOptions } from '../client-CIon-bGS.mjs';
|
|
5
5
|
import { C as CustomerProfile } from '../types-1RzYeSal.mjs';
|
|
@@ -15,6 +15,7 @@ interface RegistrationVerificationRequest {
|
|
|
15
15
|
entityType?: EntityType;
|
|
16
16
|
ipAddress: string;
|
|
17
17
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
18
|
+
cipherText?: string;
|
|
18
19
|
metadata?: Record<string, unknown>;
|
|
19
20
|
}
|
|
20
21
|
interface RegistrationVerificationResponse {
|
|
@@ -25,11 +26,13 @@ interface RegistrationVerificationResponse {
|
|
|
25
26
|
requiresEDD: boolean;
|
|
26
27
|
blockReasons: string[];
|
|
27
28
|
processingTime: number;
|
|
29
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
28
30
|
}
|
|
29
31
|
interface LoginVerificationRequest {
|
|
30
32
|
customerId: string;
|
|
31
33
|
ipAddress: string;
|
|
32
34
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
35
|
+
cipherText?: string;
|
|
33
36
|
metadata?: Record<string, unknown>;
|
|
34
37
|
}
|
|
35
38
|
interface LoginVerificationResponse {
|
|
@@ -39,6 +42,7 @@ interface LoginVerificationResponse {
|
|
|
39
42
|
requiresStepUp: boolean;
|
|
40
43
|
blockReasons: string[];
|
|
41
44
|
processingTime: number;
|
|
45
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
42
46
|
}
|
|
43
47
|
interface TransactionVerificationRequest {
|
|
44
48
|
customerId: string;
|
|
@@ -47,6 +51,7 @@ interface TransactionVerificationRequest {
|
|
|
47
51
|
currency: string;
|
|
48
52
|
transactionType?: 'deposit' | 'withdrawal' | 'bet' | 'transfer' | 'payout';
|
|
49
53
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
54
|
+
cipherText?: string;
|
|
50
55
|
metadata?: Record<string, unknown>;
|
|
51
56
|
}
|
|
52
57
|
interface TransactionVerificationResponse {
|
|
@@ -57,6 +62,7 @@ interface TransactionVerificationResponse {
|
|
|
57
62
|
requiresApproval: boolean;
|
|
58
63
|
blockReasons: string[];
|
|
59
64
|
processingTime: number;
|
|
65
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
60
66
|
}
|
|
61
67
|
interface TransactionRiskResult {
|
|
62
68
|
score: number;
|
|
@@ -70,6 +76,7 @@ interface EventVerificationRequest {
|
|
|
70
76
|
ipAddress: string;
|
|
71
77
|
eventType: string;
|
|
72
78
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
79
|
+
cipherText?: string;
|
|
73
80
|
metadata?: Record<string, unknown>;
|
|
74
81
|
}
|
|
75
82
|
interface EventVerificationResponse {
|
|
@@ -77,6 +84,7 @@ interface EventVerificationResponse {
|
|
|
77
84
|
geolocation: LocationVerification;
|
|
78
85
|
blockReasons: string[];
|
|
79
86
|
processingTime: number;
|
|
87
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
80
88
|
}
|
|
81
89
|
interface CurrencyRates {
|
|
82
90
|
[currency: string]: number;
|
|
@@ -264,6 +272,11 @@ declare class ComplianceClient {
|
|
|
264
272
|
verifyEvent(request: EventVerificationRequest, requestOptions?: RequestOptions): Promise<EventVerificationResponse>;
|
|
265
273
|
private shouldUpdateProfile;
|
|
266
274
|
private createProfileFromGeo;
|
|
275
|
+
/**
|
|
276
|
+
* Execute cipherText validation with graceful degradation.
|
|
277
|
+
* Returns undefined if cipherText is not provided or validation fails.
|
|
278
|
+
*/
|
|
279
|
+
private executeCipherTextValidation;
|
|
267
280
|
private calculateTransactionRisk;
|
|
268
281
|
private checkJurisdictionLimits;
|
|
269
282
|
private normalizeToUSD;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceFingerprintRequest, L as LocationVerification, T as LocationRequest, G as GeolocationClient, Y as LocationRequestFilters, Z as LocationRequestListResponse } from '../client-
|
|
2
|
-
export { W as CreateLocationRequestRequest, a0 as LocationCaptureRequest, a2 as LocationCaptureResponse, S as LocationRequestChannel, X as LocationRequestResult, R as LocationRequestStatus, a1 as LocationShareInfo, _ as ResendLocationRequestRequest } from '../client-
|
|
1
|
+
import { D as DeviceFingerprintRequest, L as LocationVerification, k as ValidateCipherTextResponse, T as LocationRequest, G as GeolocationClient, Y as LocationRequestFilters, Z as LocationRequestListResponse } from '../client-Bd9a5o0C.js';
|
|
2
|
+
export { W as CreateLocationRequestRequest, a0 as LocationCaptureRequest, a2 as LocationCaptureResponse, S as LocationRequestChannel, X as LocationRequestResult, R as LocationRequestStatus, a1 as LocationShareInfo, _ as ResendLocationRequestRequest } from '../client-Bd9a5o0C.js';
|
|
3
3
|
import { RiskProfileClient } from '../risk-profile/index.js';
|
|
4
4
|
import { V as VesantConfig, R as RequestOptions } from '../client-CIon-bGS.js';
|
|
5
5
|
import { C as CustomerProfile } from '../types-X5Md_dD_.js';
|
|
@@ -15,6 +15,7 @@ interface RegistrationVerificationRequest {
|
|
|
15
15
|
entityType?: EntityType;
|
|
16
16
|
ipAddress: string;
|
|
17
17
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
18
|
+
cipherText?: string;
|
|
18
19
|
metadata?: Record<string, unknown>;
|
|
19
20
|
}
|
|
20
21
|
interface RegistrationVerificationResponse {
|
|
@@ -25,11 +26,13 @@ interface RegistrationVerificationResponse {
|
|
|
25
26
|
requiresEDD: boolean;
|
|
26
27
|
blockReasons: string[];
|
|
27
28
|
processingTime: number;
|
|
29
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
28
30
|
}
|
|
29
31
|
interface LoginVerificationRequest {
|
|
30
32
|
customerId: string;
|
|
31
33
|
ipAddress: string;
|
|
32
34
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
35
|
+
cipherText?: string;
|
|
33
36
|
metadata?: Record<string, unknown>;
|
|
34
37
|
}
|
|
35
38
|
interface LoginVerificationResponse {
|
|
@@ -39,6 +42,7 @@ interface LoginVerificationResponse {
|
|
|
39
42
|
requiresStepUp: boolean;
|
|
40
43
|
blockReasons: string[];
|
|
41
44
|
processingTime: number;
|
|
45
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
42
46
|
}
|
|
43
47
|
interface TransactionVerificationRequest {
|
|
44
48
|
customerId: string;
|
|
@@ -47,6 +51,7 @@ interface TransactionVerificationRequest {
|
|
|
47
51
|
currency: string;
|
|
48
52
|
transactionType?: 'deposit' | 'withdrawal' | 'bet' | 'transfer' | 'payout';
|
|
49
53
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
54
|
+
cipherText?: string;
|
|
50
55
|
metadata?: Record<string, unknown>;
|
|
51
56
|
}
|
|
52
57
|
interface TransactionVerificationResponse {
|
|
@@ -57,6 +62,7 @@ interface TransactionVerificationResponse {
|
|
|
57
62
|
requiresApproval: boolean;
|
|
58
63
|
blockReasons: string[];
|
|
59
64
|
processingTime: number;
|
|
65
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
60
66
|
}
|
|
61
67
|
interface TransactionRiskResult {
|
|
62
68
|
score: number;
|
|
@@ -70,6 +76,7 @@ interface EventVerificationRequest {
|
|
|
70
76
|
ipAddress: string;
|
|
71
77
|
eventType: string;
|
|
72
78
|
deviceFingerprint?: DeviceFingerprintRequest;
|
|
79
|
+
cipherText?: string;
|
|
73
80
|
metadata?: Record<string, unknown>;
|
|
74
81
|
}
|
|
75
82
|
interface EventVerificationResponse {
|
|
@@ -77,6 +84,7 @@ interface EventVerificationResponse {
|
|
|
77
84
|
geolocation: LocationVerification;
|
|
78
85
|
blockReasons: string[];
|
|
79
86
|
processingTime: number;
|
|
87
|
+
cipherTextValidation?: ValidateCipherTextResponse;
|
|
80
88
|
}
|
|
81
89
|
interface CurrencyRates {
|
|
82
90
|
[currency: string]: number;
|
|
@@ -264,6 +272,11 @@ declare class ComplianceClient {
|
|
|
264
272
|
verifyEvent(request: EventVerificationRequest, requestOptions?: RequestOptions): Promise<EventVerificationResponse>;
|
|
265
273
|
private shouldUpdateProfile;
|
|
266
274
|
private createProfileFromGeo;
|
|
275
|
+
/**
|
|
276
|
+
* Execute cipherText validation with graceful degradation.
|
|
277
|
+
* Returns undefined if cipherText is not provided or validation fails.
|
|
278
|
+
*/
|
|
279
|
+
private executeCipherTextValidation;
|
|
267
280
|
private calculateTransactionRisk;
|
|
268
281
|
private checkJurisdictionLimits;
|
|
269
282
|
private normalizeToUSD;
|
package/dist/compliance/index.js
CHANGED
|
@@ -224,7 +224,7 @@ function createConsoleLogger() {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// src/core/version.ts
|
|
227
|
-
var SDK_VERSION = "1.
|
|
227
|
+
var SDK_VERSION = "1.6.0";
|
|
228
228
|
|
|
229
229
|
// src/shared/browser-utils.ts
|
|
230
230
|
function generateUUID() {
|
|
@@ -1440,17 +1440,34 @@ var ComplianceClient = class {
|
|
|
1440
1440
|
const startTime = Date.now();
|
|
1441
1441
|
this.validateRegistrationRequest(request);
|
|
1442
1442
|
let geoVerification = null;
|
|
1443
|
+
let cipherTextResult;
|
|
1443
1444
|
try {
|
|
1444
1445
|
if (this.config.debug) {
|
|
1445
1446
|
this.logger.debug("Starting registration verification", { customerId: request.customerId });
|
|
1446
1447
|
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1448
|
+
const customerData = request.cipherText ? {
|
|
1449
|
+
full_name: request.fullName,
|
|
1450
|
+
email: request.emailAddress,
|
|
1451
|
+
phone: request.phoneNumber,
|
|
1452
|
+
date_of_birth: request.dateOfBirth
|
|
1453
|
+
} : void 0;
|
|
1454
|
+
[cipherTextResult, geoVerification] = await Promise.all([
|
|
1455
|
+
this.executeCipherTextValidation(
|
|
1456
|
+
request.cipherText,
|
|
1457
|
+
request.customerId,
|
|
1458
|
+
"registration",
|
|
1459
|
+
request.ipAddress,
|
|
1460
|
+
customerData,
|
|
1461
|
+
requestOptions
|
|
1462
|
+
),
|
|
1463
|
+
this.geoClient.verifyIP({
|
|
1464
|
+
ip_address: request.ipAddress,
|
|
1465
|
+
user_id: request.customerId,
|
|
1466
|
+
event_type: "registration",
|
|
1467
|
+
device_fingerprint: request.deviceFingerprint
|
|
1468
|
+
}, requestOptions)
|
|
1469
|
+
]);
|
|
1470
|
+
const blockReasons = this.evaluateRegistrationBlock(geoVerification, cipherTextResult);
|
|
1454
1471
|
if (blockReasons.length > 0) {
|
|
1455
1472
|
if (this.config.debug) {
|
|
1456
1473
|
this.logger.debug("Registration blocked at geo stage", { blockReasons });
|
|
@@ -1462,7 +1479,8 @@ var ComplianceClient = class {
|
|
|
1462
1479
|
requiresKYC: false,
|
|
1463
1480
|
requiresEDD: false,
|
|
1464
1481
|
blockReasons,
|
|
1465
|
-
processingTime: Date.now() - startTime
|
|
1482
|
+
processingTime: Date.now() - startTime,
|
|
1483
|
+
cipherTextValidation: cipherTextResult
|
|
1466
1484
|
};
|
|
1467
1485
|
}
|
|
1468
1486
|
const profile = await this.riskClient.createProfile({
|
|
@@ -1497,7 +1515,8 @@ var ComplianceClient = class {
|
|
|
1497
1515
|
requiresKYC,
|
|
1498
1516
|
requiresEDD,
|
|
1499
1517
|
blockReasons: [],
|
|
1500
|
-
processingTime: Date.now() - startTime
|
|
1518
|
+
processingTime: Date.now() - startTime,
|
|
1519
|
+
cipherTextValidation: cipherTextResult
|
|
1501
1520
|
};
|
|
1502
1521
|
} catch (error) {
|
|
1503
1522
|
if (this.config.debug) {
|
|
@@ -1525,7 +1544,7 @@ var ComplianceClient = class {
|
|
|
1525
1544
|
* @param geoVerification - Geolocation verification result
|
|
1526
1545
|
* @returns Array of block reasons (empty if allowed)
|
|
1527
1546
|
*/
|
|
1528
|
-
evaluateRegistrationBlock(geoVerification) {
|
|
1547
|
+
evaluateRegistrationBlock(geoVerification, cipherTextResult) {
|
|
1529
1548
|
const blockReasons = [];
|
|
1530
1549
|
if (geoVerification.is_blocked) {
|
|
1531
1550
|
blockReasons.push(...geoVerification.risk_reasons);
|
|
@@ -1559,6 +1578,20 @@ var ComplianceClient = class {
|
|
|
1559
1578
|
blockReasons.push("critical_risk_level");
|
|
1560
1579
|
}
|
|
1561
1580
|
}
|
|
1581
|
+
if (cipherTextResult) {
|
|
1582
|
+
if (!cipherTextResult.valid) {
|
|
1583
|
+
blockReasons.push("ciphertext_validation_failed");
|
|
1584
|
+
}
|
|
1585
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
1586
|
+
blockReasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
1587
|
+
}
|
|
1588
|
+
if (cipherTextResult.risk?.location_mismatch) {
|
|
1589
|
+
blockReasons.push("gps_ip_location_mismatch");
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
if (geoVerification.gps_required && !cipherTextResult) {
|
|
1593
|
+
blockReasons.push("gps_verification_required");
|
|
1594
|
+
}
|
|
1562
1595
|
return [...new Set(blockReasons)];
|
|
1563
1596
|
}
|
|
1564
1597
|
/**
|
|
@@ -1689,7 +1722,15 @@ var ComplianceClient = class {
|
|
|
1689
1722
|
if (this.config.debug) {
|
|
1690
1723
|
this.logger.debug("Starting login verification", { customerId: request.customerId });
|
|
1691
1724
|
}
|
|
1692
|
-
const [geoVerification, profileResult] = await Promise.all([
|
|
1725
|
+
const [cipherTextResult, geoVerification, profileResult] = await Promise.all([
|
|
1726
|
+
this.executeCipherTextValidation(
|
|
1727
|
+
request.cipherText,
|
|
1728
|
+
request.customerId,
|
|
1729
|
+
"login",
|
|
1730
|
+
request.ipAddress,
|
|
1731
|
+
void 0,
|
|
1732
|
+
requestOptions
|
|
1733
|
+
),
|
|
1693
1734
|
this.geoClient.verifyIP({
|
|
1694
1735
|
ip_address: request.ipAddress,
|
|
1695
1736
|
user_id: request.customerId,
|
|
@@ -1698,10 +1739,23 @@ var ComplianceClient = class {
|
|
|
1698
1739
|
}, requestOptions),
|
|
1699
1740
|
this.riskClient.getProfile(request.customerId, requestOptions).catch(() => null)
|
|
1700
1741
|
]);
|
|
1742
|
+
const loginBlockReasons = this.getBlockReasons(geoVerification, profileResult || {}, cipherTextResult);
|
|
1743
|
+
const isBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
|
|
1744
|
+
if (isBlocked && !profileResult) {
|
|
1745
|
+
return {
|
|
1746
|
+
allowed: false,
|
|
1747
|
+
geolocation: geoVerification,
|
|
1748
|
+
profile: null,
|
|
1749
|
+
requiresStepUp: false,
|
|
1750
|
+
blockReasons: loginBlockReasons,
|
|
1751
|
+
processingTime: Date.now() - startTime,
|
|
1752
|
+
cipherTextValidation: cipherTextResult
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1701
1755
|
let profile;
|
|
1702
1756
|
if (profileResult) {
|
|
1703
1757
|
profile = profileResult;
|
|
1704
|
-
if (this.shouldUpdateProfile(profile, geoVerification.location.city)) {
|
|
1758
|
+
if (!isBlocked && this.shouldUpdateProfile(profile, geoVerification.location.city)) {
|
|
1705
1759
|
profile = await this.riskClient.updateProfile(profile.id, {
|
|
1706
1760
|
last_recorded_activity: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1707
1761
|
location: `${geoVerification.location.city}, ${geoVerification.location.country}`,
|
|
@@ -1714,15 +1768,15 @@ var ComplianceClient = class {
|
|
|
1714
1768
|
}
|
|
1715
1769
|
profile = await this.createProfileFromGeo(request.customerId, geoVerification);
|
|
1716
1770
|
}
|
|
1717
|
-
const
|
|
1718
|
-
const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical";
|
|
1771
|
+
const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical" || cipherTextResult?.risk?.location_mismatch === true;
|
|
1719
1772
|
return {
|
|
1720
|
-
allowed:
|
|
1773
|
+
allowed: !isBlocked && profile.customer_status !== "suspended",
|
|
1721
1774
|
geolocation: geoVerification,
|
|
1722
1775
|
profile,
|
|
1723
1776
|
requiresStepUp,
|
|
1724
|
-
blockReasons: this.getBlockReasons(geoVerification, profile),
|
|
1725
|
-
processingTime: Date.now() - startTime
|
|
1777
|
+
blockReasons: isBlocked || profile.customer_status === "suspended" ? this.getBlockReasons(geoVerification, profile, cipherTextResult) : [],
|
|
1778
|
+
processingTime: Date.now() - startTime,
|
|
1779
|
+
cipherTextValidation: cipherTextResult
|
|
1726
1780
|
};
|
|
1727
1781
|
} catch (error) {
|
|
1728
1782
|
throw new ComplianceError("Login verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -1769,27 +1823,55 @@ var ComplianceClient = class {
|
|
|
1769
1823
|
currency: request.currency
|
|
1770
1824
|
});
|
|
1771
1825
|
}
|
|
1772
|
-
const [geoVerification,
|
|
1826
|
+
const [cipherTextResult, geoVerification, profileResult] = await Promise.all([
|
|
1827
|
+
this.executeCipherTextValidation(
|
|
1828
|
+
request.cipherText,
|
|
1829
|
+
request.customerId,
|
|
1830
|
+
"transaction",
|
|
1831
|
+
request.ipAddress,
|
|
1832
|
+
void 0,
|
|
1833
|
+
requestOptions
|
|
1834
|
+
),
|
|
1773
1835
|
this.geoClient.verifyIP({
|
|
1774
1836
|
ip_address: request.ipAddress,
|
|
1775
1837
|
user_id: request.customerId,
|
|
1776
1838
|
event_type: "transaction",
|
|
1777
1839
|
device_fingerprint: request.deviceFingerprint
|
|
1778
1840
|
}, requestOptions),
|
|
1779
|
-
this.riskClient.getProfile(request.customerId, requestOptions)
|
|
1841
|
+
this.riskClient.getProfile(request.customerId, requestOptions).catch(() => null)
|
|
1780
1842
|
]);
|
|
1843
|
+
const geoBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
|
|
1844
|
+
if (geoBlocked && !profileResult) {
|
|
1845
|
+
return {
|
|
1846
|
+
allowed: false,
|
|
1847
|
+
geolocation: geoVerification,
|
|
1848
|
+
profile: null,
|
|
1849
|
+
transactionRisk: { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1850
|
+
requiresApproval: false,
|
|
1851
|
+
blockReasons: this.getTransactionBlockReasons(
|
|
1852
|
+
geoVerification,
|
|
1853
|
+
{ score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1854
|
+
true,
|
|
1855
|
+
cipherTextResult
|
|
1856
|
+
),
|
|
1857
|
+
processingTime: Date.now() - startTime,
|
|
1858
|
+
cipherTextValidation: cipherTextResult
|
|
1859
|
+
};
|
|
1860
|
+
}
|
|
1861
|
+
const profile = profileResult;
|
|
1781
1862
|
const transactionRisk = this.calculateTransactionRisk(
|
|
1782
1863
|
request.amount,
|
|
1783
1864
|
request.currency,
|
|
1784
1865
|
geoVerification,
|
|
1785
|
-
profile
|
|
1866
|
+
profile,
|
|
1867
|
+
cipherTextResult
|
|
1786
1868
|
);
|
|
1787
1869
|
const jurisdictionAllowed = this.checkJurisdictionLimits(
|
|
1788
1870
|
request.amount,
|
|
1789
1871
|
request.currency,
|
|
1790
1872
|
geoVerification.jurisdiction
|
|
1791
1873
|
);
|
|
1792
|
-
const isAllowed =
|
|
1874
|
+
const isAllowed = !geoBlocked && jurisdictionAllowed && transactionRisk.allowed && profile.customer_status !== "suspended";
|
|
1793
1875
|
return {
|
|
1794
1876
|
allowed: isAllowed,
|
|
1795
1877
|
geolocation: geoVerification,
|
|
@@ -1799,9 +1881,11 @@ var ComplianceClient = class {
|
|
|
1799
1881
|
blockReasons: this.getTransactionBlockReasons(
|
|
1800
1882
|
geoVerification,
|
|
1801
1883
|
transactionRisk,
|
|
1802
|
-
jurisdictionAllowed
|
|
1884
|
+
jurisdictionAllowed,
|
|
1885
|
+
cipherTextResult
|
|
1803
1886
|
),
|
|
1804
|
-
processingTime: Date.now() - startTime
|
|
1887
|
+
processingTime: Date.now() - startTime,
|
|
1888
|
+
cipherTextValidation: cipherTextResult
|
|
1805
1889
|
};
|
|
1806
1890
|
} catch (error) {
|
|
1807
1891
|
throw new ComplianceError("Transaction verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -1816,12 +1900,22 @@ var ComplianceClient = class {
|
|
|
1816
1900
|
async verifyEvent(request, requestOptions) {
|
|
1817
1901
|
const startTime = Date.now();
|
|
1818
1902
|
this.validateEventRequest(request);
|
|
1819
|
-
const geoVerification = await
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1903
|
+
const [cipherTextResult, geoVerification] = await Promise.all([
|
|
1904
|
+
this.executeCipherTextValidation(
|
|
1905
|
+
request.cipherText,
|
|
1906
|
+
request.customerId,
|
|
1907
|
+
request.eventType,
|
|
1908
|
+
request.ipAddress,
|
|
1909
|
+
void 0,
|
|
1910
|
+
requestOptions
|
|
1911
|
+
),
|
|
1912
|
+
this.geoClient.verifyIP({
|
|
1913
|
+
ip_address: request.ipAddress,
|
|
1914
|
+
user_id: request.customerId,
|
|
1915
|
+
event_type: request.eventType,
|
|
1916
|
+
device_fingerprint: request.deviceFingerprint
|
|
1917
|
+
}, requestOptions)
|
|
1918
|
+
]);
|
|
1825
1919
|
if (this.config.autoCreateProfiles) {
|
|
1826
1920
|
try {
|
|
1827
1921
|
const profile = await this.riskClient.getProfile(request.customerId, requestOptions);
|
|
@@ -1834,11 +1928,26 @@ var ComplianceClient = class {
|
|
|
1834
1928
|
}
|
|
1835
1929
|
}
|
|
1836
1930
|
}
|
|
1931
|
+
const cipherTextBlocked = cipherTextResult ? !cipherTextResult.valid || cipherTextResult.risk?.is_blocked === true : false;
|
|
1932
|
+
const blockReasons = [...geoVerification.risk_reasons];
|
|
1933
|
+
if (cipherTextResult) {
|
|
1934
|
+
if (!cipherTextResult.valid) {
|
|
1935
|
+
blockReasons.push("ciphertext_validation_failed");
|
|
1936
|
+
}
|
|
1937
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
1938
|
+
blockReasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
const gpsBlocked = geoVerification.gps_required && !cipherTextResult;
|
|
1942
|
+
if (gpsBlocked) {
|
|
1943
|
+
blockReasons.push("gps_verification_required");
|
|
1944
|
+
}
|
|
1837
1945
|
return {
|
|
1838
|
-
allowed: geoVerification.is_compliant && !geoVerification.is_blocked,
|
|
1946
|
+
allowed: geoVerification.is_compliant && !geoVerification.is_blocked && !cipherTextBlocked && !gpsBlocked,
|
|
1839
1947
|
geolocation: geoVerification,
|
|
1840
|
-
blockReasons:
|
|
1841
|
-
processingTime: Date.now() - startTime
|
|
1948
|
+
blockReasons: [...new Set(blockReasons)],
|
|
1949
|
+
processingTime: Date.now() - startTime,
|
|
1950
|
+
cipherTextValidation: cipherTextResult
|
|
1842
1951
|
};
|
|
1843
1952
|
}
|
|
1844
1953
|
// ============================================================================
|
|
@@ -1867,7 +1976,29 @@ var ComplianceClient = class {
|
|
|
1867
1976
|
kyc_status: "pending"
|
|
1868
1977
|
});
|
|
1869
1978
|
}
|
|
1870
|
-
|
|
1979
|
+
/**
|
|
1980
|
+
* Execute cipherText validation with graceful degradation.
|
|
1981
|
+
* Returns undefined if cipherText is not provided or validation fails.
|
|
1982
|
+
*/
|
|
1983
|
+
async executeCipherTextValidation(cipherText, userId, eventType, ipAddress, customerData, requestOptions) {
|
|
1984
|
+
if (!cipherText) return void 0;
|
|
1985
|
+
try {
|
|
1986
|
+
return await this.geoClient.validateCipherText(
|
|
1987
|
+
cipherText,
|
|
1988
|
+
userId,
|
|
1989
|
+
eventType,
|
|
1990
|
+
ipAddress,
|
|
1991
|
+
customerData,
|
|
1992
|
+
requestOptions
|
|
1993
|
+
);
|
|
1994
|
+
} catch (err) {
|
|
1995
|
+
this.logger.warn("CipherText validation failed, proceeding with IP-only", {
|
|
1996
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
1997
|
+
});
|
|
1998
|
+
return void 0;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
calculateTransactionRisk(amount, currency, geoVerification, profile, cipherTextResult) {
|
|
1871
2002
|
if (!this._currencyRatesCustomized && !this._currencyRatesWarned) {
|
|
1872
2003
|
this._currencyRatesWarned = true;
|
|
1873
2004
|
this.logger.warn(
|
|
@@ -1900,6 +2031,15 @@ var ComplianceClient = class {
|
|
|
1900
2031
|
riskScore += 50;
|
|
1901
2032
|
factors.push("account_suspended");
|
|
1902
2033
|
}
|
|
2034
|
+
if (cipherTextResult) {
|
|
2035
|
+
if (cipherTextResult.risk?.location_mismatch) {
|
|
2036
|
+
riskScore += 20;
|
|
2037
|
+
factors.push("gps_ip_location_mismatch");
|
|
2038
|
+
}
|
|
2039
|
+
if (cipherTextResult.risk?.score) {
|
|
2040
|
+
riskScore += cipherTextResult.risk.score * 0.2;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
1903
2043
|
return {
|
|
1904
2044
|
score: Math.min(riskScore, 100),
|
|
1905
2045
|
level: this.getRiskLevel(riskScore),
|
|
@@ -1925,7 +2065,7 @@ var ComplianceClient = class {
|
|
|
1925
2065
|
if (score >= 40) return "medium";
|
|
1926
2066
|
return "low";
|
|
1927
2067
|
}
|
|
1928
|
-
getBlockReasons(geoVerification, profile) {
|
|
2068
|
+
getBlockReasons(geoVerification, profile, cipherTextResult) {
|
|
1929
2069
|
const reasons = [];
|
|
1930
2070
|
if (geoVerification.is_blocked) {
|
|
1931
2071
|
reasons.push(...geoVerification.risk_reasons);
|
|
@@ -1936,9 +2076,20 @@ var ComplianceClient = class {
|
|
|
1936
2076
|
if (profile.has_sanctions) {
|
|
1937
2077
|
reasons.push("sanctions_match");
|
|
1938
2078
|
}
|
|
1939
|
-
|
|
2079
|
+
if (cipherTextResult) {
|
|
2080
|
+
if (!cipherTextResult.valid) {
|
|
2081
|
+
reasons.push("ciphertext_validation_failed");
|
|
2082
|
+
}
|
|
2083
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
2084
|
+
reasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2088
|
+
reasons.push("gps_verification_required");
|
|
2089
|
+
}
|
|
2090
|
+
return [...new Set(reasons)];
|
|
1940
2091
|
}
|
|
1941
|
-
getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed) {
|
|
2092
|
+
getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed, cipherTextResult) {
|
|
1942
2093
|
const reasons = [];
|
|
1943
2094
|
if (!geoVerification.is_compliant) {
|
|
1944
2095
|
reasons.push("non_compliant_jurisdiction");
|
|
@@ -1949,7 +2100,18 @@ var ComplianceClient = class {
|
|
|
1949
2100
|
if (!transactionRisk.allowed) {
|
|
1950
2101
|
reasons.push(...transactionRisk.factors);
|
|
1951
2102
|
}
|
|
1952
|
-
|
|
2103
|
+
if (cipherTextResult) {
|
|
2104
|
+
if (!cipherTextResult.valid) {
|
|
2105
|
+
reasons.push("ciphertext_validation_failed");
|
|
2106
|
+
}
|
|
2107
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
2108
|
+
reasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2112
|
+
reasons.push("gps_verification_required");
|
|
2113
|
+
}
|
|
2114
|
+
return [...new Set(reasons)];
|
|
1953
2115
|
}
|
|
1954
2116
|
// ============================================================================
|
|
1955
2117
|
// Location Request Methods
|