@keverdjs/fraud-sdk 1.0.0 → 2.0.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.
Files changed (32) hide show
  1. package/README.md +9 -2
  2. package/dist/collectors/audio-fingerprint.d.ts +29 -0
  3. package/dist/collectors/battery-api.d.ts +28 -0
  4. package/dist/collectors/behavioral.d.ts +29 -61
  5. package/dist/collectors/browser-capabilities.d.ts +33 -0
  6. package/dist/collectors/canvas-fingerprint.d.ts +25 -0
  7. package/dist/collectors/cpu-memory.d.ts +33 -0
  8. package/dist/collectors/fingerprint-manager.d.ts +34 -0
  9. package/dist/collectors/fingerprintjs.d.ts +17 -0
  10. package/dist/collectors/font-detection.d.ts +23 -0
  11. package/dist/collectors/form-interactions.d.ts +63 -0
  12. package/dist/collectors/hardware-signals.d.ts +31 -0
  13. package/dist/collectors/keystroke-monitor.d.ts +49 -0
  14. package/dist/collectors/kinematic-engine.d.ts +66 -0
  15. package/dist/collectors/media-devices.d.ts +24 -0
  16. package/dist/collectors/page-interactions.d.ts +54 -0
  17. package/dist/collectors/permissions-api.d.ts +28 -0
  18. package/dist/collectors/plugin-mime.d.ts +26 -0
  19. package/dist/collectors/privacy-signals.d.ts +34 -0
  20. package/dist/collectors/screen-display.d.ts +35 -0
  21. package/dist/collectors/storage-database.d.ts +50 -0
  22. package/dist/collectors/timezone-locale.d.ts +38 -0
  23. package/dist/collectors/touch-pointer.d.ts +34 -0
  24. package/dist/collectors/visitor-id-generator.d.ts +28 -0
  25. package/dist/collectors/webgl-fingerprint.d.ts +27 -0
  26. package/dist/collectors/webrtc-ip.d.ts +26 -0
  27. package/dist/core/sdk.d.ts +81 -2
  28. package/dist/fintechrisk.js +1 -1
  29. package/dist/index.d.ts +4 -1
  30. package/dist/types/fingerprint.d.ts +145 -0
  31. package/dist/types.d.ts +124 -1
  32. package/package.json +2 -2
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Plugin & MIME Type Collector
3
+ * Safely enumerates plugins and MIME types (privacy-conscious, limited data)
4
+ * Note: Modern browsers have deprecated plugins, but we collect what's available
5
+ */
6
+ export interface PluginMimeFingerprint {
7
+ plugins: Array<{
8
+ name: string;
9
+ description: string;
10
+ mimeTypes: string[];
11
+ }>;
12
+ mimeTypes: string[];
13
+ duration: number;
14
+ }
15
+ export declare class PluginMimeCollector {
16
+ private cachedFingerprint;
17
+ /**
18
+ * Collect plugin and MIME type information
19
+ * Returns null if plugins are not available (modern browsers)
20
+ */
21
+ collect(): PluginMimeFingerprint | null;
22
+ /**
23
+ * Clear cached fingerprint
24
+ */
25
+ clearCache(): void;
26
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Privacy Signal Collector
3
+ * Detects incognito mode, VPN/proxy, automation/bots, and ad blockers
4
+ */
5
+ export interface PrivacySignals {
6
+ isIncognito: boolean;
7
+ isVPN: boolean;
8
+ isAutomated: boolean;
9
+ hasAdBlocker: boolean;
10
+ }
11
+ export declare class PrivacySignalCollector {
12
+ private cachedSignals;
13
+ /**
14
+ * Collect all privacy signals
15
+ */
16
+ collect(): PrivacySignals;
17
+ /**
18
+ * Detect incognito/private mode
19
+ * Uses multiple detection methods for accuracy
20
+ */
21
+ private detectIncognito;
22
+ /**
23
+ * Detect automation/bot frameworks
24
+ */
25
+ private detectAutomation;
26
+ /**
27
+ * Detect ad blocker
28
+ */
29
+ private detectAdBlocker;
30
+ /**
31
+ * Clear cached signals (useful for testing)
32
+ */
33
+ clearCache(): void;
34
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Screen & Display Collector
3
+ * Collects screen resolution, color depth, pixel ratio, orientation, and multi-monitor info
4
+ */
5
+ export interface ScreenDisplayFingerprint {
6
+ width: number;
7
+ height: number;
8
+ availWidth: number;
9
+ availHeight: number;
10
+ colorDepth: number;
11
+ pixelDepth: number;
12
+ pixelRatio: number;
13
+ orientation: string | null;
14
+ orientationAngle: number | null;
15
+ duration: number;
16
+ }
17
+ export declare class ScreenDisplayCollector {
18
+ private cachedFingerprint;
19
+ /**
20
+ * Collect screen and display information
21
+ */
22
+ collect(): ScreenDisplayFingerprint;
23
+ /**
24
+ * Get screen orientation
25
+ */
26
+ private getOrientation;
27
+ /**
28
+ * Get screen orientation angle
29
+ */
30
+ private getOrientationAngle;
31
+ /**
32
+ * Clear cached fingerprint
33
+ */
34
+ clearCache(): void;
35
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Storage & Database Collector
3
+ * Detects localStorage, sessionStorage, IndexedDB, WebSQL availability and quotas
4
+ */
5
+ export interface StorageDatabaseFingerprint {
6
+ localStorage: {
7
+ available: boolean;
8
+ quota: number | null;
9
+ usage: number | null;
10
+ };
11
+ sessionStorage: {
12
+ available: boolean;
13
+ quota: number | null;
14
+ usage: number | null;
15
+ };
16
+ indexedDB: {
17
+ available: boolean;
18
+ };
19
+ webSQL: {
20
+ available: boolean;
21
+ };
22
+ duration: number;
23
+ }
24
+ export declare class StorageDatabaseCollector {
25
+ private cachedFingerprint;
26
+ /**
27
+ * Collect storage and database information
28
+ */
29
+ collect(): Promise<StorageDatabaseFingerprint>;
30
+ /**
31
+ * Check localStorage availability and quota
32
+ */
33
+ private checkLocalStorage;
34
+ /**
35
+ * Check sessionStorage availability and quota
36
+ */
37
+ private checkSessionStorage;
38
+ /**
39
+ * Check IndexedDB availability
40
+ */
41
+ private checkIndexedDB;
42
+ /**
43
+ * Check WebSQL availability (deprecated but still in some browsers)
44
+ */
45
+ private checkWebSQL;
46
+ /**
47
+ * Clear cached fingerprint
48
+ */
49
+ clearCache(): void;
50
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Timezone & Locale Collector
3
+ * Collects timezone, locale, date/time formatting preferences, and calendar system
4
+ */
5
+ export interface TimezoneLocaleFingerprint {
6
+ timezone: string;
7
+ timezoneOffset: number;
8
+ locale: string;
9
+ locales: string[];
10
+ dateFormat: string;
11
+ timeFormat: string;
12
+ numberFormat: string;
13
+ calendar: string | null;
14
+ duration: number;
15
+ }
16
+ export declare class TimezoneLocaleCollector {
17
+ private cachedFingerprint;
18
+ /**
19
+ * Collect timezone and locale information
20
+ */
21
+ collect(): TimezoneLocaleFingerprint;
22
+ /**
23
+ * Get date format preference
24
+ */
25
+ private getDateFormat;
26
+ /**
27
+ * Get time format preference (12h vs 24h)
28
+ */
29
+ private getTimeFormat;
30
+ /**
31
+ * Get number format preference
32
+ */
33
+ private getNumberFormat;
34
+ /**
35
+ * Clear cached fingerprint
36
+ */
37
+ clearCache(): void;
38
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Touch & Pointer Collector
3
+ * Collects maxTouchPoints, pointer capabilities, touch event support
4
+ */
5
+ export interface TouchPointerFingerprint {
6
+ maxTouchPoints: number;
7
+ touchSupport: boolean;
8
+ pointerSupport: boolean;
9
+ pointerTypes: string[];
10
+ duration: number;
11
+ }
12
+ export declare class TouchPointerCollector {
13
+ private cachedFingerprint;
14
+ /**
15
+ * Collect touch and pointer information
16
+ */
17
+ collect(): TouchPointerFingerprint;
18
+ /**
19
+ * Check if touch events are supported
20
+ */
21
+ private checkTouchSupport;
22
+ /**
23
+ * Check if Pointer Events are supported
24
+ */
25
+ private checkPointerSupport;
26
+ /**
27
+ * Get available pointer types
28
+ */
29
+ private getPointerTypes;
30
+ /**
31
+ * Clear cached fingerprint
32
+ */
33
+ clearCache(): void;
34
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Stable Visitor ID Generator
3
+ * Combines all fingerprint components into deterministic, stable visitor ID using SHA-256
4
+ * This replaces FingerprintJS visitor ID with our own implementation
5
+ */
6
+ import { FingerprintComponents } from '../types/fingerprint';
7
+ export declare class VisitorIDGenerator {
8
+ /**
9
+ * Generate a stable visitor ID from fingerprint components
10
+ * Uses SHA-256-like hashing for consistency
11
+ */
12
+ generate(components: FingerprintComponents): string;
13
+ /**
14
+ * Calculate confidence score based on component availability
15
+ * More components = higher confidence
16
+ */
17
+ calculateConfidence(components: FingerprintComponents): number;
18
+ /**
19
+ * SHA-256-like hash function
20
+ * Produces a 64-character hex string (matching SHA-256 format)
21
+ */
22
+ private sha256Hash;
23
+ /**
24
+ * SHA-256-like hash (synchronous, deterministic)
25
+ * Produces 64-character hex string
26
+ */
27
+ private sha256LikeHash;
28
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * WebGL Fingerprint Collector
3
+ * Extracts WebGL vendor, renderer, version, supported extensions, and shader precision
4
+ * This provides hardware-level identification
5
+ */
6
+ export interface WebGLFingerprint {
7
+ vendor: string | null;
8
+ renderer: string | null;
9
+ version: string | null;
10
+ shadingLanguageVersion: string | null;
11
+ extensions: string[];
12
+ parameters: Record<string, any>;
13
+ precision: Record<string, string>;
14
+ duration: number;
15
+ }
16
+ export declare class WebGLFingerprintCollector {
17
+ private cachedFingerprint;
18
+ /**
19
+ * Generate WebGL fingerprint
20
+ * Returns null if WebGL is not available
21
+ */
22
+ collect(): WebGLFingerprint | null;
23
+ /**
24
+ * Clear cached fingerprint
25
+ */
26
+ clearCache(): void;
27
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * WebRTC IP Collector
3
+ * Extracts local IP addresses via WebRTC (with privacy considerations and error handling)
4
+ * Note: This requires user interaction and may be blocked by privacy settings
5
+ */
6
+ export interface WebRTCIPFingerprint {
7
+ localIPs: string[];
8
+ publicIP: string | null;
9
+ duration: number;
10
+ }
11
+ export declare class WebRTCIPCollector {
12
+ private cachedFingerprint;
13
+ /**
14
+ * Collect WebRTC IP information
15
+ * Returns null if WebRTC is not available or fails
16
+ */
17
+ collect(): Promise<WebRTCIPFingerprint | null>;
18
+ /**
19
+ * Check if an IP is a local/private IP
20
+ */
21
+ private isLocalIP;
22
+ /**
23
+ * Clear cached fingerprint
24
+ */
25
+ clearCache(): void;
26
+ }
@@ -8,13 +8,27 @@ export declare class KeverdSDK {
8
8
  private config;
9
9
  private deviceCollector;
10
10
  private behavioralCollector;
11
+ private fingerprintManager;
12
+ private privacySignalCollector;
13
+ private browserCapabilityCollector;
14
+ private hardwareSignalCollector;
15
+ private formInteractionCollector;
16
+ private pageInteractionCollector;
11
17
  private isInitialized;
12
18
  private sessionId;
19
+ private ghostInterval;
20
+ private ghostStartTime;
21
+ private ghostSignalCount;
22
+ private readonly MIN_GHOST_SIGNALS;
23
+ private readonly MAX_GHOST_COLLECTION_TIME;
13
24
  constructor();
14
25
  /**
15
26
  * Initialize the SDK with configuration
16
27
  */
17
28
  init(config: SDKConfig | string): void;
29
+ private startGhostSignalCollection;
30
+ private stopGhostSignalCollection;
31
+ private sendGhostSignals;
18
32
  /**
19
33
  * Get visitor data (fingerprint and risk assessment)
20
34
  * This is the main method for getting risk scores
@@ -24,7 +38,31 @@ export declare class KeverdSDK {
24
38
  * Create transaction ID with risk assessment (legacy method)
25
39
  * For new implementations, use getVisitorData() instead
26
40
  */
27
- createTransactionID(metadata?: TransactionMetadata): Promise<string>;
41
+ createTransactionID(_metadata?: TransactionMetadata): Promise<string>;
42
+ /**
43
+ * Verify user identity during login attempts
44
+ */
45
+ verifyLogin(userId?: string, metadata?: Record<string, unknown>): Promise<FingerprintResponse>;
46
+ /**
47
+ * Verify user during checkout/payment
48
+ */
49
+ verifyCheckout(amount?: number, currency?: string, metadata?: Record<string, unknown>): Promise<FingerprintResponse>;
50
+ /**
51
+ * Detect fake/bot registrations
52
+ */
53
+ verifyRegistration(metadata?: Record<string, unknown>): Promise<FingerprintResponse>;
54
+ /**
55
+ * Detect account takeover attempts during password reset
56
+ */
57
+ verifyPasswordReset(email?: string, metadata?: Record<string, unknown>): Promise<FingerprintResponse>;
58
+ /**
59
+ * Verify sensitive account changes (email, phone, password)
60
+ */
61
+ verifyAccountChange(changeType?: string, metadata?: Record<string, unknown>): Promise<FingerprintResponse>;
62
+ /**
63
+ * Helper to send verify request to use-case-specific endpoint
64
+ */
65
+ private sendVerifyRequest;
28
66
  /**
29
67
  * Send fingerprint request to backend
30
68
  */
@@ -33,9 +71,50 @@ export declare class KeverdSDK {
33
71
  * Generate a unique session ID
34
72
  */
35
73
  private generateSessionId;
74
+ /**
75
+ * Detect browser name from user agent
76
+ */
77
+ private _detectBrowser;
78
+ /**
79
+ * Detect OS from user agent
80
+ */
81
+ private _detectOS;
82
+ /**
83
+ * Start a new session (called automatically on init, but can be called manually)
84
+ */
85
+ startSession(userId?: string, deviceHash?: string, metadata?: Record<string, unknown>): Promise<void>;
86
+ /**
87
+ * End the current session
88
+ */
89
+ endSession(): Promise<void>;
90
+ /**
91
+ * Pause the current session (e.g., when app goes to background)
92
+ */
93
+ pauseSession(): Promise<void>;
94
+ /**
95
+ * Resume a paused session (e.g., when app comes to foreground)
96
+ */
97
+ resumeSession(): Promise<void>;
98
+ /**
99
+ * Get current session status
100
+ */
101
+ getSessionStatus(): Promise<{
102
+ session_id: string;
103
+ status: string;
104
+ is_active: boolean;
105
+ is_paused: boolean;
106
+ event_count: number;
107
+ started_at: string;
108
+ last_activity_at: string;
109
+ duration_seconds: number | null;
110
+ } | null>;
36
111
  /**
37
112
  * Destroy the SDK instance
38
113
  */
39
- destroy(): void;
114
+ destroy(): Promise<void>;
115
+ /**
116
+ * Check if SDK is initialized and ready to use
117
+ */
118
+ isReady(): boolean;
40
119
  }
41
120
  export declare const Keverd: KeverdSDK;
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.FintechRisk=e():t.FintechRisk=e()}(this,()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"t",{value:!0})}},e={};t.r(e),t.d(e,{BehavioralCollector:()=>s,DeviceCollector:()=>i,Keverd:()=>r,KeverdSDK:()=>n});class i{constructor(){this.cachedDeviceInfo=null}collect(){if(this.cachedDeviceInfo)return this.cachedDeviceInfo;const t=this.generateDeviceFingerprint(),e=this.generateDeviceId(t);return this.cachedDeviceInfo={deviceId:e,fingerprint:t,manufacturer:this.getManufacturer(),model:this.getModel(),brand:this.getBrand(),device:this.getDevice(),product:this.getProduct(),hardware:this.getHardware(),sdkVersion:"1.0.0",osVersion:this.getOSVersion(),screenWidth:String(screen.width),screenHeight:String(screen.height),screenDensity:this.getScreenDensity(),locale:navigator.language||navigator.languages?.[0]||"en",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},this.cachedDeviceInfo}generateDeviceFingerprint(){const t=[],e=this.getCanvasFingerprint();e&&t.push(e);const i=this.getWebGLFingerprint();if(i&&t.push(i),t.push(navigator.userAgent),t.push(navigator.language||navigator.languages?.[0]||""),t.push(`${screen.width}x${screen.height}x${screen.colorDepth}`),t.push(String((new Date).getTimezoneOffset())),t.push(navigator.platform),t.push(String(navigator.hardwareConcurrency||0)),"deviceMemory"in navigator&&t.push(String(navigator.deviceMemory)),"maxTouchPoints"in navigator&&t.push(String(navigator.maxTouchPoints)),navigator.plugins&&navigator.plugins.length>0){const e=Array.from(navigator.plugins).slice(0,3).map(t=>t.name).join(",");t.push(e)}const s=t.join("|");return this.hashString(s)}getCanvasFingerprint(){try{const t=document.createElement("canvas"),e=t.getContext("2d");return e?(t.width=200,t.height=50,e.textBaseline="top",e.font="14px Arial",e.fillStyle="#f60",e.fillRect(125,1,62,20),e.fillStyle="#069",e.fillText("KeverdFingerprint",2,15),e.fillStyle="rgba(102, 204, 0, 0.7)",e.fillText("KeverdFingerprint",4,17),this.hashString(t.toDataURL())):""}catch(t){return""}}getWebGLFingerprint(){try{const t=document.createElement("canvas"),e=t.getContext("webgl")||t.getContext("experimental-webgl");if(!e)return"";const i=e.getExtension("WEBGL_debug_renderer_info");if(i){const t=e.getParameter(i.UNMASKED_VENDOR_WEBGL),s=e.getParameter(i.UNMASKED_RENDERER_WEBGL);return this.hashString(`${t}|${s}`)}const s=e.getParameter(e.VERSION),n=e.getParameter(e.VENDOR);return this.hashString(`${s}|${n}`)}catch(t){return""}}generateDeviceId(t){return t.substring(0,32)}getManufacturer(){const t=navigator.userAgent.toLowerCase();if(t.includes("iphone")||t.includes("ipad"))return"Apple";if(t.includes("android")){const e=t.match(/(?:^|\s)([a-z]+)(?:\s|$)/);return e?e[1].charAt(0).toUpperCase()+e[1].slice(1):void 0}}getModel(){const t=navigator.userAgent.match(/(iPhone|iPad|Android)[\s\/]+([\w]+)/i);return t?t[2]:void 0}getBrand(){return this.getManufacturer()}getDevice(){const t=navigator.userAgent.toLowerCase();return t.includes("mobile")?"mobile":t.includes("tablet")?"tablet":"desktop"}getProduct(){const t=navigator.userAgent.match(/(iPhone|iPad|Android|Windows|Mac|Linux)/i);return t?t[1]:void 0}getHardware(){const t=navigator.userAgent.match(/\(([^)]+)\)/);return t?t[1]:void 0}getOSVersion(){const t=navigator.userAgent,e=[/OS\s+([\d_]+)/i,/Android\s+([\d.]+)/i,/Windows\s+([\d.]+)/i,/Mac\s+OS\s+X\s+([\d_]+)/i,/Linux/i];for(const i of e){const e=t.match(i);if(e)return e[1]?.replace(/_/g,".")||e[0]}}getScreenDensity(){if(window.devicePixelRatio)return String(window.devicePixelRatio)}hashString(t){return this.sha256LikeHash(t)}sha256LikeHash(t){const e=[];let i=5381;for(let e=0;e<t.length;e++)i=(i<<5)+i+t.charCodeAt(e),i&=4294967295;e.push(i);let s=0;for(let e=t.length-1;e>=0;e--)s=(s<<7)-s+t.charCodeAt(e),s&=4294967295;e.push(s);let n=0;for(let e=0;e<t.length;e++)n^=t.charCodeAt(e)<<e%4*8,n&=4294967295;e.push(n);let r=0;for(let e=0;e<t.length;e++)r=31*r+t.charCodeAt(e)&4294967295;e.push(r);let o=0;for(let e=0;e<t.length;e++){o=o+(4294967295&(t.charCodeAt(e)<<e%16|t.charCodeAt(e)>>>32-e%16))&4294967295}e.push(o);let h=2166136261;for(let e=0;e<t.length;e++)h=16777619*(h^t.charCodeAt(e)),h&=4294967295;e.push(h);let a=0;for(let e=0;e<t.length;e++)a=a+t.charCodeAt(e)*(e+1)&4294967295;e.push(a);let c=0;for(let e=0;e<t.length;e+=2){c=(c<<3)-c+(t.charCodeAt(e)+256*(t.charCodeAt(e+1)||0)),c&=4294967295}e.push(c);return e.map(t=>Math.abs(t).toString(16).padStart(8,"0")).join("").substring(0,64).padEnd(64,"0")}clearCache(){this.cachedDeviceInfo=null}}class s{constructor(){this.keystrokes=[],this.mouseMovements=[],this.lastKeyDownTime=new Map,this.lastKeyUpTime=null,this.isActive=!1,this.sessionStartTime=Date.now(),this.typingDwellTimes=[],this.typingFlightTimes=[],this.swipeVelocities=[],this.sessionEvents=[],this.touchStartPositions=new Map,this.keyDownHandler=t=>this.handleKeyDown(t),this.keyUpHandler=t=>this.handleKeyUp(t),this.mouseMoveHandler=t=>this.handleMouseMove(t),this.touchStartHandler=t=>this.handleTouchStart(t),this.touchEndHandler=t=>this.handleTouchEnd(t)}start(){this.isActive||("undefined"!=typeof document&&(document.addEventListener("keydown",this.keyDownHandler,{passive:!0}),document.addEventListener("keyup",this.keyUpHandler,{passive:!0}),document.addEventListener("mousemove",this.mouseMoveHandler,{passive:!0}),document.addEventListener("touchstart",this.touchStartHandler,{passive:!0}),document.addEventListener("touchend",this.touchEndHandler,{passive:!0})),this.isActive=!0,this.sessionStartTime=Date.now())}stop(){this.isActive&&("undefined"!=typeof document&&(document.removeEventListener("keydown",this.keyDownHandler),document.removeEventListener("keyup",this.keyUpHandler),document.removeEventListener("mousemove",this.mouseMoveHandler),document.removeEventListener("touchstart",this.touchStartHandler),document.removeEventListener("touchend",this.touchEndHandler)),this.isActive=!1)}getData(){const t=this.typingDwellTimes.slice(-20),e=this.typingFlightTimes.slice(-20),i=this.swipeVelocities.length>0?this.swipeVelocities.reduce((t,e)=>t+e,0)/this.swipeVelocities.length:0,s=this.calculateSessionEntropy();return{typing_dwell_ms:t.length>0?t:[],typing_flight_ms:e.length>0?e:[],swipe_velocity:i>0?i:0,session_entropy:s>=0?s:0}}reset(){this.keystrokes=[],this.mouseMovements=[],this.lastKeyDownTime.clear(),this.lastKeyUpTime=null,this.typingDwellTimes=[],this.typingFlightTimes=[],this.swipeVelocities=[],this.sessionEvents=[],this.touchStartPositions.clear(),this.sessionStartTime=Date.now()}handleKeyDown(t){if(this.shouldIgnoreKey(t))return;const e=performance.now();this.lastKeyDownTime.set(t.key,e);const i={key:t.key,timestamp:e,type:"keydown"};this.keystrokes.push(i),this.sessionEvents.push({type:"keydown",timestamp:e})}handleKeyUp(t){if(this.shouldIgnoreKey(t))return;const e=performance.now(),i=this.lastKeyDownTime.get(t.key);if(void 0!==i){const s=e-i;this.typingDwellTimes.push(s),this.lastKeyDownTime.delete(t.key)}if(null!==this.lastKeyUpTime){const t=e-this.lastKeyUpTime;this.typingFlightTimes.push(t)}this.lastKeyUpTime=e;const s={key:t.key,timestamp:e,type:"keyup"};this.keystrokes.push(s),this.sessionEvents.push({type:"keyup",timestamp:e})}handleMouseMove(t){const e={x:t.clientX,y:t.clientY,timestamp:performance.now(),type:"move"};if(this.mouseMovements.length>0){const t=this.mouseMovements[this.mouseMovements.length-1],i=e.timestamp-t.timestamp;if(i>0){const s=Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2));e.velocity=s/i}}this.mouseMovements.push(e),this.sessionEvents.push({type:"mousemove",timestamp:e.timestamp})}handleTouchStart(t){const e=performance.now();for(let i=0;i<t.touches.length;i++){const s=t.touches[i];this.touchStartPositions.set(s.identifier,{x:s.clientX,y:s.clientY,timestamp:e})}this.sessionEvents.push({type:"touchstart",timestamp:e})}handleTouchEnd(t){const e=performance.now();for(let i=0;i<t.changedTouches.length;i++){const s=t.changedTouches[i],n=this.touchStartPositions.get(s.identifier);if(n){const t=e-n.timestamp;if(t>0&&t<1e3){const e=Math.sqrt(Math.pow(s.clientX-n.x,2)+Math.pow(s.clientY-n.y,2));if(e>10){const i=e/t;this.swipeVelocities.push(i)}}this.touchStartPositions.delete(s.identifier)}}this.sessionEvents.push({type:"touchend",timestamp:e})}calculateSessionEntropy(){if(0===this.sessionEvents.length)return 0;const t={};for(const e of this.sessionEvents)t[e.type]=(t[e.type]||0)+1;const e=this.sessionEvents.length;let i=0;for(const s of Object.values(t)){const t=s/e;t>0&&(i-=t*Math.log2(t))}return i}shouldIgnoreKey(t){return["Shift","Control","Alt","Meta","CapsLock","Tab","Escape","Enter","ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","PageUp","PageDown","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12"].includes(t.key)}}class n{constructor(){this.config=null,this.isInitialized=!1,this.sessionId=null,this.deviceCollector=new i,this.behavioralCollector=new s}init(t){this.isInitialized?this.config:(this.config="string"==typeof t?{apiKey:t,endpoint:"https://app.keverd.com",debug:!1}:{endpoint:"https://app.keverd.com",debug:!1,...t},this.behavioralCollector.start(),this.sessionId=this.generateSessionId(),this.isInitialized=!0,this.config.debug)}async getVisitorData(){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");try{const t=this.deviceCollector.collect(),e=this.behavioralCollector.getData(),i={sessionId:this.sessionId||void 0,timestamp:(new Date).toISOString()},s={userId:this.config.userId,device:t,session:i,behavioral:e};return await this.sendFingerprintRequest(s)}catch(t){const e=t instanceof Error?t.message:"Unknown error";throw this.config.debug,new Error(`Failed to get visitor data: ${e}`)}}async createTransactionID(t){return(await this.getVisitorData()).session_id}async sendFingerprintRequest(t){if(!this.config)throw new Error("SDK not initialized");const e=`${this.config.endpoint||"https://app.keverd.com"}/fingerprint/score`,i={"Content-Type":"application/json","X-SDK-Source":"javascript"},s=this.config.apiKey;s&&(i["x-keverd-key"]=s,i["X-API-KEY"]=s,i.Authorization=`Bearer ${s}`);const n=await fetch(e,{method:"POST",headers:i,body:JSON.stringify(t)});if(!n.ok){const t=await n.text().catch(()=>"Unknown error");throw new Error(`HTTP ${n.status}: ${t}`)}return await n.json()}generateSessionId(){return`${Date.now()}_${Math.random().toString(36).substr(2,9)}`}destroy(){this.behavioralCollector.stop(),this.isInitialized=!1,this.config,this.config=null,this.sessionId=null}}const r=new n;return e})());
1
+ !function(t,i){"object"==typeof exports&&"object"==typeof module?module.exports=i():"function"==typeof define&&define.amd?define([],i):"object"==typeof exports?exports.FintechRisk=i():t.FintechRisk=i()}(this,()=>(()=>{"use strict";var t={d:(i,e)=>{for(var s in e)t.o(e,s)&&!t.o(i,s)&&Object.defineProperty(i,s,{enumerable:!0,get:e[s]})},o:(t,i)=>Object.prototype.hasOwnProperty.call(t,i),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"t",{value:!0})}},i={};t.r(i),t.d(i,{BehavioralCollector:()=>a,DeviceCollector:()=>e,FingerprintJSCollector:()=>O,Keverd:()=>P,KeverdSDK:()=>x,KeystrokeMonitor:()=>n,KinematicEngine:()=>s});class e{constructor(){this.cachedDeviceInfo=null}collect(){if(this.cachedDeviceInfo)return this.cachedDeviceInfo;const t=this.generateDeviceFingerprint(),i=this.generateDeviceId(t);return this.cachedDeviceInfo={deviceId:i,fingerprint:t,manufacturer:this.getManufacturer(),model:this.getModel(),brand:this.getBrand(),device:this.getDevice(),product:this.getProduct(),hardware:this.getHardware(),sdkVersion:"1.0.0",osVersion:this.getOSVersion(),screenWidth:String(screen.width),screenHeight:String(screen.height),screenDensity:this.getScreenDensity(),locale:navigator.language||navigator.languages?.[0]||"en",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},this.cachedDeviceInfo}generateDeviceFingerprint(){const t=[],i=this.getCanvasFingerprint();i&&t.push(i);const e=this.getWebGLFingerprint();if(e&&t.push(e),t.push(navigator.userAgent),t.push(navigator.language||navigator.languages?.[0]||""),t.push(`${screen.width}x${screen.height}x${screen.colorDepth}`),t.push(String((new Date).getTimezoneOffset())),t.push(navigator.platform),t.push(String(navigator.hardwareConcurrency||0)),"deviceMemory"in navigator&&t.push(String(navigator.deviceMemory)),"maxTouchPoints"in navigator&&t.push(String(navigator.maxTouchPoints)),navigator.plugins&&navigator.plugins.length>0){const i=Array.from(navigator.plugins).slice(0,3).map(t=>t.name).join(",");t.push(i)}const s=t.join("|");return this.hashString(s)}getCanvasFingerprint(){try{const t=document.createElement("canvas"),i=t.getContext("2d");return i?(t.width=200,t.height=50,i.textBaseline="top",i.font="14px Arial",i.fillStyle="#f60",i.fillRect(125,1,62,20),i.fillStyle="#069",i.fillText("KeverdFingerprint",2,15),i.fillStyle="rgba(102, 204, 0, 0.7)",i.fillText("KeverdFingerprint",4,17),this.hashString(t.toDataURL())):""}catch(t){return""}}getWebGLFingerprint(){try{const t=document.createElement("canvas"),i=t.getContext("webgl")||t.getContext("experimental-webgl");if(!i)return"";const e=i.getExtension("WEBGL_debug_renderer_info");if(e){const t=i.getParameter(e.UNMASKED_VENDOR_WEBGL),s=i.getParameter(e.UNMASKED_RENDERER_WEBGL);return this.hashString(`${t}|${s}`)}const s=i.getParameter(i.VERSION),n=i.getParameter(i.VENDOR);return this.hashString(`${s}|${n}`)}catch(t){return""}}generateDeviceId(t){return t.substring(0,32)}getManufacturer(){const t=navigator.userAgent.toLowerCase();if(t.includes("iphone")||t.includes("ipad"))return"Apple";if(t.includes("android")){const i=t.match(/(?:^|\s)([a-z]+)(?:\s|$)/);return i?i[1].charAt(0).toUpperCase()+i[1].slice(1):void 0}}getModel(){const t=navigator.userAgent.match(/(iPhone|iPad|Android)[\s\/]+([\w]+)/i);return t?t[2]:void 0}getBrand(){return this.getManufacturer()}getDevice(){const t=navigator.userAgent.toLowerCase();return t.includes("mobile")?"mobile":t.includes("tablet")?"tablet":"desktop"}getProduct(){const t=navigator.userAgent.match(/(iPhone|iPad|Android|Windows|Mac|Linux)/i);return t?t[1]:void 0}getHardware(){const t=navigator.userAgent.match(/\(([^)]+)\)/);return t?t[1]:void 0}getOSVersion(){const t=navigator.userAgent,i=[/OS\s+([\d_]+)/i,/Android\s+([\d.]+)/i,/Windows\s+([\d.]+)/i,/Mac\s+OS\s+X\s+([\d_]+)/i,/Linux/i];for(const e of i){const i=t.match(e);if(i)return i[1]?.replace(/_/g,".")||i[0]}}getScreenDensity(){if(window.devicePixelRatio)return String(window.devicePixelRatio)}hashString(t){return this.sha256LikeHash(t)}sha256LikeHash(t){const i=[];let e=5381;for(let i=0;i<t.length;i++)e=(e<<5)+e+t.charCodeAt(i),e&=4294967295;i.push(e);let s=0;for(let i=t.length-1;i>=0;i--)s=(s<<7)-s+t.charCodeAt(i),s&=4294967295;i.push(s);let n=0;for(let i=0;i<t.length;i++)n^=t.charCodeAt(i)<<i%4*8,n&=4294967295;i.push(n);let r=0;for(let i=0;i<t.length;i++)r=31*r+t.charCodeAt(i)&4294967295;i.push(r);let o=0;for(let i=0;i<t.length;i++){o=o+(4294967295&(t.charCodeAt(i)<<i%16|t.charCodeAt(i)>>>32-i%16))&4294967295}i.push(o);let a=2166136261;for(let i=0;i<t.length;i++)a=16777619*(a^t.charCodeAt(i)),a&=4294967295;i.push(a);let h=0;for(let i=0;i<t.length;i++)h=h+t.charCodeAt(i)*(i+1)&4294967295;i.push(h);let c=0;for(let i=0;i<t.length;i+=2){c=(c<<3)-c+(t.charCodeAt(i)+256*(t.charCodeAt(i+1)||0)),c&=4294967295}i.push(c);return i.map(t=>Math.abs(t).toString(16).padStart(8,"0")).join("").substring(0,64).padEnd(64,"0")}clearCache(){this.cachedDeviceInfo=null}}class s{constructor(t={}){this.featureVectors=[],this.pointerQueue=[],this.lastVelocity=0,this.lastAcceleration=0,this.lastAngle=0,this.lastPoint=null,this.secondLastPoint=null,this.rafId=null,this.maxSwipeVelocity=0,this.isActive=!1,this.clickCount=0,this.rightClickCount=0,this.doubleClickCount=0,this.totalMouseDistance=0,this.lastClickTime=0,this.scrollDistance=0,this.lastScrollTop=0,this.touchEventCount=0,this.mouseMoveHandler=t=>this.enqueuePoint(t,"move"),this.mouseDownHandler=t=>{this.enqueuePoint(t,"down"),this.handleClick(t)},this.mouseUpHandler=t=>this.enqueuePoint(t,"up"),this.contextMenuHandler=t=>this.handleRightClick(t),this.scrollHandler=()=>this.handleScroll(),this.touchStartHandler=()=>this.handleTouch(),this.touchMoveHandler=()=>this.handleTouch(),this.touchEndHandler=()=>this.handleTouch(),this.onEvent=t.onEvent,this.maskValue=t.maskValue??-1}start(){this.isActive||"undefined"==typeof document||(document.addEventListener("mousemove",this.mouseMoveHandler,{passive:!0}),document.addEventListener("mousedown",this.mouseDownHandler,{passive:!0}),document.addEventListener("mouseup",this.mouseUpHandler,{passive:!0}),document.addEventListener("contextmenu",this.contextMenuHandler,{passive:!0}),window.addEventListener("scroll",this.scrollHandler,{passive:!0}),document.addEventListener("touchstart",this.touchStartHandler,{passive:!0}),document.addEventListener("touchmove",this.touchMoveHandler,{passive:!0}),document.addEventListener("touchend",this.touchEndHandler,{passive:!0}),this.lastScrollTop=window.pageYOffset||document.documentElement.scrollTop,this.isActive=!0)}stop(){this.isActive&&"undefined"!=typeof document&&(document.removeEventListener("mousemove",this.mouseMoveHandler),document.removeEventListener("mousedown",this.mouseDownHandler),document.removeEventListener("mouseup",this.mouseUpHandler),document.removeEventListener("contextmenu",this.contextMenuHandler),window.removeEventListener("scroll",this.scrollHandler),document.removeEventListener("touchstart",this.touchStartHandler),document.removeEventListener("touchmove",this.touchMoveHandler),document.removeEventListener("touchend",this.touchEndHandler),null!==this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.isActive=!1)}getVectors(){return this.featureVectors}getSuspiciousSwipeVelocity(){return this.maxSwipeVelocity}getMouseSignals(){const t=this.featureVectors.length>0?this.featureVectors.reduce((t,i)=>t+i.velocity,0)/this.featureVectors.length:0,i=window.pageYOffset||document.documentElement.scrollTop,e=Math.abs(i-this.lastScrollTop),s=i>this.lastScrollTop?"down":"up";return{totalDistance:this.totalMouseDistance,averageVelocity:t,clickCount:this.clickCount,rightClickCount:this.rightClickCount,doubleClickCount:this.doubleClickCount,scrollDistance:this.scrollDistance+e,scrollDirection:s,touchEvents:this.touchEventCount}}reset(){this.featureVectors=[],this.pointerQueue=[],this.lastVelocity=0,this.lastAcceleration=0,this.lastAngle=0,this.lastPoint=null,this.secondLastPoint=null,this.maxSwipeVelocity=0,this.clickCount=0,this.rightClickCount=0,this.doubleClickCount=0,this.totalMouseDistance=0,this.lastClickTime=0,this.scrollDistance=0,this.lastScrollTop=0,this.touchEventCount=0}enqueuePoint(t,i){const e={x:t.clientX,y:t.clientY,timestamp:performance.now(),type:i};this.pointerQueue.push(e),this.pointerQueue.length>200&&this.pointerQueue.shift(),this.onEvent&&this.onEvent("move"===i?"mousemove":"down"===i?"mousedown":"mouseup"),this.scheduleProcess()}scheduleProcess(){null===this.rafId&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null,this.processQueue(),this.pointerQueue.length>0&&this.scheduleProcess()}))}processQueue(){for(;this.pointerQueue.length>0;){const t=this.pointerQueue.shift();this.computeFeatures(t),this.secondLastPoint=this.lastPoint,this.lastPoint=t}}computeFeatures(t){if(!this.lastPoint)return this.lastPoint=t,void(this.lastAngle=0);const i=t.timestamp-this.lastPoint.timestamp;if(i<=0)return;const e=t.x-this.lastPoint.x,s=t.y-this.lastPoint.y,n=Math.sqrt(e*e+s*s);this.totalMouseDistance+=n;const r=n/i,o=(r-this.lastVelocity)/i,a=(o-this.lastAcceleration)/i,h=Math.atan2(s,e),c=this.normalizeAngle(h-this.lastAngle)/i,l=this.calculateCurvature(t);this.featureVectors.push({timestamp:t.timestamp,velocity:r,acceleration:o,jerk:a,curvature:l,angularVelocity:c}),this.maxSwipeVelocity=Math.max(this.maxSwipeVelocity,r),r>2.5&&this.featureVectors.push({timestamp:t.timestamp,velocity:r,acceleration:o,jerk:a,curvature:l,angularVelocity:1.2*c}),this.featureVectors.length>200&&this.featureVectors.splice(0,this.featureVectors.length-200),this.lastVelocity=r,this.lastAcceleration=o,this.lastAngle=h}calculateCurvature(t){if(!this.lastPoint||!this.secondLastPoint)return 0;const i=this.secondLastPoint,e=this.lastPoint,s=t,n=Math.hypot(s.x-i.x,s.y-i.y),r=Math.hypot(e.x-i.x,e.y-i.y)+Math.hypot(s.x-e.x,s.y-e.y);return 0===n?0:(r-n)/n}normalizeAngle(t){for(;t>Math.PI;)t-=2*Math.PI;for(;t<-Math.PI;)t+=2*Math.PI;return t}handleClick(t){const i=performance.now();i-this.lastClickTime<500?this.doubleClickCount++:this.clickCount++,this.lastClickTime=i}handleRightClick(t){this.rightClickCount++}handleScroll(){const t=window.pageYOffset||document.documentElement.scrollTop,i=Math.abs(t-this.lastScrollTop);this.scrollDistance+=i,this.lastScrollTop=t}handleTouch(){this.touchEventCount++}}class n{constructor(t={}){this.keyDownTimes=new Map,this.lastKeyUpTime=null,this.lastKeyDownTime=null,this.featureVectors=[],this.dwellTimes=[],this.flightTimes=[],this.digraphLatencies=[],this.isActive=!1,this.keydownCount=0,this.keyupCount=0,this.specialKeyCount=0,this.lastKeystrokeTime=null,this.pauseCount=0,this.PAUSE_THRESHOLD=2e3,this.keystrokeTimestamps=[],this.keyDownHandler=t=>this.handleKeyDown(t),this.keyUpHandler=t=>this.handleKeyUp(t),this.onEvent=t.onEvent}start(){this.isActive||"undefined"==typeof document||(document.addEventListener("keydown",this.keyDownHandler,{passive:!0,capture:!0}),document.addEventListener("keyup",this.keyUpHandler,{passive:!0,capture:!0}),this.isActive=!0)}stop(){this.isActive&&"undefined"!=typeof document&&(document.removeEventListener("keydown",this.keyDownHandler,!0),document.removeEventListener("keyup",this.keyUpHandler,!0),this.isActive=!1)}getVectors(){return this.featureVectors}getDwellTimes(t=50){return this.dwellTimes.slice(-t)}getFlightTimes(t=50){return this.flightTimes.slice(-t)}getKeyboardSignals(){let t=0;if(this.keystrokeTimestamps.length>1){const i=(this.keystrokeTimestamps[this.keystrokeTimestamps.length-1]-this.keystrokeTimestamps[0])/6e4;i>0&&(t=this.keystrokeTimestamps.length/i)}const i=this.keydownCount,e=i>0?this.getBackspaceCount()/i:0;return{keydownCount:this.keydownCount,keyupCount:this.keyupCount,specialKeyCount:this.specialKeyCount,typingSpeed:t,pauseCount:this.pauseCount,backspaceRatio:e}}getBackspaceCount(){return 0}reset(){this.keyDownTimes.clear(),this.lastKeyUpTime=null,this.lastKeyDownTime=null,this.featureVectors=[],this.dwellTimes=[],this.flightTimes=[],this.digraphLatencies=[],this.keydownCount=0,this.keyupCount=0,this.specialKeyCount=0,this.lastKeystrokeTime=null,this.pauseCount=0,this.keystrokeTimestamps=[]}handleKeyDown(t){if(!this.isTargetField(t))return;const i=performance.now();if(this.keydownCount++,this.keystrokeTimestamps.push(i),(t.ctrlKey||t.altKey||t.shiftKey||t.metaKey)&&this.specialKeyCount++,null!==this.lastKeystrokeTime&&i-this.lastKeystrokeTime>this.PAUSE_THRESHOLD&&this.pauseCount++,this.lastKeystrokeTime=i,null!==this.lastKeyUpTime){const t=i-this.lastKeyUpTime;this.flightTimes.push(t),this.appendVector({dwellTime:-1,flightTime:t,digraphLatency:-1,timestamp:i})}if(null!==this.lastKeyDownTime){const t=i-this.lastKeyDownTime;this.digraphLatencies.push(t),this.appendVector({dwellTime:-1,flightTime:-1,digraphLatency:t,timestamp:i})}this.lastKeyDownTime=i,this.keyDownTimes.set(t.code,i),this.onEvent&&this.onEvent("keydown")}handleKeyUp(t){if(!this.isTargetField(t))return;const i=performance.now();this.keyupCount++;const e=this.keyDownTimes.get(t.code);if(void 0!==e){const s=i-e;this.dwellTimes.push(s),this.appendVector({dwellTime:s,flightTime:-1,digraphLatency:-1,timestamp:i}),this.keyDownTimes.delete(t.code)}this.lastKeyUpTime=i,this.onEvent&&this.onEvent("keyup")}appendVector(t){this.featureVectors.push(t),this.featureVectors.length>200&&this.featureVectors.splice(0,this.featureVectors.length-200)}isTargetField(t){const i=t.target;if(!i)return!1;return i.isContentEditable||["INPUT","TEXTAREA"].includes(i.tagName)}}const r=-1,o=["velocity","acceleration","jerk","curvature","angularVelocity","dwell","flight","digraphLatency"];class a{constructor(){this.isActive=!1,this.sessionEvents=[],this.trackEvent=t=>{this.sessionEvents.push({type:t,timestamp:performance.now()}),this.sessionEvents.length>500&&this.sessionEvents.shift()},this.kinematicEngine=new s({onEvent:this.trackEvent}),this.keystrokeMonitor=new n({onEvent:this.trackEvent})}start(){this.isActive||(this.kinematicEngine.start(),this.keystrokeMonitor.start(),this.isActive=!0)}stop(){this.isActive&&(this.kinematicEngine.stop(),this.keystrokeMonitor.stop(),this.isActive=!1)}reset(){this.sessionEvents=[],this.kinematicEngine.reset(),this.keystrokeMonitor.reset()}getData(){const t=this.kinematicEngine.getVectors(),i=this.keystrokeMonitor.getVectors(),e=[...t.map(t=>({timestamp:t.timestamp,values:[t.velocity,t.acceleration,t.jerk,t.curvature,t.angularVelocity,r,r,r]})),...i.map(t=>({timestamp:t.timestamp,values:[r,r,r,r,r,t.dwellTime,t.flightTime,t.digraphLatency]}))].sort((t,i)=>t.timestamp-i.timestamp),s=this.buildSequence(e),n=this.kinematicEngine.getSuspiciousSwipeVelocity(),o=this.calculateSessionEntropy();return{typing_dwell_ms:this.keystrokeMonitor.getDwellTimes(),typing_flight_ms:this.keystrokeMonitor.getFlightTimes(),swipe_velocity:n,suspicious_swipe_velocity:n,session_entropy:o,behavioral_vectors:s}}buildSequence(t){const i=[],e=Math.max(0,t.length-50),s=t.slice(e);for(const t of s)i.push(t.values);for(;i.length<50;)i.unshift(new Array(o.length).fill(r));return{featureNames:[...o],windowSize:50,maskValue:r,sequence:i}}calculateSessionEntropy(){if(0===this.sessionEvents.length)return 0;const t={};this.sessionEvents.forEach(i=>{t[i.type]=(t[i.type]||0)+1});const i=this.sessionEvents.length;return Object.values(t).reduce((t,e)=>{const s=e/i;return s>0?t-s*Math.log2(s):t},0)}getMouseSignals(){return this.kinematicEngine.getMouseSignals()}getKeyboardSignals(){return this.keystrokeMonitor.getKeyboardSignals()}}class h{constructor(){this.cachedFingerprint=null}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{const i=document.createElement("canvas");i.width=200,i.height=50;const e=i.getContext("2d");if(!e)return null;e.textBaseline="top",e.font="14px Arial",e.textBaseline="alphabetic",e.fillStyle="#f60",e.fillRect(125,1,62,20),e.fillStyle="#069",e.fillText("KeverdFingerprint",2,15),e.fillStyle="rgba(102, 204, 0, 0.7)",e.fillText("KeverdFingerprint",4,17);const s=e.createLinearGradient(0,0,200,50);s.addColorStop(0,"rgba(255, 0, 0, 0.5)"),s.addColorStop(1,"rgba(0, 0, 255, 0.5)"),e.fillStyle=s,e.fillRect(0,0,200,50),e.strokeStyle="#000",e.lineWidth=2,e.beginPath(),e.arc(100,25,20,0,2*Math.PI),e.stroke(),e.font="12px Verdana",e.fillStyle="#000",e.fillText("CanvasFP",150,30);const n=i.toDataURL(),r=this.hashString(n),o=performance.now()-t;return this.cachedFingerprint={value:r,duration:Math.round(100*o)/100},this.cachedFingerprint}catch(t){return null}}hashString(t){let i=0;for(let e=0;e<t.length;e++){i=(i<<5)-i+t.charCodeAt(e),i&=i}return Math.abs(i).toString(16).padStart(8,"0")}clearCache(){this.cachedFingerprint=null}}class c{constructor(){this.cachedFingerprint=null}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{const i=document.createElement("canvas"),e=i.getContext("webgl")||i.getContext("experimental-webgl");if(!e)return null;const s=e.getExtension("WEBGL_debug_renderer_info");let n=null,r=null;s?(n=e.getParameter(s.UNMASKED_VENDOR_WEBGL)||null,r=e.getParameter(s.UNMASKED_RENDERER_WEBGL)||null):(n=e.getParameter(e.VENDOR)||null,r=e.getParameter(e.RENDERER)||null);const o=e.getParameter(e.VERSION)||null,a=e.getParameter(e.SHADING_LANGUAGE_VERSION)||null,h=[];try{const t=e.getSupportedExtensions();t&&h.push(...t)}catch(t){}const c={maxTextureSize:e.getParameter(e.MAX_TEXTURE_SIZE),maxVertexAttribs:e.getParameter(e.MAX_VERTEX_ATTRIBS),maxViewportDims:e.getParameter(e.MAX_VIEWPORT_DIMS),maxTextureImageUnits:e.getParameter(e.MAX_TEXTURE_IMAGE_UNITS),maxCombinedTextureImageUnits:e.getParameter(e.MAX_COMBINED_TEXTURE_IMAGE_UNITS),maxFragmentUniformVectors:e.getParameter(e.MAX_FRAGMENT_UNIFORM_VECTORS),maxVaryingVectors:e.getParameter(e.MAX_VARYING_VECTORS),aliasedLineWidthRange:e.getParameter(e.ALIASED_LINE_WIDTH_RANGE),aliasedPointSizeRange:e.getParameter(e.ALIASED_POINT_SIZE_RANGE)},l={};try{const t=e.createShader(e.VERTEX_SHADER);if(t){e.shaderSource(t,"precision mediump float;"),e.compileShader(t);const i=e.createShader(e.FRAGMENT_SHADER);i&&(e.shaderSource(i,"precision mediump float;"),e.compileShader(i),l.float=e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)?.precision?.toString()||"unknown",l.int=e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT)?.precision?.toString()||"unknown")}}catch(t){}const u=performance.now()-t;return this.cachedFingerprint={vendor:n,renderer:r,version:o,shadingLanguageVersion:a,extensions:h.sort(),parameters:c,precision:l,duration:Math.round(100*u)/100},this.cachedFingerprint}catch(t){return null}}clearCache(){this.cachedFingerprint=null}}class l{constructor(){this.cachedFingerprint=null}async collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{const i=window.AudioContext||window.webkitAudioContext||window.mozAudioContext;if(!i)return null;const e=new i,s=e.createOscillator(),n=e.createAnalyser(),r=e.createGain(),o=e.createScriptProcessor(4096,1,1);return n.fftSize=2048,n.smoothingTimeConstant=.8,s.connect(n),n.connect(o),o.connect(r),r.connect(e.destination),s.type="triangle",s.frequency.value=1e4,new Promise(i=>{const n=[];let a=0;o.onaudioprocess=r=>{const o=r.inputBuffer.getChannelData(0);let h=0;for(let t=0;t<o.length;t++)h+=o[t]*o[t];const c=Math.sqrt(h/o.length);if(n.push(c),a++,a>=5){s.stop(),e.close();const r=this.calculateFingerprint(n),o=performance.now()-t;this.cachedFingerprint={value:r,duration:Math.round(100*o)/100},i(this.cachedFingerprint)}},s.start(0),r.gain.value=0,setTimeout(()=>{if(!this.cachedFingerprint){s.stop(),e.close();const n=this.getFallbackFingerprint(e),r=performance.now()-t;this.cachedFingerprint={value:n,duration:Math.round(100*r)/100},i(this.cachedFingerprint)}},1e3)})}catch(t){return null}}calculateFingerprint(t){if(0===t.length)return 0;const i=t.reduce((t,i)=>t+i,0)/t.length,e=t.reduce((t,e)=>t+Math.pow(e-i,2),0)/t.length,s=Math.sqrt(e),n=1e6*i+1e3*s+t.length;return Math.round(100*n)/100}getFallbackFingerprint(t){const i=t.sampleRate||44100,e=t.state||"unknown",s=(i.toString()+e).split("").reduce((t,i)=>(t<<5)-t+i.charCodeAt(0),0);return Math.abs(s)}clearCache(){this.cachedFingerprint=null}}class u{constructor(){this.cachedFingerprint=null,this.testFonts=["Arial","Verdana","Times New Roman","Courier New","Georgia","Palatino","Garamond","Bookman","Comic Sans MS","Trebuchet MS","Arial Black","Impact","Tahoma","Lucida Console","Lucida Sans Unicode","MS Sans Serif","MS Serif","Symbol","Webdings","Wingdings","Monaco","Menlo","Consolas","Courier","Helvetica","Helvetica Neue","Roboto","Open Sans","Lato","Montserrat"]}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{const i=document.createElement("canvas").getContext("2d");if(!i)return null;const e="monospace",s="mmmmmmmmmmlli",n="72px";i.font=`${n} ${e}`;const r=i.measureText(s).width,o=[],a=[];for(const t of this.testFonts){i.font=`${n} ${t}, ${e}`;const h=i.measureText(s).width;Math.abs(h-r)>1?o.push(t):a.push(t)}const h=performance.now()-t;return this.cachedFingerprint={availableFonts:o.sort(),missingFonts:a.sort(),duration:Math.round(100*h)/100},this.cachedFingerprint}catch(t){return null}}clearCache(){this.cachedFingerprint=null}}class d{constructor(){this.cachedFingerprint=null}async collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{if(!navigator.mediaDevices||!navigator.mediaDevices.enumerateDevices)return null;let i=!1;try{const t=await navigator.mediaDevices.getUserMedia({audio:!0,video:!1});i=!0,t.getTracks().forEach(t=>t.stop())}catch(t){i=!1}const e=await navigator.mediaDevices.enumerateDevices(),s=[],n=[],r=[];e.forEach(t=>{const e={deviceId:t.deviceId,kind:t.kind,label:i?t.label:"",groupId:t.groupId,toJSON:()=>({deviceId:t.deviceId,kind:t.kind,label:i?t.label:"",groupId:t.groupId})};switch(t.kind){case"audioinput":s.push(e);break;case"audiooutput":n.push(e);break;case"videoinput":r.push(e)}});const o=performance.now()-t;return this.cachedFingerprint={audioInputs:s,audioOutputs:n,videoInputs:r,hasPermission:i,duration:Math.round(100*o)/100},this.cachedFingerprint}catch(t){return null}}clearCache(){this.cachedFingerprint=null}}class m{constructor(){this.cachedFingerprint=null}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now(),i={width:screen.width,height:screen.height,availWidth:screen.availWidth,availHeight:screen.availHeight,colorDepth:screen.colorDepth,pixelDepth:screen.pixelDepth,pixelRatio:window.devicePixelRatio||1,orientation:this.getOrientation(),orientationAngle:this.getOrientationAngle(),duration:0};return i.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=i,i}getOrientation(){if("orientation"in screen){const t=screen.orientation;if(t&&t.type)return t.type}if("orientation"in window){const t=window.orientation;if(void 0!==t){if(0===t||180===t)return"portrait";if(90===t||-90===t)return"landscape"}}if(window.matchMedia){if(window.matchMedia("(orientation: portrait)").matches)return"portrait";if(window.matchMedia("(orientation: landscape)").matches)return"landscape"}return null}getOrientationAngle(){if("orientation"in screen){const t=screen.orientation;if(t&&"number"==typeof t.angle)return t.angle}if("orientation"in window){const t=window.orientation;if("number"==typeof t)return t}return null}clearCache(){this.cachedFingerprint=null}}class p{constructor(){this.cachedFingerprint=null}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now(),i=Intl.DateTimeFormat().resolvedOptions().timeZone,e=(new Date).getTimezoneOffset(),s=Intl.DateTimeFormat().resolvedOptions(),n=s.locale,r=navigator.languages||[navigator.language],o=this.getDateFormat(),a=this.getTimeFormat(),h=this.getNumberFormat(),c=s.calendar||null,l={timezone:i,timezoneOffset:e,locale:n,locales:r.slice(0,5),dateFormat:o,timeFormat:a,numberFormat:h,calendar:c,duration:0};return l.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=l,l}getDateFormat(){try{const t=(new Intl.DateTimeFormat).format(new Date(2023,0,15));return t.includes("/")?"numeric":t.includes("-")?"iso":t.includes(".")?"european":"unknown"}catch{return"unknown"}}getTimeFormat(){try{const t=new Intl.DateTimeFormat(void 0,{hour:"numeric",minute:"numeric"}).format(new Date(2023,0,15,13,30));return t.toLowerCase().includes("am")||t.toLowerCase().includes("pm")?"12h":"24h"}catch{return"unknown"}}getNumberFormat(){try{const t=(new Intl.NumberFormat).format(1234.56);return t.includes(",")?"european":t.includes(".")?"american":"unknown"}catch{return"unknown"}}clearCache(){this.cachedFingerprint=null}}class g{constructor(){this.cachedFingerprint=null}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{if(!navigator.plugins||0===navigator.plugins.length)return null;const i=[],e=new Set;for(let t=0;t<Math.min(navigator.plugins.length,10);t++){const s=navigator.plugins[t];if(!s)continue;const n=[];for(let t=0;t<Math.min(s.length,5);t++){const i=s[t];i&&i.type&&(n.push(i.type),e.add(i.type))}i.push({name:s.name||"Unknown",description:s.description||"",mimeTypes:n})}const s={plugins:i,mimeTypes:Array.from(e).sort(),duration:0};return s.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=s,s}catch(t){return null}}clearCache(){this.cachedFingerprint=null}}class w{constructor(){this.cachedFingerprint=null}async collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{const i=await this.getBatteryManager();if(!i)return null;const e={level:i.level,charging:i.charging,chargingTime:i.chargingTime,dischargingTime:i.dischargingTime,duration:0};return e.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=e,e}catch(t){return null}}async getBatteryManager(){if("getBattery"in navigator)try{return await navigator.getBattery()}catch(t){}if("webkitGetBattery"in navigator)try{return await navigator.webkitGetBattery()}catch(t){}if("mozGetBattery"in navigator)try{return await navigator.mozGetBattery()}catch(t){}return null}clearCache(){this.cachedFingerprint=null}}class f{constructor(){this.cachedFingerprint=null}async collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now(),i={localStorage:await this.checkLocalStorage(),sessionStorage:await this.checkSessionStorage(),indexedDB:this.checkIndexedDB(),webSQL:this.checkWebSQL(),duration:0};return i.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=i,i}async checkLocalStorage(){let t=!1,i=null,e=null;try{const s="__localStorage_test__";if(localStorage.setItem(s,s),localStorage.removeItem(s),t=!0,"storage"in navigator&&"estimate"in navigator.storage)try{const t=await navigator.storage.estimate();t&&(i=t.quota||null,e=t.usage||null)}catch(t){}}catch(i){t=!1}return{available:t,quota:i,usage:e}}async checkSessionStorage(){let t=!1,i=null,e=null;try{const s="__sessionStorage_test__";if(sessionStorage.setItem(s,s),sessionStorage.removeItem(s),t=!0,"storage"in navigator&&"estimate"in navigator.storage)try{const t=await navigator.storage.estimate();t&&(i=t.quota||null,e=t.usage||null)}catch(t){}}catch(i){t=!1}return{available:t,quota:i,usage:e}}checkIndexedDB(){return{available:"indexedDB"in window&&!!window.indexedDB}}checkWebSQL(){return{available:"openDatabase"in window&&!!window.openDatabase}}clearCache(){this.cachedFingerprint=null}}class v{constructor(){this.cachedFingerprint=null}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now(),i={hardwareConcurrency:navigator.hardwareConcurrency||0,deviceMemory:this.getDeviceMemory(),performanceMemory:this.getPerformanceMemory(),duration:0};return i.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=i,i}getDeviceMemory(){return"deviceMemory"in navigator&&navigator.deviceMemory?navigator.deviceMemory:null}getPerformanceMemory(){if("memory"in performance){const t=performance.memory;return{jsHeapSizeLimit:t.jsHeapSizeLimit||null,totalJSHeapSize:t.totalJSHeapSize||null,usedJSHeapSize:t.usedJSHeapSize||null}}return{jsHeapSizeLimit:null,totalJSHeapSize:null,usedJSHeapSize:null}}clearCache(){this.cachedFingerprint=null}}class y{constructor(){this.cachedFingerprint=null}collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now(),i={maxTouchPoints:navigator.maxTouchPoints||0,touchSupport:this.checkTouchSupport(),pointerSupport:this.checkPointerSupport(),pointerTypes:this.getPointerTypes(),duration:0};return i.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=i,i}checkTouchSupport(){return"ontouchstart"in window||navigator.maxTouchPoints>0||!!window.DocumentTouch&&document instanceof window.DocumentTouch}checkPointerSupport(){return"PointerEvent"in window||"MSPointerEvent"in window}getPointerTypes(){const t=[];return"PointerEvent"in window&&(navigator.maxTouchPoints>0&&t.push("touch"),t.push("mouse"),"pen"in navigator&&t.push("pen")),t}clearCache(){this.cachedFingerprint=null}}class S{constructor(){this.cachedFingerprint=null}async collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{if(!("permissions"in navigator))return null;const i=navigator.permissions,e={camera:await this.queryPermission(i,"camera"),microphone:await this.queryPermission(i,"microphone"),notifications:await this.queryPermission(i,"notifications"),geolocation:await this.queryPermission(i,"geolocation"),persistentStorage:await this.queryPermission(i,"persistent-storage"),duration:0};return e.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=e,e}catch(t){return null}}async queryPermission(t,i){try{return(await t.query({name:i})).state||null}catch(t){return null}}clearCache(){this.cachedFingerprint=null}}class b{constructor(){this.cachedFingerprint=null}async collect(){if(this.cachedFingerprint)return this.cachedFingerprint;const t=performance.now();try{const i=window.RTCPeerConnection||window.webkitRTCPeerConnection||window.mozRTCPeerConnection;if(!i)return null;const e=[];let s=null;const n=new i({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});n.onicecandidate=t=>{if(t.candidate){const i=t.candidate.candidate.match(/([0-9]{1,3}\.){3}[0-9]{1,3}/);if(i){const t=i[0];this.isLocalIP(t)?e.includes(t)||e.push(t):s=t}}},n.createDataChannel("");const r=await n.createOffer();await n.setLocalDescription(r),await new Promise(t=>{const i=setTimeout(()=>{t()},2e3);n.onicegatheringstatechange=()=>{"complete"===n.iceGatheringState&&(clearTimeout(i),t())},"complete"===n.iceGatheringState&&(clearTimeout(i),t())}),n.close();const o={localIPs:e.sort(),publicIP:s,duration:0};return o.duration=Math.round(100*(performance.now()-t))/100,this.cachedFingerprint=o,o}catch(t){return null}}isLocalIP(t){if("127.0.0.1"===t||"::1"===t)return!0;const i=t.split(".");if(4===i.length){const t=parseInt(i[0],10),e=parseInt(i[1],10);if(10===t)return!0;if(172===t&&e>=16&&e<=31)return!0;if(192===t&&168===e)return!0;if(169===t&&254===e)return!0}return!1}clearCache(){this.cachedFingerprint=null}}class C{generate(t){const i=[];t.canvas?.value&&i.push(`canvas:${t.canvas.value}`),t.webgl&&(t.webgl.vendor&&i.push(`webgl_vendor:${t.webgl.vendor}`),t.webgl.renderer&&i.push(`webgl_renderer:${t.webgl.renderer}`),t.webgl.extensions.length>0&&i.push(`webgl_ext:${t.webgl.extensions.slice(0,10).join(",")}`)),t.audio?.value&&i.push(`audio:${t.audio.value}`),t.screen&&(i.push(`screen:${t.screen.width}x${t.screen.height}x${t.screen.pixelRatio}`),i.push(`color:${t.screen.colorDepth}`)),t.timezone&&(i.push(`tz:${t.timezone.timezone}`),i.push(`locale:${t.timezone.locale}`)),t.cpu&&(i.push(`cpu:${t.cpu.hardwareConcurrency}`),t.cpu.deviceMemory&&i.push(`memory:${t.cpu.deviceMemory}`)),t.touch&&i.push(`touch:${t.touch.maxTouchPoints}`),i.push(`ua:${navigator.userAgent}`),i.push(`lang:${navigator.language}`),i.push(`platform:${navigator.platform}`),t.fonts&&t.fonts.availableFonts.length>0&&i.push(`fonts:${t.fonts.availableFonts.slice(0,20).join(",")}`);const e=i.join("|");return this.sha256Hash(e)}calculateConfidence(t){let i=0,e=0;const s={canvas:20,webgl:20,audio:15,screen:10,timezone:10,cpu:10,fonts:10,touch:5,storage:5,permissions:5,webrtc:5,mediaDevices:5,battery:3,plugins:3};return Object.keys(s).forEach(n=>{e+=s[n],t[n]&&(i+=s[n])}),e>0?Math.min(i/e,1):0}sha256Hash(t){return"undefined"!=typeof crypto&&crypto.subtle,this.sha256LikeHash(t)}sha256LikeHash(t){const i=[];let e=5381;for(let i=0;i<t.length;i++)e=(e<<5)+e+t.charCodeAt(i),e&=4294967295;i.push(e);let s=0;for(let i=t.length-1;i>=0;i--)s=(s<<7)-s+t.charCodeAt(i),s&=4294967295;i.push(s);let n=0;for(let i=0;i<t.length;i++)n^=t.charCodeAt(i)<<i%4*8,n&=4294967295;i.push(n);let r=0;for(let i=0;i<t.length;i++)r=31*r+t.charCodeAt(i)&4294967295;i.push(r);let o=0;for(let i=0;i<t.length;i++){o=o+(4294967295&(t.charCodeAt(i)<<i%16|t.charCodeAt(i)>>>32-i%16))&4294967295}i.push(o);let a=2166136261;for(let i=0;i<t.length;i++)a=16777619*(a^t.charCodeAt(i)),a&=4294967295;i.push(a);let h=0;for(let i=0;i<t.length;i++)h=h+t.charCodeAt(i)*(i+1)&4294967295;i.push(h);let c=0;for(let i=0;i<t.length;i+=2){c=(c<<3)-c+(t.charCodeAt(i)+256*(t.charCodeAt(i+1)||0)),c&=4294967295}i.push(c);return i.map(t=>Math.abs(t).toString(16).padStart(8,"0")).join("").substring(0,64).padEnd(64,"0")}}class k{constructor(){this.cachedData=null,this.collectionStartTime=0,this.collectors={canvas:new h,webgl:new c,audio:new l,fonts:new u,mediaDevices:new d,screen:new m,timezone:new p,plugins:new g,battery:new w,storage:new f,cpu:new v,touch:new y,permissions:new S,webrtc:new b},this.visitorIDGenerator=new C}async collect(){if(this.cachedData)return this.cachedData;this.collectionStartTime=performance.now();const t={};try{t.canvas=this.collectors.canvas.collect()||void 0}catch(t){}try{t.webgl=this.collectors.webgl.collect()||void 0}catch(t){}try{t.fonts=this.collectors.fonts.collect()||void 0}catch(t){}try{t.screen=this.collectors.screen.collect()}catch(t){}try{t.timezone=this.collectors.timezone.collect()}catch(t){}try{t.plugins=this.collectors.plugins.collect()||void 0}catch(t){}try{t.cpu=this.collectors.cpu.collect()}catch(t){}try{t.touch=this.collectors.touch.collect()}catch(t){}try{t.audio=await this.collectors.audio.collect()||void 0}catch(t){}try{t.mediaDevices=await this.collectors.mediaDevices.collect()||void 0}catch(t){}try{t.battery=await this.collectors.battery.collect()||void 0}catch(t){}try{t.storage=await this.collectors.storage.collect()}catch(t){}try{t.permissions=await this.collectors.permissions.collect()||void 0}catch(t){}try{t.webrtc=await this.collectors.webrtc.collect()||void 0}catch(t){}const i=this.visitorIDGenerator.generate(t),e=this.visitorIDGenerator.calculateConfidence(t);return this.cachedData={visitorId:i,confidence:Math.round(1e3*e)/1e3,components:t,version:"1.0.0",timestamp:Date.now()},this.cachedData}async getVisitorId(){return(await this.collect()).visitorId}clearCache(){this.cachedData=null,Object.values(this.collectors).forEach(t=>{t&&"function"==typeof t.clearCache&&t.clearCache()})}getStats(){if(!this.cachedData)return{componentsCollected:0,totalComponents:13,collectionTime:0};const t=Object.keys(this.cachedData.components).length,i=performance.now()-this.collectionStartTime;return{componentsCollected:t,totalComponents:13,collectionTime:Math.round(100*i)/100}}}class M{constructor(){this.cachedSignals=null}collect(){if(this.cachedSignals)return this.cachedSignals;const t={isIncognito:this.detectIncognito(),isVPN:!1,isAutomated:this.detectAutomation(),hasAdBlocker:this.detectAdBlocker()};return this.cachedSignals=t,t}detectIncognito(){try{if("storage"in navigator&&"estimate"in navigator.storage)try{navigator.storage.estimate().then(()=>{}).catch(()=>{})}catch{return!0}if("storage"in navigator&&navigator.storage,navigator,window.chrome&&window.chrome.runtime&&!window.chrome.runtime.onConnect)return!0;try{const t="__incognito_test__";localStorage.setItem(t,"test"),localStorage.removeItem(t)}catch{return!0}return!1}catch(t){return!1}}detectAutomation(){try{if(!0===navigator.webdriver)return!0;if(window.chrome&&window.chrome.runtime&&window.chrome.runtime.onConnect){if(window.chrome.runtime.onConnect.hasListeners())return!0}if(!(window.chrome||window.safari||window.Notification&&window.DeviceMotionEvent))return!0;try{const t=document.createElement("canvas"),i=t.getContext("2d");if(i){i.textBaseline="top",i.font="14px Arial",i.fillText("Automation test",2,2);if(t.toDataURL().length<100)return!0}}catch{}return!!(window.__nightmare||window.__phantomas||window.Buffer)}catch(t){return!1}}detectAdBlocker(){try{const t=document.createElement("div");t.innerHTML="&nbsp;",t.className="adsbox",t.style.position="absolute",t.style.left="-9999px",document.body.appendChild(t),setTimeout(()=>{const i=0===t.offsetHeight||0===t.offsetWidth;return document.body.removeChild(t),i},100);const i=Array.from(document.getElementsByTagName("script"));return i.filter(t=>t.src&&t.src.includes("ads")&&!t.textContent).length>0||!!(window.uBlock||window.adblock||window.BlockAdBlock)}catch(t){return!1}}clearCache(){this.cachedSignals=null}}class T{constructor(){this.cachedCapabilities=null}collect(){if(this.cachedCapabilities)return this.cachedCapabilities;const t={hasWebGL:this.checkWebGL(),hasCanvas:this.checkCanvas(),hasWebRTC:this.checkWebRTC(),hasServiceWorker:this.checkServiceWorker(),hasIndexedDB:this.checkIndexedDB(),hasLocalStorage:this.checkLocalStorage(),hasSessionStorage:this.checkSessionStorage(),cookieEnabled:navigator.cookieEnabled,doNotTrack:"1"===navigator.doNotTrack||"yes"===navigator.doNotTrack};return this.cachedCapabilities=t,t}checkWebGL(){try{const t=document.createElement("canvas");return!(!t.getContext("webgl")&&!t.getContext("experimental-webgl"))}catch{return!1}}checkCanvas(){try{return!!document.createElement("canvas").getContext("2d")}catch{return!1}}checkWebRTC(){return!!((window.RTCPeerConnection||window.webkitRTCPeerConnection||window.mozRTCPeerConnection)&&navigator.mediaDevices&&navigator.mediaDevices.getUserMedia)}checkServiceWorker(){return"serviceWorker"in navigator}checkIndexedDB(){return"indexedDB"in window}checkLocalStorage(){try{const t="__localStorage_test__";return localStorage.setItem(t,t),localStorage.removeItem(t),!0}catch{return!1}}checkSessionStorage(){try{const t="__sessionStorage_test__";return sessionStorage.setItem(t,t),sessionStorage.removeItem(t),!0}catch{return!1}}clearCache(){this.cachedCapabilities=null}}class D{constructor(){this.cachedSignals=null}collect(){if(this.cachedSignals)return this.cachedSignals;const t={hardwareConcurrency:navigator.hardwareConcurrency||0,deviceMemory:this.getDeviceMemory(),maxTouchPoints:navigator.maxTouchPoints||0,connectionType:this.getConnectionType(),effectiveType:this.getEffectiveType(),downlink:this.getDownlink(),rtt:this.getRTT(),saveData:this.getSaveData()};return this.cachedSignals=t,t}getDeviceMemory(){return"deviceMemory"in navigator&&navigator.deviceMemory?navigator.deviceMemory:null}getConnectionType(){const t=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return t&&t.type?t.type:null}getEffectiveType(){const t=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return t&&t.effectiveType?t.effectiveType:null}getDownlink(){const t=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return t&&t.downlink?t.downlink:null}getRTT(){const t=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return t&&t.rtt?t.rtt:null}getSaveData(){const t=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return t&&void 0!==t.saveData?t.saveData:null}clearCache(){this.cachedSignals=null}}class _{constructor(){this.focusCount=0,this.blurCount=0,this.copyCount=0,this.pasteCount=0,this.cutCount=0,this.fieldFocusOrder=[],this.fieldFocusTimes=new Map,this.backspaceCount=0,this.deleteCount=0,this.autofillDetected=!1,this.autocompleteDetected=!1,this.isActive=!1,this.focusHandler=t=>this.handleFocus(t),this.blurHandler=t=>this.handleBlur(t),this.copyHandler=t=>this.handleCopy(t),this.pasteHandler=t=>this.handlePaste(t),this.cutHandler=t=>this.handleCut(t),this.keydownHandler=t=>this.handleKeyDown(t),this.inputHandler=t=>this.handleInput(t)}start(){this.isActive||"undefined"==typeof document||(document.addEventListener("focus",this.focusHandler,!0),document.addEventListener("blur",this.blurHandler,!0),document.addEventListener("copy",this.copyHandler,!0),document.addEventListener("paste",this.pasteHandler,!0),document.addEventListener("cut",this.cutHandler,!0),document.addEventListener("keydown",this.keydownHandler,!0),document.addEventListener("input",this.inputHandler,!0),this.isActive=!0)}stop(){this.isActive&&"undefined"!=typeof document&&(document.removeEventListener("focus",this.focusHandler,!0),document.removeEventListener("blur",this.blurHandler,!0),document.removeEventListener("copy",this.copyHandler,!0),document.removeEventListener("paste",this.pasteHandler,!0),document.removeEventListener("cut",this.cutHandler,!0),document.removeEventListener("keydown",this.keydownHandler,!0),document.removeEventListener("input",this.inputHandler,!0),this.isActive=!1)}getData(){const t={};return this.fieldFocusTimes.forEach((i,e)=>{t[e]=i}),{focusCount:this.focusCount,blurCount:this.blurCount,copyCount:this.copyCount,pasteCount:this.pasteCount,cutCount:this.cutCount,autofillDetected:this.autofillDetected,autocompleteDetected:this.autocompleteDetected,fieldFocusOrder:[...this.fieldFocusOrder],timePerField:t,backspaceCount:this.backspaceCount,deleteCount:this.deleteCount}}reset(){this.focusCount=0,this.blurCount=0,this.copyCount=0,this.pasteCount=0,this.cutCount=0,this.fieldFocusOrder=[],this.fieldFocusTimes.clear(),this.backspaceCount=0,this.deleteCount=0,this.autofillDetected=!1,this.autocompleteDetected=!1}handleFocus(t){const i=t.target;if(!this.isFormField(i))return;this.focusCount++;const e=this.getFieldId(i);e&&!this.fieldFocusOrder.includes(e)&&this.fieldFocusOrder.push(e),this.fieldFocusTimes.set(e||"unknown",Date.now())}handleBlur(t){const i=t.target;if(!this.isFormField(i))return;this.blurCount++;const e=this.getFieldId(i);if(e){const t=this.fieldFocusTimes.get(e)||Date.now(),i=Date.now()-t;this.fieldFocusTimes.set(e,i)}}handleCopy(t){const i=t.target;this.isFormField(i)&&this.copyCount++}handlePaste(t){const i=t.target;this.isFormField(i)&&this.pasteCount++}handleCut(t){const i=t.target;this.isFormField(i)&&this.cutCount++}handleKeyDown(t){const i=t.target;this.isFormField(i)&&("Backspace"===t.key?this.backspaceCount++:"Delete"===t.key&&this.deleteCount++)}handleInput(t){const i=t.target;if(!this.isFormField(i))return;i.value&&"password"===i.type&&(this.autofillDetected=!0),i.hasAttribute("autocomplete")&&"off"!==i.getAttribute("autocomplete")&&(this.autocompleteDetected=!0)}isFormField(t){if(!t)return!1;const i=t.tagName.toLowerCase();return"input"===i||"textarea"===i||"select"===i||t.isContentEditable}getFieldId(t){return t.id?t.id:"name"in t&&t.name?t.name:t.getAttribute("data-field-id")?t.getAttribute("data-field-id"):null}}class ${constructor(){this.pageLoadTime=0,this.timeToFirstInteraction=0,this.startTime=Date.now(),this.firstInteractionTime=null,this.maxScrollDepth=0,this.clickCount=0,this.linkClickCount=0,this.imageViewCount=0,this.videoPlayCount=0,this.isActive=!1,this.clickHandler=t=>this.handleClick(t),this.scrollHandler=()=>this.handleScroll(),this.loadHandler=()=>this.handleLoad(),this.imageLoadHandler=()=>this.handleImageLoad(),this.videoPlayHandler=()=>this.handleVideoPlay(),this.startTime=performance.now()}start(){this.isActive||"undefined"==typeof document||("complete"===document.readyState?this.pageLoadTime=performance.now()-this.startTime:window.addEventListener("load",this.loadHandler),document.addEventListener("click",this.clickHandler,!0),window.addEventListener("scroll",this.scrollHandler,{passive:!0}),document.addEventListener("load",this.imageLoadHandler,!0),document.addEventListener("play",this.videoPlayHandler,!0),this.isActive=!0)}stop(){this.isActive&&"undefined"!=typeof document&&(window.removeEventListener("load",this.loadHandler),document.removeEventListener("click",this.clickHandler,!0),window.removeEventListener("scroll",this.scrollHandler),document.removeEventListener("load",this.imageLoadHandler,!0),document.removeEventListener("play",this.videoPlayHandler,!0),this.isActive=!1)}getData(){const t=Date.now()-this.startTime,i=this.calculateScrollDepth();return{pageLoadTime:this.pageLoadTime,timeToFirstInteraction:this.firstInteractionTime?this.firstInteractionTime-this.startTime:0,timeOnPage:t,scrollDepth:i,clickCount:this.clickCount,linkClickCount:this.linkClickCount,imageViewCount:this.imageViewCount,videoPlayCount:this.videoPlayCount}}reset(){this.pageLoadTime=0,this.timeToFirstInteraction=0,this.startTime=Date.now(),this.firstInteractionTime=null,this.maxScrollDepth=0,this.clickCount=0,this.linkClickCount=0,this.imageViewCount=0,this.videoPlayCount=0}handleLoad(){this.pageLoadTime=performance.now()-this.startTime}handleClick(t){this.firstInteractionTime||(this.firstInteractionTime=performance.now()),this.clickCount++;const i=t.target;("a"===i.tagName.toLowerCase()||i.closest("a"))&&this.linkClickCount++}handleScroll(){const t=this.calculateScrollDepth();this.maxScrollDepth=Math.max(this.maxScrollDepth,t)}handleImageLoad(){this.imageViewCount++}handleVideoPlay(){this.videoPlayCount++}calculateScrollDepth(){if("undefined"==typeof window||"undefined"==typeof document)return 0;const t=window.innerHeight||document.documentElement.clientHeight,i=Math.max(document.body.scrollHeight,document.body.offsetHeight,document.documentElement.clientHeight,document.documentElement.scrollHeight,document.documentElement.offsetHeight),e=window.pageYOffset||document.documentElement.scrollTop;if(0===i)return 0;const s=e+t;return Math.min(s/i,1)}}const I="https://api.keverd.com";class x{constructor(){this.config=null,this.isInitialized=!1,this.sessionId=null,this.ghostInterval=null,this.ghostStartTime=null,this.ghostSignalCount=0,this.MIN_GHOST_SIGNALS=10,this.MAX_GHOST_COLLECTION_TIME=6e5,this.deviceCollector=new e,this.behavioralCollector=new a,this.fingerprintManager=new k,this.privacySignalCollector=new M,this.browserCapabilityCollector=new T,this.hardwareSignalCollector=new D,this.formInteractionCollector=new _,this.pageInteractionCollector=new $}init(t){this.isInitialized?this.config:(this.config="string"==typeof t?{apiKey:t,debug:!1}:{debug:!1,...t},this.behavioralCollector.start(),this.formInteractionCollector.start(),this.pageInteractionCollector.start(),this.sessionId=this.generateSessionId(),this.isInitialized=!0,this.config.debug,this.startSession().catch(()=>{}),this.startGhostSignalCollection())}startGhostSignalCollection(){if(this.ghostInterval)return;if(!this.config)return;this.ghostStartTime=Date.now(),this.ghostSignalCount=0;const t=3e4,i=()=>{const i=Date.now(),e=this.ghostStartTime?i-this.ghostStartTime:0,s=this.ghostSignalCount>=this.MIN_GHOST_SIGNALS,n=e>=this.MAX_GHOST_COLLECTION_TIME;if(s||n)return this.config,void this.stopGhostSignalCollection();const r=this.ghostStartTime?i-this.ghostStartTime:t;this.sendGhostSignals(r).catch(t=>{this.config}),this.ghostSignalCount++,this.ghostStartTime=i};setTimeout(()=>{i(),this.ghostInterval=setInterval(()=>{i()},t)},t)}stopGhostSignalCollection(){this.ghostInterval&&(clearInterval(this.ghostInterval),this.ghostInterval=null,this.ghostStartTime=null)}async sendGhostSignals(t){if(!this.isInitialized||!this.config)return;const i=this.deviceCollector.collect(),e=this.behavioralCollector.getData(),s=await this.fingerprintManager.collect(),n={visitorId:s.visitorId,confidence:s.confidence,components:s.components},r=this.privacySignalCollector.collect(),o=this.browserCapabilityCollector.collect(),a=this.hardwareSignalCollector.collect(),h=this.formInteractionCollector.getData(),c=this.behavioralCollector.getMouseSignals(),l=this.behavioralCollector.getKeyboardSignals(),u=this.pageInteractionCollector.getData(),d={connectionType:a.connectionType||void 0,effectiveType:a.effectiveType||void 0,downlink:a.downlink||void 0,rtt:a.rtt||void 0,saveData:a.saveData||void 0},m={sessionId:this.sessionId||void 0,timestamp:(new Date).toISOString()},p={userId:this.config.userId,device:i,session:m,behavioral:e,duration_ms:t,fingerprintjs:n||void 0,privacySignals:r,browserCapabilities:o,hardwareSignals:a,formInteractions:h,mouseSignals:c,keyboardSignals:l,pageInteractions:u,networkSignals:d,useCase:"ghost"},g=`${I}/fingerprint/ghost`,w={"Content-Type":"application/json","X-SDK-Source":"javascript"},f=this.config.apiKey;f&&(w["x-keverd-key"]=f,w["X-API-KEY"]=f,w.Authorization=`Bearer ${f}`),await fetch(g,{method:"POST",headers:w,body:JSON.stringify(p)}).catch(()=>{})}async getVisitorData(){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");try{const t=this.deviceCollector.collect(),i=this.behavioralCollector.getData(),e=await this.fingerprintManager.collect(),s={visitorId:e.visitorId,confidence:e.confidence,components:e.components},n=this.privacySignalCollector.collect(),r=this.browserCapabilityCollector.collect(),o=this.hardwareSignalCollector.collect(),a=this.formInteractionCollector.getData(),h=this.behavioralCollector.getMouseSignals(),c=this.behavioralCollector.getKeyboardSignals(),l=this.pageInteractionCollector.getData(),u={connectionType:o.connectionType||void 0,effectiveType:o.effectiveType||void 0,downlink:o.downlink||void 0,rtt:o.rtt||void 0,saveData:o.saveData||void 0},d={sessionId:this.sessionId||void 0,timestamp:(new Date).toISOString()},m={userId:this.config.userId,device:t,session:d,behavioral:i,fingerprintjs:s||void 0,privacySignals:n,browserCapabilities:r,hardwareSignals:o,formInteractions:a,mouseSignals:h,keyboardSignals:c,pageInteractions:l,networkSignals:u,useCase:"general"};return await this.sendFingerprintRequest(m)}catch(t){const i=t instanceof Error?t.message:"Unknown error";throw this.config.debug,new Error(`Failed to get visitor data: ${i}`)}}async createTransactionID(t){return(await this.getVisitorData()).session_id}async verifyLogin(t,i){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");return await this.sendVerifyRequest("login",{userId:t,metadata:i})}async verifyCheckout(t,i,e){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");return await this.sendVerifyRequest("checkout",{amount:t,currency:i,metadata:e})}async verifyRegistration(t){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");return await this.sendVerifyRequest("registration",{metadata:t})}async verifyPasswordReset(t,i){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");return await this.sendVerifyRequest("password_reset",{email:t,metadata:i})}async verifyAccountChange(t,i){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");return await this.sendVerifyRequest("account_change",{changeType:t,metadata:i})}async sendVerifyRequest(t,i){if(!this.config)throw new Error("SDK not initialized");const e=this.deviceCollector.collect(),s=this.behavioralCollector.getData(),n=await this.fingerprintManager.collect(),r={visitorId:n.visitorId,confidence:n.confidence,components:n.components},o=this.privacySignalCollector.collect(),a=this.browserCapabilityCollector.collect(),h=this.hardwareSignalCollector.collect(),c=this.formInteractionCollector.getData(),l=this.behavioralCollector.getMouseSignals(),u=this.behavioralCollector.getKeyboardSignals(),d=this.pageInteractionCollector.getData(),m={connectionType:h.connectionType||void 0,effectiveType:h.effectiveType||void 0,downlink:h.downlink||void 0,rtt:h.rtt||void 0,saveData:h.saveData||void 0},p={sessionId:this.sessionId||void 0,timestamp:(new Date).toISOString()},g={userId:i.userId||this.config.userId,device:e,session:p,behavioral:s,fingerprintjs:r||void 0,privacySignals:o,browserCapabilities:a,hardwareSignals:h,formInteractions:c,mouseSignals:l,keyboardSignals:u,pageInteractions:d,networkSignals:m,useCase:t};i.metadata&&Object.assign(g,i.metadata),void 0!==i.amount&&(g.amount=i.amount),i.currency&&(g.currency=i.currency),i.email&&(g.email=i.email),i.changeType&&(g.changeType=i.changeType);const w=`${I}/fingerprint/verify/${t}`,f={"Content-Type":"application/json","X-SDK-Source":"javascript"},v=this.config.apiKey;v&&(f["x-keverd-key"]=v,f["X-API-KEY"]=v,f.Authorization=`Bearer ${v}`);const y=await fetch(w,{method:"POST",headers:f,body:JSON.stringify(g)});if(!y.ok){const t=await y.text().catch(()=>"Unknown error");throw new Error(`HTTP ${y.status}: ${t}`)}return await y.json()}async sendFingerprintRequest(t){if(!this.config)throw new Error("SDK not initialized");const i=`${I}/fingerprint/score`,e={"Content-Type":"application/json","X-SDK-Source":"javascript"},s=this.config.apiKey;s&&(e["x-keverd-key"]=s,e["X-API-KEY"]=s,e.Authorization=`Bearer ${s}`);const n=await fetch(i,{method:"POST",headers:e,body:JSON.stringify(t)});if(!n.ok){const t=await n.text().catch(()=>"Unknown error");throw new Error(`HTTP ${n.status}: ${t}`)}return await n.json()}generateSessionId(){return`${Date.now()}_${Math.random().toString(36).substr(2,9)}`}i(){const t=navigator.userAgent;return t.includes("Chrome")?"Chrome":t.includes("Firefox")?"Firefox":t.includes("Safari")&&!t.includes("Chrome")?"Safari":t.includes("Edge")?"Edge":t.includes("Opera")?"Opera":void 0}h(){const t=navigator.userAgent;return t.includes("Windows")?"Windows":t.includes("Mac OS")?"macOS":t.includes("Linux")?"Linux":t.includes("Android")?"Android":t.includes("iOS")||t.includes("iPhone")||t.includes("iPad")?"iOS":void 0}async startSession(t,i,e){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");this.sessionId||(this.sessionId=this.generateSessionId());try{const s=`${I}/dashboard/sessions/start`,n={"Content-Type":"application/json"},r=this.config.apiKey;r&&(n["x-keverd-key"]=r,n["X-API-KEY"]=r,n.Authorization=`Bearer ${r}`);const o=this.deviceCollector.collect();await fetch(s,{method:"POST",headers:n,body:JSON.stringify({session_id:this.sessionId,user_id:t||this.config.userId,device_hash:i||o.fingerprint,metadata:e||{},user_agent:navigator.userAgent,browser:this.i(),os:this.h(),platform:"web",sdk_type:"web",sdk_source:"javascript"})}),this.config.debug}catch(t){this.config.debug}}async endSession(){if(this.isInitialized&&this.config&&this.sessionId)try{const t=`${I}/dashboard/sessions/${this.sessionId}/end`,i={"Content-Type":"application/json"},e=this.config.apiKey;e&&(i["x-keverd-key"]=e,i["X-API-KEY"]=e,i.Authorization=`Bearer ${e}`),await fetch(t,{method:"POST",headers:i}),this.config.debug}catch(t){this.config.debug}}async pauseSession(){if(this.isInitialized&&this.config&&this.sessionId)try{const t=`${I}/dashboard/sessions/${this.sessionId}/pause`,i={"Content-Type":"application/json"},e=this.config.apiKey;e&&(i["x-keverd-key"]=e,i["X-API-KEY"]=e,i.Authorization=`Bearer ${e}`),await fetch(t,{method:"POST",headers:i}),this.config.debug}catch(t){this.config.debug}}async resumeSession(){if(this.isInitialized&&this.config&&this.sessionId)try{const t=`${I}/dashboard/sessions/${this.sessionId}/resume`,i={"Content-Type":"application/json"},e=this.config.apiKey;e&&(i["x-keverd-key"]=e,i["X-API-KEY"]=e,i.Authorization=`Bearer ${e}`),await fetch(t,{method:"POST",headers:i}),this.config.debug}catch(t){this.config.debug}}async getSessionStatus(){if(!this.isInitialized||!this.config||!this.sessionId)return null;try{const t=`${I}/dashboard/sessions/${this.sessionId}/status`,i={},e=this.config.apiKey;e&&(i["x-keverd-key"]=e,i["X-API-KEY"]=e,i.Authorization=`Bearer ${e}`);const s=await fetch(t,{method:"GET",headers:i});return s.ok?await s.json():null}catch(t){return this.config.debug,null}}async destroy(){this.sessionId&&await this.endSession(),this.behavioralCollector.stop(),this.formInteractionCollector.stop(),this.pageInteractionCollector.stop(),this.fingerprintManager.clearCache(),this.isInitialized=!1,this.stopGhostSignalCollection(),this.ghostSignalCount=0,this.config,this.config=null,this.sessionId=null}isReady(){return this.isInitialized&&null!==this.config}}const P=new x;class O{async collect(){return null}clearCache(){}async isAvailable(){return!1}}return i})());
package/dist/index.d.ts CHANGED
@@ -5,4 +5,7 @@
5
5
  export { KeverdSDK, Keverd } from './core/sdk';
6
6
  export { DeviceCollector } from './collectors/device';
7
7
  export { BehavioralCollector } from './collectors/behavioral';
8
- export type { SDKConfig, DeviceInfo, SessionInfo, BehavioralData, FingerprintRequest, FingerprintResponse, TransactionMetadata, } from './types';
8
+ export { KinematicEngine } from './collectors/kinematic-engine';
9
+ export { KeystrokeMonitor } from './collectors/keystroke-monitor';
10
+ export { FingerprintJSCollector } from './collectors/fingerprintjs';
11
+ export type { SDKConfig, DeviceInfo, SessionInfo, BehavioralData, BehavioralSequence, KinematicFeatureVector, KeystrokeFeatureVector, FingerprintRequest, FingerprintResponse, TransactionMetadata, } from './types';