vesant-sdk 1.1.0 → 1.2.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/{types-DgNbBnEH.d.ts → client-BIfLMfuC.d.mts} +274 -2
- package/dist/{types-DGbuL8c0.d.mts → client-BWp5FI3x.d.ts} +274 -2
- package/dist/compliance/index.d.mts +9 -4
- package/dist/compliance/index.d.ts +9 -4
- package/dist/compliance/index.js +297 -2
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +297 -2
- package/dist/compliance/index.mjs.map +1 -1
- package/dist/geolocation/index.d.mts +3 -5
- package/dist/geolocation/index.d.ts +3 -5
- package/dist/geolocation/index.js +310 -250
- package/dist/geolocation/index.js.map +1 -1
- package/dist/geolocation/index.mjs +310 -250
- package/dist/geolocation/index.mjs.map +1 -1
- package/dist/index.d.mts +5 -7
- package/dist/index.d.ts +5 -7
- package/dist/index.js +322 -251
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +322 -251
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.d.mts +2 -3
- package/dist/kyc/core.d.ts +2 -3
- 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.d.mts +2 -3
- package/dist/kyc/index.d.ts +2 -3
- 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 +3 -5
- package/dist/react.d.ts +3 -5
- package/dist/react.js +29 -3
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +29 -3
- package/dist/react.mjs.map +1 -1
- package/dist/risk-profile/index.d.mts +4 -5
- package/dist/risk-profile/index.d.ts +4 -5
- 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/{types-DBGM-bFB.d.mts → types-BpKxSXGF.d.mts} +50 -1
- package/dist/{types-DBGM-bFB.d.ts → types-BpKxSXGF.d.ts} +50 -1
- package/dist/{types-BQTkTvNp.d.mts → types-DKCQN4C5.d.mts} +1 -1
- package/dist/{types-BF8mYH2W.d.ts → types-DfHLp_tz.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/client-B7YzKVEm.d.mts +0 -52
- package/dist/client-BaNLT2Df.d.ts +0 -52
- package/dist/client-VKJg2GGT.d.mts +0 -253
- package/dist/client-hXdrPhA4.d.ts +0 -253
package/dist/index.mjs
CHANGED
|
@@ -99,7 +99,7 @@ var noopLogger = {
|
|
|
99
99
|
};
|
|
100
100
|
|
|
101
101
|
// src/core/version.ts
|
|
102
|
-
var SDK_VERSION = "1.
|
|
102
|
+
var SDK_VERSION = "1.2.0";
|
|
103
103
|
|
|
104
104
|
// src/core/client.ts
|
|
105
105
|
var BaseClient = class {
|
|
@@ -324,6 +324,281 @@ var BaseClient = class {
|
|
|
324
324
|
}
|
|
325
325
|
};
|
|
326
326
|
|
|
327
|
+
// src/shared/browser-utils.ts
|
|
328
|
+
function generateUUID() {
|
|
329
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
330
|
+
return crypto.randomUUID();
|
|
331
|
+
}
|
|
332
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
333
|
+
const r = Math.random() * 16 | 0;
|
|
334
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
335
|
+
return v.toString(16);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
function generateDeviceId() {
|
|
339
|
+
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
340
|
+
return generateUUID();
|
|
341
|
+
}
|
|
342
|
+
const storageKey = "cgs_device_id";
|
|
343
|
+
let deviceId = localStorage.getItem(storageKey);
|
|
344
|
+
if (!deviceId) {
|
|
345
|
+
deviceId = generateUUID();
|
|
346
|
+
localStorage.setItem(storageKey, deviceId);
|
|
347
|
+
}
|
|
348
|
+
return deviceId;
|
|
349
|
+
}
|
|
350
|
+
function getBrowserInfo() {
|
|
351
|
+
if (typeof navigator === "undefined") {
|
|
352
|
+
return { browser: "unknown", browser_version: "", os: "unknown", os_version: "" };
|
|
353
|
+
}
|
|
354
|
+
const ua = navigator.userAgent;
|
|
355
|
+
let browser = "unknown";
|
|
356
|
+
let browserVersion = "";
|
|
357
|
+
let os = "unknown";
|
|
358
|
+
let osVersion = "";
|
|
359
|
+
if (ua.includes("Firefox/")) {
|
|
360
|
+
browser = "Firefox";
|
|
361
|
+
browserVersion = ua.match(/Firefox\/([\d.]+)/)?.[1] || "";
|
|
362
|
+
} else if (ua.includes("Edg/")) {
|
|
363
|
+
browser = "Edge";
|
|
364
|
+
browserVersion = ua.match(/Edg\/([\d.]+)/)?.[1] || "";
|
|
365
|
+
} else if (ua.includes("Chrome/")) {
|
|
366
|
+
browser = "Chrome";
|
|
367
|
+
browserVersion = ua.match(/Chrome\/([\d.]+)/)?.[1] || "";
|
|
368
|
+
} else if (ua.includes("Safari/") && !ua.includes("Chrome")) {
|
|
369
|
+
browser = "Safari";
|
|
370
|
+
browserVersion = ua.match(/Version\/([\d.]+)/)?.[1] || "";
|
|
371
|
+
} else if (ua.includes("Opera") || ua.includes("OPR/")) {
|
|
372
|
+
browser = "Opera";
|
|
373
|
+
browserVersion = ua.match(/(?:Opera|OPR)\/([\d.]+)/)?.[1] || "";
|
|
374
|
+
}
|
|
375
|
+
if (ua.includes("Windows")) {
|
|
376
|
+
os = "Windows";
|
|
377
|
+
if (ua.includes("Windows NT 10.0")) osVersion = "10";
|
|
378
|
+
else if (ua.includes("Windows NT 6.3")) osVersion = "8.1";
|
|
379
|
+
else if (ua.includes("Windows NT 6.2")) osVersion = "8";
|
|
380
|
+
else if (ua.includes("Windows NT 6.1")) osVersion = "7";
|
|
381
|
+
} else if (ua.includes("Mac OS X")) {
|
|
382
|
+
os = "macOS";
|
|
383
|
+
osVersion = ua.match(/Mac OS X ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
384
|
+
} else if (ua.includes("Linux")) {
|
|
385
|
+
os = "Linux";
|
|
386
|
+
} else if (ua.includes("Android")) {
|
|
387
|
+
os = "Android";
|
|
388
|
+
osVersion = ua.match(/Android ([\d.]+)/)?.[1] || "";
|
|
389
|
+
} else if (ua.includes("iOS") || ua.includes("iPhone") || ua.includes("iPad")) {
|
|
390
|
+
os = "iOS";
|
|
391
|
+
osVersion = ua.match(/OS ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
392
|
+
}
|
|
393
|
+
return { browser, browser_version: browserVersion, os, os_version: osVersion };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/geolocation/ciphertext.ts
|
|
397
|
+
var CIPHER_TEXT_EXPIRY_MINUTES = 5;
|
|
398
|
+
async function computeHMAC(key, message) {
|
|
399
|
+
if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
|
|
400
|
+
const encoder = new TextEncoder();
|
|
401
|
+
const keyData = encoder.encode(key);
|
|
402
|
+
const msgData = encoder.encode(message);
|
|
403
|
+
const cryptoKey = await globalThis.crypto.subtle.importKey(
|
|
404
|
+
"raw",
|
|
405
|
+
keyData,
|
|
406
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
407
|
+
false,
|
|
408
|
+
["sign"]
|
|
409
|
+
);
|
|
410
|
+
const signature = await globalThis.crypto.subtle.sign("HMAC", cryptoKey, msgData);
|
|
411
|
+
const bytes = new Uint8Array(signature);
|
|
412
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
413
|
+
}
|
|
414
|
+
const { createHmac } = await import('crypto');
|
|
415
|
+
return createHmac("sha256", key).update(message).digest("hex");
|
|
416
|
+
}
|
|
417
|
+
function getWebGLInfo() {
|
|
418
|
+
if (typeof document === "undefined") return null;
|
|
419
|
+
try {
|
|
420
|
+
const canvas = document.createElement("canvas");
|
|
421
|
+
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
|
422
|
+
if (!gl) return null;
|
|
423
|
+
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
424
|
+
if (!debugInfo) return null;
|
|
425
|
+
return {
|
|
426
|
+
vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || "",
|
|
427
|
+
renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || ""
|
|
428
|
+
};
|
|
429
|
+
} catch {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function getNetworkInfo() {
|
|
434
|
+
if (typeof navigator === "undefined") return void 0;
|
|
435
|
+
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
|
436
|
+
if (!connection) return void 0;
|
|
437
|
+
return {
|
|
438
|
+
effective_type: connection.effectiveType,
|
|
439
|
+
downlink: connection.downlink,
|
|
440
|
+
rtt: connection.rtt,
|
|
441
|
+
save_data: connection.saveData
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
445
|
+
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
return new Promise((resolve) => {
|
|
449
|
+
navigator.geolocation.getCurrentPosition(
|
|
450
|
+
(position) => {
|
|
451
|
+
const { latitude, longitude, accuracy } = position.coords;
|
|
452
|
+
if (latitude < -90 || latitude > 90) {
|
|
453
|
+
resolve(null);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
if (longitude < -180 || longitude > 180) {
|
|
457
|
+
resolve(null);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (accuracy !== null && accuracy !== void 0 && accuracy <= 0) {
|
|
461
|
+
resolve(null);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
resolve({
|
|
465
|
+
latitude,
|
|
466
|
+
longitude,
|
|
467
|
+
accuracy,
|
|
468
|
+
altitude: position.coords.altitude ?? void 0,
|
|
469
|
+
altitude_accuracy: position.coords.altitudeAccuracy ?? void 0,
|
|
470
|
+
heading: position.coords.heading ?? void 0,
|
|
471
|
+
speed: position.coords.speed ?? void 0,
|
|
472
|
+
timestamp: position.timestamp
|
|
473
|
+
});
|
|
474
|
+
},
|
|
475
|
+
() => {
|
|
476
|
+
resolve(null);
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
enableHighAccuracy: highAccuracy,
|
|
480
|
+
timeout,
|
|
481
|
+
maximumAge: 0
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
function collectDeviceData(includeWebGL) {
|
|
487
|
+
const browserInfo = getBrowserInfo();
|
|
488
|
+
const webglInfo = includeWebGL ? getWebGLInfo() : null;
|
|
489
|
+
return {
|
|
490
|
+
device_id: generateDeviceId(),
|
|
491
|
+
user_agent: typeof navigator !== "undefined" ? navigator.userAgent : "",
|
|
492
|
+
platform: typeof navigator !== "undefined" ? navigator.platform : "",
|
|
493
|
+
browser: browserInfo.browser,
|
|
494
|
+
browser_version: browserInfo.browser_version,
|
|
495
|
+
os: browserInfo.os,
|
|
496
|
+
os_version: browserInfo.os_version,
|
|
497
|
+
screen_resolution: typeof screen !== "undefined" ? `${screen.width}x${screen.height}` : void 0,
|
|
498
|
+
language: typeof navigator !== "undefined" ? navigator.language : void 0,
|
|
499
|
+
timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone,
|
|
500
|
+
color_depth: typeof screen !== "undefined" ? screen.colorDepth : void 0,
|
|
501
|
+
hardware_concurrency: typeof navigator !== "undefined" ? navigator.hardwareConcurrency : void 0,
|
|
502
|
+
device_memory: typeof navigator !== "undefined" ? navigator.deviceMemory : void 0,
|
|
503
|
+
touch_support: typeof navigator !== "undefined" ? navigator.maxTouchPoints > 0 : void 0,
|
|
504
|
+
webgl_vendor: webglInfo?.vendor,
|
|
505
|
+
webgl_renderer: webglInfo?.renderer
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function encodePayload(payload) {
|
|
509
|
+
const json = JSON.stringify(payload);
|
|
510
|
+
if (typeof btoa !== "undefined") {
|
|
511
|
+
return btoa(unescape(encodeURIComponent(json)));
|
|
512
|
+
} else if (typeof Buffer !== "undefined") {
|
|
513
|
+
return Buffer.from(json, "utf-8").toString("base64");
|
|
514
|
+
}
|
|
515
|
+
throw new Error("No base64 encoding method available");
|
|
516
|
+
}
|
|
517
|
+
async function generateCipherText(options, config) {
|
|
518
|
+
const warnings = [];
|
|
519
|
+
let requestLocation = options.requestLocation ?? false;
|
|
520
|
+
if (config?.require_gps) {
|
|
521
|
+
const reason = options.reason;
|
|
522
|
+
if (reason === "login" && config.require_gps.login || reason === "registration" && config.require_gps.registration || reason === "transaction" && config.require_gps.transaction) {
|
|
523
|
+
requestLocation = true;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const deviceData = collectDeviceData(options.includeWebGL !== false);
|
|
527
|
+
let locationData;
|
|
528
|
+
if (requestLocation) {
|
|
529
|
+
const location = await requestGPSLocation(
|
|
530
|
+
options.locationTimeout || 1e4,
|
|
531
|
+
options.highAccuracy !== false
|
|
532
|
+
);
|
|
533
|
+
if (location) {
|
|
534
|
+
locationData = location;
|
|
535
|
+
} else {
|
|
536
|
+
warnings.push("GPS location not available or permission denied");
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
let networkData;
|
|
540
|
+
if (options.includeNetworkInfo !== false) {
|
|
541
|
+
networkData = getNetworkInfo();
|
|
542
|
+
}
|
|
543
|
+
const now = /* @__PURE__ */ new Date();
|
|
544
|
+
const expiry = new Date(now.getTime() + CIPHER_TEXT_EXPIRY_MINUTES * 60 * 1e3);
|
|
545
|
+
const payload = {
|
|
546
|
+
device: deviceData,
|
|
547
|
+
location: locationData,
|
|
548
|
+
network: networkData,
|
|
549
|
+
metadata: {
|
|
550
|
+
collected_at: now.toISOString(),
|
|
551
|
+
sdk_version: SDK_VERSION,
|
|
552
|
+
collection_reason: options.reason,
|
|
553
|
+
page_url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
554
|
+
referrer: typeof document !== "undefined" ? document.referrer || void 0 : void 0
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
const encoded = encodePayload(payload);
|
|
558
|
+
const timestamp = now.getTime().toString(36);
|
|
559
|
+
let cipherText;
|
|
560
|
+
const hmacKey = options.signingKey || options.apiKey;
|
|
561
|
+
if (hmacKey) {
|
|
562
|
+
const message = `02.${timestamp}.${encoded}`;
|
|
563
|
+
const hmac = await computeHMAC(hmacKey, message);
|
|
564
|
+
cipherText = `${message}.${hmac}`;
|
|
565
|
+
} else {
|
|
566
|
+
cipherText = `01.${timestamp}.${encoded}`;
|
|
567
|
+
}
|
|
568
|
+
return {
|
|
569
|
+
cipherText,
|
|
570
|
+
locationCaptured: !!locationData,
|
|
571
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
572
|
+
generatedAt: now.toISOString(),
|
|
573
|
+
expiresAt: expiry.toISOString()
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
function decodeCipherText(cipherText) {
|
|
577
|
+
try {
|
|
578
|
+
const parts = cipherText.split(".");
|
|
579
|
+
if (parts.length !== 3 && parts.length !== 4) return null;
|
|
580
|
+
const [version, , encodedB64] = parts;
|
|
581
|
+
if (version !== "01" && version !== "02") return null;
|
|
582
|
+
const json = decodeURIComponent(escape(atob(encodedB64)));
|
|
583
|
+
return JSON.parse(json);
|
|
584
|
+
} catch {
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function isCipherTextExpired(cipherText) {
|
|
589
|
+
try {
|
|
590
|
+
const parts = cipherText.split(".");
|
|
591
|
+
if (parts.length !== 3 && parts.length !== 4) return true;
|
|
592
|
+
const timestampB36 = parts[1];
|
|
593
|
+
const timestamp = parseInt(timestampB36, 36);
|
|
594
|
+
const now = Date.now();
|
|
595
|
+
const expiryMs = CIPHER_TEXT_EXPIRY_MINUTES * 60 * 1e3;
|
|
596
|
+
return now - timestamp > expiryMs;
|
|
597
|
+
} catch {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
327
602
|
// src/geolocation/client.ts
|
|
328
603
|
var GeolocationClient = class extends BaseClient {
|
|
329
604
|
constructor(config) {
|
|
@@ -424,7 +699,11 @@ var GeolocationClient = class extends BaseClient {
|
|
|
424
699
|
* ```
|
|
425
700
|
*/
|
|
426
701
|
async getGPSConfig(requestOptions) {
|
|
427
|
-
|
|
702
|
+
const config = await this.requestWithRetry("/api/v1/geo/config", void 0, void 0, void 0, requestOptions);
|
|
703
|
+
if (config.signing_key) {
|
|
704
|
+
this.cachedSigningKey = config.signing_key;
|
|
705
|
+
}
|
|
706
|
+
return config;
|
|
428
707
|
}
|
|
429
708
|
// ============================================================================
|
|
430
709
|
// CipherText Validation
|
|
@@ -684,258 +963,39 @@ var GeolocationClient = class extends BaseClient {
|
|
|
684
963
|
}, void 0, requestOptions);
|
|
685
964
|
}
|
|
686
965
|
// ============================================================================
|
|
687
|
-
//
|
|
966
|
+
// CipherText Generation
|
|
688
967
|
// ============================================================================
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
function getBrowserInfo() {
|
|
715
|
-
if (typeof navigator === "undefined") {
|
|
716
|
-
return { browser: "unknown", browser_version: "", os: "unknown", os_version: "" };
|
|
717
|
-
}
|
|
718
|
-
const ua = navigator.userAgent;
|
|
719
|
-
let browser = "unknown";
|
|
720
|
-
let browserVersion = "";
|
|
721
|
-
let os = "unknown";
|
|
722
|
-
let osVersion = "";
|
|
723
|
-
if (ua.includes("Firefox/")) {
|
|
724
|
-
browser = "Firefox";
|
|
725
|
-
browserVersion = ua.match(/Firefox\/([\d.]+)/)?.[1] || "";
|
|
726
|
-
} else if (ua.includes("Edg/")) {
|
|
727
|
-
browser = "Edge";
|
|
728
|
-
browserVersion = ua.match(/Edg\/([\d.]+)/)?.[1] || "";
|
|
729
|
-
} else if (ua.includes("Chrome/")) {
|
|
730
|
-
browser = "Chrome";
|
|
731
|
-
browserVersion = ua.match(/Chrome\/([\d.]+)/)?.[1] || "";
|
|
732
|
-
} else if (ua.includes("Safari/") && !ua.includes("Chrome")) {
|
|
733
|
-
browser = "Safari";
|
|
734
|
-
browserVersion = ua.match(/Version\/([\d.]+)/)?.[1] || "";
|
|
735
|
-
} else if (ua.includes("Opera") || ua.includes("OPR/")) {
|
|
736
|
-
browser = "Opera";
|
|
737
|
-
browserVersion = ua.match(/(?:Opera|OPR)\/([\d.]+)/)?.[1] || "";
|
|
738
|
-
}
|
|
739
|
-
if (ua.includes("Windows")) {
|
|
740
|
-
os = "Windows";
|
|
741
|
-
if (ua.includes("Windows NT 10.0")) osVersion = "10";
|
|
742
|
-
else if (ua.includes("Windows NT 6.3")) osVersion = "8.1";
|
|
743
|
-
else if (ua.includes("Windows NT 6.2")) osVersion = "8";
|
|
744
|
-
else if (ua.includes("Windows NT 6.1")) osVersion = "7";
|
|
745
|
-
} else if (ua.includes("Mac OS X")) {
|
|
746
|
-
os = "macOS";
|
|
747
|
-
osVersion = ua.match(/Mac OS X ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
748
|
-
} else if (ua.includes("Linux")) {
|
|
749
|
-
os = "Linux";
|
|
750
|
-
} else if (ua.includes("Android")) {
|
|
751
|
-
os = "Android";
|
|
752
|
-
osVersion = ua.match(/Android ([\d.]+)/)?.[1] || "";
|
|
753
|
-
} else if (ua.includes("iOS") || ua.includes("iPhone") || ua.includes("iPad")) {
|
|
754
|
-
os = "iOS";
|
|
755
|
-
osVersion = ua.match(/OS ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
756
|
-
}
|
|
757
|
-
return { browser, browser_version: browserVersion, os, os_version: osVersion };
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
// src/geolocation/ciphertext.ts
|
|
761
|
-
var CIPHER_TEXT_EXPIRY_MINUTES = 5;
|
|
762
|
-
function getWebGLInfo() {
|
|
763
|
-
if (typeof document === "undefined") return null;
|
|
764
|
-
try {
|
|
765
|
-
const canvas = document.createElement("canvas");
|
|
766
|
-
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
|
767
|
-
if (!gl) return null;
|
|
768
|
-
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
769
|
-
if (!debugInfo) return null;
|
|
770
|
-
return {
|
|
771
|
-
vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || "",
|
|
772
|
-
renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || ""
|
|
773
|
-
};
|
|
774
|
-
} catch {
|
|
775
|
-
return null;
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
function getNetworkInfo() {
|
|
779
|
-
if (typeof navigator === "undefined") return void 0;
|
|
780
|
-
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
|
781
|
-
if (!connection) return void 0;
|
|
782
|
-
return {
|
|
783
|
-
effective_type: connection.effectiveType,
|
|
784
|
-
downlink: connection.downlink,
|
|
785
|
-
rtt: connection.rtt,
|
|
786
|
-
save_data: connection.saveData
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
790
|
-
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
791
|
-
return null;
|
|
792
|
-
}
|
|
793
|
-
return new Promise((resolve) => {
|
|
794
|
-
navigator.geolocation.getCurrentPosition(
|
|
795
|
-
(position) => {
|
|
796
|
-
const { latitude, longitude, accuracy } = position.coords;
|
|
797
|
-
if (latitude < -90 || latitude > 90) {
|
|
798
|
-
resolve(null);
|
|
799
|
-
return;
|
|
800
|
-
}
|
|
801
|
-
if (longitude < -180 || longitude > 180) {
|
|
802
|
-
resolve(null);
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
if (accuracy !== null && accuracy !== void 0 && accuracy <= 0) {
|
|
806
|
-
resolve(null);
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
resolve({
|
|
810
|
-
latitude,
|
|
811
|
-
longitude,
|
|
812
|
-
accuracy,
|
|
813
|
-
altitude: position.coords.altitude ?? void 0,
|
|
814
|
-
altitude_accuracy: position.coords.altitudeAccuracy ?? void 0,
|
|
815
|
-
heading: position.coords.heading ?? void 0,
|
|
816
|
-
speed: position.coords.speed ?? void 0,
|
|
817
|
-
timestamp: position.timestamp
|
|
818
|
-
});
|
|
819
|
-
},
|
|
820
|
-
() => {
|
|
821
|
-
resolve(null);
|
|
822
|
-
},
|
|
823
|
-
{
|
|
824
|
-
enableHighAccuracy: highAccuracy,
|
|
825
|
-
timeout,
|
|
826
|
-
maximumAge: 0
|
|
827
|
-
}
|
|
968
|
+
/**
|
|
969
|
+
* Generate a signed cipherText containing device and location data.
|
|
970
|
+
*
|
|
971
|
+
* Automatically passes the client's API key for HMAC signing (v02 format).
|
|
972
|
+
* If no API key is configured, falls back to unsigned v01 format.
|
|
973
|
+
*
|
|
974
|
+
* @param options - Options for cipherText generation
|
|
975
|
+
* @param gpsConfig - Optional GPS config (from getGPSConfig)
|
|
976
|
+
* @returns CipherText result with the signed string
|
|
977
|
+
*
|
|
978
|
+
* @example
|
|
979
|
+
* ```typescript
|
|
980
|
+
* const result = await client.generateCipherText({ reason: 'login' });
|
|
981
|
+
* console.log(result.cipherText); // v02 signed cipherText
|
|
982
|
+
* ```
|
|
983
|
+
*/
|
|
984
|
+
async generateCipherText(options, gpsConfig) {
|
|
985
|
+
let signingKey = this.cachedSigningKey;
|
|
986
|
+
if (!signingKey) {
|
|
987
|
+
const config = await this.getGPSConfig();
|
|
988
|
+
signingKey = config.signing_key;
|
|
989
|
+
}
|
|
990
|
+
return generateCipherText(
|
|
991
|
+
{ ...options, signingKey: signingKey || void 0 },
|
|
992
|
+
gpsConfig
|
|
828
993
|
);
|
|
829
|
-
});
|
|
830
|
-
}
|
|
831
|
-
function collectDeviceData(includeWebGL) {
|
|
832
|
-
const browserInfo = getBrowserInfo();
|
|
833
|
-
const webglInfo = includeWebGL ? getWebGLInfo() : null;
|
|
834
|
-
return {
|
|
835
|
-
device_id: generateDeviceId(),
|
|
836
|
-
user_agent: typeof navigator !== "undefined" ? navigator.userAgent : "",
|
|
837
|
-
platform: typeof navigator !== "undefined" ? navigator.platform : "",
|
|
838
|
-
browser: browserInfo.browser,
|
|
839
|
-
browser_version: browserInfo.browser_version,
|
|
840
|
-
os: browserInfo.os,
|
|
841
|
-
os_version: browserInfo.os_version,
|
|
842
|
-
screen_resolution: typeof screen !== "undefined" ? `${screen.width}x${screen.height}` : void 0,
|
|
843
|
-
language: typeof navigator !== "undefined" ? navigator.language : void 0,
|
|
844
|
-
timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone,
|
|
845
|
-
color_depth: typeof screen !== "undefined" ? screen.colorDepth : void 0,
|
|
846
|
-
hardware_concurrency: typeof navigator !== "undefined" ? navigator.hardwareConcurrency : void 0,
|
|
847
|
-
device_memory: typeof navigator !== "undefined" ? navigator.deviceMemory : void 0,
|
|
848
|
-
touch_support: typeof navigator !== "undefined" ? navigator.maxTouchPoints > 0 : void 0,
|
|
849
|
-
webgl_vendor: webglInfo?.vendor,
|
|
850
|
-
webgl_renderer: webglInfo?.renderer
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
function encodePayload(payload) {
|
|
854
|
-
const json = JSON.stringify(payload);
|
|
855
|
-
if (typeof btoa !== "undefined") {
|
|
856
|
-
return btoa(unescape(encodeURIComponent(json)));
|
|
857
|
-
} else if (typeof Buffer !== "undefined") {
|
|
858
|
-
return Buffer.from(json, "utf-8").toString("base64");
|
|
859
|
-
}
|
|
860
|
-
throw new Error("No base64 encoding method available");
|
|
861
|
-
}
|
|
862
|
-
async function generateCipherText(options, config) {
|
|
863
|
-
const warnings = [];
|
|
864
|
-
let requestLocation = options.requestLocation ?? false;
|
|
865
|
-
if (config?.require_gps) {
|
|
866
|
-
const reason = options.reason;
|
|
867
|
-
if (reason === "login" && config.require_gps.login || reason === "registration" && config.require_gps.registration || reason === "transaction" && config.require_gps.transaction) {
|
|
868
|
-
requestLocation = true;
|
|
869
|
-
}
|
|
870
994
|
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
options.locationTimeout || 1e4,
|
|
876
|
-
options.highAccuracy !== false
|
|
877
|
-
);
|
|
878
|
-
if (location) {
|
|
879
|
-
locationData = location;
|
|
880
|
-
} else {
|
|
881
|
-
warnings.push("GPS location not available or permission denied");
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
let networkData;
|
|
885
|
-
if (options.includeNetworkInfo !== false) {
|
|
886
|
-
networkData = getNetworkInfo();
|
|
887
|
-
}
|
|
888
|
-
const now = /* @__PURE__ */ new Date();
|
|
889
|
-
const expiry = new Date(now.getTime() + CIPHER_TEXT_EXPIRY_MINUTES * 60 * 1e3);
|
|
890
|
-
const payload = {
|
|
891
|
-
device: deviceData,
|
|
892
|
-
location: locationData,
|
|
893
|
-
network: networkData,
|
|
894
|
-
metadata: {
|
|
895
|
-
collected_at: now.toISOString(),
|
|
896
|
-
sdk_version: SDK_VERSION,
|
|
897
|
-
collection_reason: options.reason,
|
|
898
|
-
page_url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
899
|
-
referrer: typeof document !== "undefined" ? document.referrer || void 0 : void 0
|
|
900
|
-
}
|
|
901
|
-
};
|
|
902
|
-
const encoded = encodePayload(payload);
|
|
903
|
-
const version = "01";
|
|
904
|
-
const timestamp = now.getTime().toString(36);
|
|
905
|
-
const cipherText = `${version}.${timestamp}.${encoded}`;
|
|
906
|
-
return {
|
|
907
|
-
cipherText,
|
|
908
|
-
locationCaptured: !!locationData,
|
|
909
|
-
warnings: warnings.length > 0 ? warnings : void 0,
|
|
910
|
-
generatedAt: now.toISOString(),
|
|
911
|
-
expiresAt: expiry.toISOString()
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
function decodeCipherText(cipherText) {
|
|
915
|
-
try {
|
|
916
|
-
const parts = cipherText.split(".");
|
|
917
|
-
if (parts.length !== 3) return null;
|
|
918
|
-
const [version, , encodedB64] = parts;
|
|
919
|
-
if (version !== "01") return null;
|
|
920
|
-
const json = decodeURIComponent(escape(atob(encodedB64)));
|
|
921
|
-
return JSON.parse(json);
|
|
922
|
-
} catch {
|
|
923
|
-
return null;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
function isCipherTextExpired(cipherText) {
|
|
927
|
-
try {
|
|
928
|
-
const parts = cipherText.split(".");
|
|
929
|
-
if (parts.length !== 3) return true;
|
|
930
|
-
const timestampB36 = parts[1];
|
|
931
|
-
const timestamp = parseInt(timestampB36, 36);
|
|
932
|
-
const now = Date.now();
|
|
933
|
-
const expiryMs = CIPHER_TEXT_EXPIRY_MINUTES * 60 * 1e3;
|
|
934
|
-
return now - timestamp > expiryMs;
|
|
935
|
-
} catch {
|
|
936
|
-
return true;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
995
|
+
// ============================================================================
|
|
996
|
+
// Utility Methods (inherited from BaseClient: healthCheck, updateConfig, getConfig, buildQueryString)
|
|
997
|
+
// ============================================================================
|
|
998
|
+
};
|
|
939
999
|
|
|
940
1000
|
// src/risk-profile/client.ts
|
|
941
1001
|
var RiskProfileClient = class extends BaseClient {
|
|
@@ -1120,6 +1180,17 @@ var ComplianceClient = class {
|
|
|
1120
1180
|
this.currencyRates = DEFAULT_CURRENCY_RATES;
|
|
1121
1181
|
}
|
|
1122
1182
|
// ============================================================================
|
|
1183
|
+
// Sub-Client Accessors
|
|
1184
|
+
// ============================================================================
|
|
1185
|
+
/** Get the underlying GeolocationClient for direct geolocation API access */
|
|
1186
|
+
getGeolocationClient() {
|
|
1187
|
+
return this.geoClient;
|
|
1188
|
+
}
|
|
1189
|
+
/** Get the underlying RiskProfileClient for direct risk profile API access */
|
|
1190
|
+
getRiskProfileClient() {
|
|
1191
|
+
return this.riskClient;
|
|
1192
|
+
}
|
|
1193
|
+
// ============================================================================
|
|
1123
1194
|
// Main Verification Methods
|
|
1124
1195
|
// ============================================================================
|
|
1125
1196
|
/**
|