@axeptio/behavior-detection 1.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.
- package/README.md +828 -0
- package/dist/behavior-detection.esm.min.js +2 -0
- package/dist/behavior-detection.esm.min.js.map +7 -0
- package/dist/behavior-detection.min.js +2 -0
- package/dist/behavior-detection.min.js.map +7 -0
- package/dist/behavior-detector.d.ts +102 -0
- package/dist/browser.d.ts +33 -0
- package/dist/cjs/behavior-detector.d.ts +102 -0
- package/dist/cjs/behavior-detector.js +315 -0
- package/dist/cjs/browser.d.ts +33 -0
- package/dist/cjs/browser.js +226 -0
- package/dist/cjs/index.d.ts +38 -0
- package/dist/cjs/index.js +55 -0
- package/dist/cjs/math-utils.d.ts +84 -0
- package/dist/cjs/math-utils.js +141 -0
- package/dist/cjs/strategies/click.d.ts +39 -0
- package/dist/cjs/strategies/click.js +173 -0
- package/dist/cjs/strategies/environment.d.ts +52 -0
- package/dist/cjs/strategies/environment.js +148 -0
- package/dist/cjs/strategies/index.d.ts +18 -0
- package/dist/cjs/strategies/index.js +36 -0
- package/dist/cjs/strategies/keyboard.d.ts +43 -0
- package/dist/cjs/strategies/keyboard.js +233 -0
- package/dist/cjs/strategies/mouse.d.ts +39 -0
- package/dist/cjs/strategies/mouse.js +159 -0
- package/dist/cjs/strategies/resize.d.ts +21 -0
- package/dist/cjs/strategies/resize.js +97 -0
- package/dist/cjs/strategies/scroll.d.ts +37 -0
- package/dist/cjs/strategies/scroll.js +149 -0
- package/dist/cjs/strategies/tap.d.ts +38 -0
- package/dist/cjs/strategies/tap.js +214 -0
- package/dist/cjs/strategy.d.ts +107 -0
- package/dist/cjs/strategy.js +33 -0
- package/dist/cjs/types.d.ts +168 -0
- package/dist/cjs/types.js +26 -0
- package/dist/esm/behavior-detector.d.ts +102 -0
- package/dist/esm/behavior-detector.js +311 -0
- package/dist/esm/browser.d.ts +33 -0
- package/dist/esm/browser.js +224 -0
- package/dist/esm/index.d.ts +38 -0
- package/dist/esm/index.js +36 -0
- package/dist/esm/math-utils.d.ts +84 -0
- package/dist/esm/math-utils.js +127 -0
- package/dist/esm/strategies/click.d.ts +39 -0
- package/dist/esm/strategies/click.js +169 -0
- package/dist/esm/strategies/environment.d.ts +52 -0
- package/dist/esm/strategies/environment.js +144 -0
- package/dist/esm/strategies/index.d.ts +18 -0
- package/dist/esm/strategies/index.js +19 -0
- package/dist/esm/strategies/keyboard.d.ts +43 -0
- package/dist/esm/strategies/keyboard.js +229 -0
- package/dist/esm/strategies/mouse.d.ts +39 -0
- package/dist/esm/strategies/mouse.js +155 -0
- package/dist/esm/strategies/resize.d.ts +21 -0
- package/dist/esm/strategies/resize.js +93 -0
- package/dist/esm/strategies/scroll.d.ts +37 -0
- package/dist/esm/strategies/scroll.js +145 -0
- package/dist/esm/strategies/tap.d.ts +38 -0
- package/dist/esm/strategies/tap.js +210 -0
- package/dist/esm/strategy.d.ts +107 -0
- package/dist/esm/strategy.js +29 -0
- package/dist/esm/types.d.ts +168 -0
- package/dist/esm/types.js +23 -0
- package/dist/index.d.ts +38 -0
- package/dist/math-utils.d.ts +84 -0
- package/dist/strategies/click.d.ts +39 -0
- package/dist/strategies/environment.d.ts +52 -0
- package/dist/strategies/index.d.ts +18 -0
- package/dist/strategies/keyboard.d.ts +43 -0
- package/dist/strategies/mouse.d.ts +39 -0
- package/dist/strategies/resize.d.ts +21 -0
- package/dist/strategies/scroll.d.ts +37 -0
- package/dist/strategies/tap.d.ts +38 -0
- package/dist/strategy.d.ts +107 -0
- package/dist/types.d.ts +168 -0
- package/package.json +60 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Fingerprinting Strategy
|
|
3
|
+
* Captures browser environment on initialization and tick updates
|
|
4
|
+
*/
|
|
5
|
+
import { BaseStrategy } from '../strategy';
|
|
6
|
+
interface EnvironmentData {
|
|
7
|
+
screenWidth: number;
|
|
8
|
+
screenHeight: number;
|
|
9
|
+
windowWidth: number;
|
|
10
|
+
windowHeight: number;
|
|
11
|
+
devicePixelRatio: number;
|
|
12
|
+
colorDepth: number;
|
|
13
|
+
userAgent: string;
|
|
14
|
+
platform: string;
|
|
15
|
+
language: string;
|
|
16
|
+
languages: string[];
|
|
17
|
+
hardwareConcurrency?: number;
|
|
18
|
+
maxTouchPoints: number;
|
|
19
|
+
vendor: string;
|
|
20
|
+
hasWebGL: boolean;
|
|
21
|
+
hasWebRTC: boolean;
|
|
22
|
+
hasLocalStorage: boolean;
|
|
23
|
+
hasSessionStorage: boolean;
|
|
24
|
+
hasIndexedDB: boolean;
|
|
25
|
+
plugins: number;
|
|
26
|
+
mimeTypes: number;
|
|
27
|
+
suspiciousRatio: boolean;
|
|
28
|
+
suspiciousDimensions: boolean;
|
|
29
|
+
featureInconsistency: boolean;
|
|
30
|
+
isMobile: boolean;
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
export declare class EnvironmentStrategy extends BaseStrategy {
|
|
34
|
+
readonly name = "environment";
|
|
35
|
+
readonly defaultWeight = 0.08;
|
|
36
|
+
private data;
|
|
37
|
+
start(): void;
|
|
38
|
+
stop(): void;
|
|
39
|
+
reset(): void;
|
|
40
|
+
onTick(_timestamp: number): void;
|
|
41
|
+
score(): number | undefined;
|
|
42
|
+
private isMobileDevice;
|
|
43
|
+
private captureEnvironment;
|
|
44
|
+
getDebugInfo(): EnvironmentData | null;
|
|
45
|
+
/**
|
|
46
|
+
* Check if current device is mobile
|
|
47
|
+
* Returns true if mobile, false otherwise
|
|
48
|
+
* Returns null if environment hasn't been captured yet
|
|
49
|
+
*/
|
|
50
|
+
isMobile(): boolean | null;
|
|
51
|
+
}
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection Strategies - Modular behavior analysis
|
|
3
|
+
* Import only what you need for optimal bundle size
|
|
4
|
+
*/
|
|
5
|
+
export { MouseStrategy } from './mouse';
|
|
6
|
+
export { ScrollStrategy } from './scroll';
|
|
7
|
+
export { ClickStrategy } from './click';
|
|
8
|
+
export { TapStrategy } from './tap';
|
|
9
|
+
export { KeyboardStrategy } from './keyboard';
|
|
10
|
+
export { EnvironmentStrategy } from './environment';
|
|
11
|
+
export { ResizeStrategy } from './resize';
|
|
12
|
+
export { MouseStrategy as Mouse } from './mouse';
|
|
13
|
+
export { ScrollStrategy as Scroll } from './scroll';
|
|
14
|
+
export { ClickStrategy as Click } from './click';
|
|
15
|
+
export { TapStrategy as Tap } from './tap';
|
|
16
|
+
export { KeyboardStrategy as Keyboard } from './keyboard';
|
|
17
|
+
export { EnvironmentStrategy as Environment } from './environment';
|
|
18
|
+
export { ResizeStrategy as Resize } from './resize';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard Timing Detection Strategy
|
|
3
|
+
* Monitors typing in specific input fields
|
|
4
|
+
* Analyzes keydown/keyup timing and micro-variations
|
|
5
|
+
*/
|
|
6
|
+
import { BaseStrategy } from '../strategy';
|
|
7
|
+
export declare class KeyboardStrategy extends BaseStrategy {
|
|
8
|
+
readonly name = "keyboard";
|
|
9
|
+
readonly defaultWeight = 0.1;
|
|
10
|
+
private events;
|
|
11
|
+
private targetSelectors;
|
|
12
|
+
private focusedElement;
|
|
13
|
+
private focusedElementSelector;
|
|
14
|
+
private lastEventTimestamp;
|
|
15
|
+
private sessionPauseThreshold;
|
|
16
|
+
private downListener;
|
|
17
|
+
private upListener;
|
|
18
|
+
private focusListeners;
|
|
19
|
+
private blurListeners;
|
|
20
|
+
private isActive;
|
|
21
|
+
constructor(options?: {
|
|
22
|
+
targetSelectors?: string[];
|
|
23
|
+
});
|
|
24
|
+
start(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Add a new target selector at runtime
|
|
27
|
+
*/
|
|
28
|
+
addTarget(selector: string): void;
|
|
29
|
+
private attachFocusListeners;
|
|
30
|
+
private attachFocusListenersForSelector;
|
|
31
|
+
stop(): void;
|
|
32
|
+
reset(): void;
|
|
33
|
+
score(): number | undefined;
|
|
34
|
+
getDebugInfo(): {
|
|
35
|
+
eventCount: number;
|
|
36
|
+
downEvents: number;
|
|
37
|
+
upEvents: number;
|
|
38
|
+
backspaceCount: number;
|
|
39
|
+
pressDurations: number[];
|
|
40
|
+
focusedElement: string;
|
|
41
|
+
trackedElements: number;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mouse Movement Detection Strategy
|
|
3
|
+
* Autonomous module that manages its own mouse event listeners and state
|
|
4
|
+
* Tracks distance and angle to detect unnatural jumps and sharp turns
|
|
5
|
+
*/
|
|
6
|
+
import { BaseStrategy, type TimeSeriesPoint } from '../strategy';
|
|
7
|
+
export declare class MouseStrategy extends BaseStrategy {
|
|
8
|
+
readonly name = "mouse";
|
|
9
|
+
readonly defaultWeight = 0.3;
|
|
10
|
+
private distanceSeries;
|
|
11
|
+
private angleSeries;
|
|
12
|
+
private lastPosition;
|
|
13
|
+
private lastAngle;
|
|
14
|
+
private cumulativeAngle;
|
|
15
|
+
private rollingWindowMs;
|
|
16
|
+
private listener;
|
|
17
|
+
private leaveListener;
|
|
18
|
+
private isActive;
|
|
19
|
+
private screenDiagonal;
|
|
20
|
+
constructor(options?: {
|
|
21
|
+
rollingWindow?: number;
|
|
22
|
+
});
|
|
23
|
+
start(): void;
|
|
24
|
+
stop(): void;
|
|
25
|
+
reset(): void;
|
|
26
|
+
score(): number | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Mouse-specific pattern detection
|
|
29
|
+
* Detects bot-like patterns: constant velocity, linear paths
|
|
30
|
+
*/
|
|
31
|
+
private detectMousePatterns;
|
|
32
|
+
getDebugInfo(): {
|
|
33
|
+
eventCount: number;
|
|
34
|
+
rollingWindow: number;
|
|
35
|
+
isActive: boolean;
|
|
36
|
+
distanceSeries: TimeSeriesPoint[];
|
|
37
|
+
angleSeries: TimeSeriesPoint[];
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resize Behavior Detection Strategy
|
|
3
|
+
*/
|
|
4
|
+
import { BaseStrategy } from '../strategy';
|
|
5
|
+
export declare class ResizeStrategy extends BaseStrategy {
|
|
6
|
+
readonly name = "resize";
|
|
7
|
+
readonly defaultWeight = 0.02;
|
|
8
|
+
private events;
|
|
9
|
+
private listener;
|
|
10
|
+
private isActive;
|
|
11
|
+
private lastMousePosition;
|
|
12
|
+
private mouseListener;
|
|
13
|
+
start(): void;
|
|
14
|
+
stop(): void;
|
|
15
|
+
reset(): void;
|
|
16
|
+
score(): number | undefined;
|
|
17
|
+
getDebugInfo(): {
|
|
18
|
+
eventCount: number;
|
|
19
|
+
withMouseData: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll Behavior Detection Strategy
|
|
3
|
+
* Autonomous module managing scroll event listeners
|
|
4
|
+
* Tracks normalized scroll distance and velocity patterns
|
|
5
|
+
*/
|
|
6
|
+
import { BaseStrategy, type TimeSeriesPoint } from '../strategy';
|
|
7
|
+
export declare class ScrollStrategy extends BaseStrategy {
|
|
8
|
+
readonly name = "scroll";
|
|
9
|
+
readonly defaultWeight = 0.15;
|
|
10
|
+
private distanceSeries;
|
|
11
|
+
private velocitySeries;
|
|
12
|
+
private lastScrollY;
|
|
13
|
+
private lastTimestamp;
|
|
14
|
+
private rollingWindowMs;
|
|
15
|
+
private documentHeight;
|
|
16
|
+
private listener;
|
|
17
|
+
private isActive;
|
|
18
|
+
constructor(options?: {
|
|
19
|
+
rollingWindow?: number;
|
|
20
|
+
});
|
|
21
|
+
start(): void;
|
|
22
|
+
stop(): void;
|
|
23
|
+
reset(): void;
|
|
24
|
+
score(): number | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Scroll-specific pattern detection
|
|
27
|
+
* Detects bot-like patterns: constant deltas, instant jumps, too smooth
|
|
28
|
+
*/
|
|
29
|
+
private detectScrollPatterns;
|
|
30
|
+
getDebugInfo(): {
|
|
31
|
+
eventCount: number;
|
|
32
|
+
rollingWindow: number;
|
|
33
|
+
isActive: boolean;
|
|
34
|
+
distanceSeries: TimeSeriesPoint[];
|
|
35
|
+
velocitySeries: TimeSeriesPoint[];
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tap Behavior Detection Strategy (Mobile)
|
|
3
|
+
* Monitors touch interactions on specific elements
|
|
4
|
+
* Analyzes tap duration, precision, movement, and timing patterns
|
|
5
|
+
*/
|
|
6
|
+
import { BaseStrategy } from '../strategy';
|
|
7
|
+
export declare class TapStrategy extends BaseStrategy {
|
|
8
|
+
readonly name = "tap";
|
|
9
|
+
readonly defaultWeight = 0.35;
|
|
10
|
+
private events;
|
|
11
|
+
private targetSelectors;
|
|
12
|
+
private touchStartListeners;
|
|
13
|
+
private touchEndListeners;
|
|
14
|
+
private activeTouches;
|
|
15
|
+
private isActive;
|
|
16
|
+
constructor(options?: {
|
|
17
|
+
targetSelectors?: string[];
|
|
18
|
+
});
|
|
19
|
+
start(): void;
|
|
20
|
+
addTarget(selector: string): void;
|
|
21
|
+
private attachTouchListeners;
|
|
22
|
+
private attachTouchListenersForSelector;
|
|
23
|
+
stop(): void;
|
|
24
|
+
reset(): void;
|
|
25
|
+
score(): number | undefined;
|
|
26
|
+
getDebugInfo(): {
|
|
27
|
+
eventCount: number;
|
|
28
|
+
positions: {
|
|
29
|
+
outside: number;
|
|
30
|
+
deadCenter: number;
|
|
31
|
+
overElement: number;
|
|
32
|
+
};
|
|
33
|
+
durations: number[];
|
|
34
|
+
movements: number[];
|
|
35
|
+
inViewport: number;
|
|
36
|
+
trackedElements: number;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection Strategy Interface
|
|
3
|
+
* Each strategy is a fully autonomous module responsible for:
|
|
4
|
+
* - Registering its own event listeners
|
|
5
|
+
* - Managing its own state and events
|
|
6
|
+
* - Responding to lifecycle events (start/stop)
|
|
7
|
+
* - Optionally receiving tick updates for polling-based detection
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Time series data point
|
|
11
|
+
* Used by strategies that track values over time
|
|
12
|
+
*/
|
|
13
|
+
export interface TimeSeriesPoint {
|
|
14
|
+
value: number;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Event notification from strategy to detector
|
|
19
|
+
*/
|
|
20
|
+
export interface StrategyEvent {
|
|
21
|
+
strategy: string;
|
|
22
|
+
weight: number;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Base class for detection strategies
|
|
27
|
+
* Handles event callback pattern to avoid repetition
|
|
28
|
+
*/
|
|
29
|
+
export declare abstract class BaseStrategy implements DetectionStrategy {
|
|
30
|
+
abstract readonly name: string;
|
|
31
|
+
abstract readonly defaultWeight: number;
|
|
32
|
+
protected eventCallback: ((event: StrategyEvent) => void) | null;
|
|
33
|
+
setEventCallback(callback: (event: StrategyEvent) => void): void;
|
|
34
|
+
protected notifyEvent(weight: number): void;
|
|
35
|
+
abstract start(): void;
|
|
36
|
+
abstract stop(): void;
|
|
37
|
+
abstract reset(): void;
|
|
38
|
+
abstract score(): number | undefined;
|
|
39
|
+
onTick?(timestamp: number): void;
|
|
40
|
+
getDebugInfo?(): any;
|
|
41
|
+
}
|
|
42
|
+
export interface DetectionStrategy {
|
|
43
|
+
/**
|
|
44
|
+
* Unique identifier for this strategy
|
|
45
|
+
*/
|
|
46
|
+
readonly name: string;
|
|
47
|
+
/**
|
|
48
|
+
* Default weight for this strategy in overall score calculation
|
|
49
|
+
*/
|
|
50
|
+
readonly defaultWeight: number;
|
|
51
|
+
/**
|
|
52
|
+
* Start detection - register event listeners
|
|
53
|
+
*/
|
|
54
|
+
start(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Stop detection - remove event listeners, cleanup
|
|
57
|
+
*/
|
|
58
|
+
stop(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Reset collected data
|
|
61
|
+
*/
|
|
62
|
+
reset(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Calculate score based on collected data
|
|
65
|
+
* @returns Score 0-1, or undefined if insufficient data
|
|
66
|
+
*/
|
|
67
|
+
score(): number | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Optional: Called on regular interval for polling-based detection
|
|
70
|
+
* Use this to sample document/window/navigator state
|
|
71
|
+
* @param timestamp - Current timestamp
|
|
72
|
+
*/
|
|
73
|
+
onTick?(timestamp: number): void;
|
|
74
|
+
/**
|
|
75
|
+
* Optional: Get debug information about collected data
|
|
76
|
+
*/
|
|
77
|
+
getDebugInfo?(): any;
|
|
78
|
+
/**
|
|
79
|
+
* Optional: Set callback for when events are received
|
|
80
|
+
* Used to track confidence - detector will be notified when strategy receives data
|
|
81
|
+
* @param callback - Function to call when event is received
|
|
82
|
+
*/
|
|
83
|
+
setEventCallback?(callback: (event: StrategyEvent) => void): void;
|
|
84
|
+
}
|
|
85
|
+
export interface StrategyConfig {
|
|
86
|
+
strategy: DetectionStrategy;
|
|
87
|
+
weight: number;
|
|
88
|
+
enabled: boolean;
|
|
89
|
+
}
|
|
90
|
+
export interface TickOptions {
|
|
91
|
+
/**
|
|
92
|
+
* Tick interval in milliseconds
|
|
93
|
+
* Default: 1000 (1 second)
|
|
94
|
+
*/
|
|
95
|
+
interval?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Whether to start ticking immediately
|
|
98
|
+
* Default: false (start with detector.start())
|
|
99
|
+
*/
|
|
100
|
+
autoStart?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Automatically pause detection when the tab is hidden
|
|
103
|
+
* Uses the Page Visibility API to stop strategies and tick when document.hidden is true
|
|
104
|
+
* Default: true (recommended for better performance and battery life)
|
|
105
|
+
*/
|
|
106
|
+
pauseOnHidden?: boolean;
|
|
107
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
export type EventType = 'tab-visibility' | 'scroll' | 'resize' | 'mouse-move' | 'click' | 'keypress' | 'environment';
|
|
2
|
+
export interface BaseEvent {
|
|
3
|
+
type: EventType;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
}
|
|
6
|
+
export interface TabVisibilityEvent extends BaseEvent {
|
|
7
|
+
type: 'tab-visibility';
|
|
8
|
+
hidden: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface ScrollEvent extends BaseEvent {
|
|
11
|
+
type: 'scroll';
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
elementId?: string;
|
|
15
|
+
deltaY?: number;
|
|
16
|
+
deltaTime?: number;
|
|
17
|
+
velocity?: number;
|
|
18
|
+
isProgrammatic?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface ResizeEvent extends BaseEvent {
|
|
21
|
+
type: 'resize';
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
mouseX?: number;
|
|
25
|
+
mouseY?: number;
|
|
26
|
+
mouseNearEdge?: boolean;
|
|
27
|
+
screenWidth: number;
|
|
28
|
+
screenHeight: number;
|
|
29
|
+
screenAvailWidth: number;
|
|
30
|
+
screenAvailHeight: number;
|
|
31
|
+
devicePixelRatio: number;
|
|
32
|
+
isFullscreen?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface MouseMoveEvent extends BaseEvent {
|
|
35
|
+
type: 'mouse-move';
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
velocityX?: number;
|
|
39
|
+
velocityY?: number;
|
|
40
|
+
directionChange?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface ClickEvent extends BaseEvent {
|
|
43
|
+
type: 'click';
|
|
44
|
+
x: number;
|
|
45
|
+
y: number;
|
|
46
|
+
targetX: number;
|
|
47
|
+
targetY: number;
|
|
48
|
+
targetWidth: number;
|
|
49
|
+
targetHeight: number;
|
|
50
|
+
distanceFromTarget: number;
|
|
51
|
+
mousePositionBeforeClick?: {
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
timestamp: number;
|
|
55
|
+
};
|
|
56
|
+
timeSinceLastMouseMove?: number;
|
|
57
|
+
targetInViewport: boolean;
|
|
58
|
+
targetVisibleArea: number;
|
|
59
|
+
}
|
|
60
|
+
export interface KeypressEvent extends BaseEvent {
|
|
61
|
+
type: 'keypress';
|
|
62
|
+
key: string;
|
|
63
|
+
timeSinceLastKey?: number;
|
|
64
|
+
}
|
|
65
|
+
export interface EnvironmentEvent extends BaseEvent {
|
|
66
|
+
type: 'environment';
|
|
67
|
+
screenWidth: number;
|
|
68
|
+
screenHeight: number;
|
|
69
|
+
screenAvailWidth: number;
|
|
70
|
+
screenAvailHeight: number;
|
|
71
|
+
windowWidth: number;
|
|
72
|
+
windowHeight: number;
|
|
73
|
+
devicePixelRatio: number;
|
|
74
|
+
colorDepth: number;
|
|
75
|
+
pixelDepth: number;
|
|
76
|
+
userAgent: string;
|
|
77
|
+
platform: string;
|
|
78
|
+
language: string;
|
|
79
|
+
languages: string[];
|
|
80
|
+
hardwareConcurrency?: number;
|
|
81
|
+
maxTouchPoints: number;
|
|
82
|
+
vendor: string;
|
|
83
|
+
hasWebGL: boolean;
|
|
84
|
+
hasWebRTC: boolean;
|
|
85
|
+
hasNotifications: boolean;
|
|
86
|
+
hasGeolocation: boolean;
|
|
87
|
+
hasIndexedDB: boolean;
|
|
88
|
+
hasLocalStorage: boolean;
|
|
89
|
+
hasSessionStorage: boolean;
|
|
90
|
+
plugins: number;
|
|
91
|
+
mimeTypes: number;
|
|
92
|
+
suspiciousRatio?: boolean;
|
|
93
|
+
suspiciousDimensions?: boolean;
|
|
94
|
+
featureInconsistency?: boolean;
|
|
95
|
+
}
|
|
96
|
+
export type TrackedEvent = TabVisibilityEvent | ScrollEvent | ResizeEvent | MouseMoveEvent | ClickEvent | KeypressEvent | EnvironmentEvent;
|
|
97
|
+
export interface EventStorage {
|
|
98
|
+
'tab-visibility': TabVisibilityEvent[];
|
|
99
|
+
'scroll': ScrollEvent[];
|
|
100
|
+
'resize': ResizeEvent[];
|
|
101
|
+
'mouse-move': MouseMoveEvent[];
|
|
102
|
+
'click': ClickEvent[];
|
|
103
|
+
'keypress': KeypressEvent[];
|
|
104
|
+
'environment': EnvironmentEvent[];
|
|
105
|
+
}
|
|
106
|
+
export interface ScoreBreakdown {
|
|
107
|
+
overall: number;
|
|
108
|
+
factors: {
|
|
109
|
+
mouseMovement?: number;
|
|
110
|
+
clickAccuracy?: number;
|
|
111
|
+
scrollBehavior?: number;
|
|
112
|
+
keyboardTiming?: number;
|
|
113
|
+
tabActivity?: number;
|
|
114
|
+
resizeBehavior?: number;
|
|
115
|
+
environmentFingerprint?: number;
|
|
116
|
+
};
|
|
117
|
+
weights: {
|
|
118
|
+
mouseMovement: number;
|
|
119
|
+
clickAccuracy: number;
|
|
120
|
+
scrollBehavior: number;
|
|
121
|
+
keyboardTiming: number;
|
|
122
|
+
tabActivity: number;
|
|
123
|
+
resizeBehavior: number;
|
|
124
|
+
environmentFingerprint: number;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export interface ScoreOptions {
|
|
128
|
+
breakdown?: boolean;
|
|
129
|
+
auditTrail?: boolean;
|
|
130
|
+
}
|
|
131
|
+
export interface ScoreResult {
|
|
132
|
+
score: number;
|
|
133
|
+
breakdown?: ScoreBreakdown;
|
|
134
|
+
auditTrail?: TrackedEvent[];
|
|
135
|
+
}
|
|
136
|
+
export type ScoringFunction = (events: TrackedEvent[]) => number | undefined;
|
|
137
|
+
export interface BehaviorSettings {
|
|
138
|
+
sampleRates?: {
|
|
139
|
+
mouseMove?: number;
|
|
140
|
+
scroll?: number;
|
|
141
|
+
keypress?: number;
|
|
142
|
+
};
|
|
143
|
+
rollingWindows?: {
|
|
144
|
+
mouseMove?: number;
|
|
145
|
+
scroll?: number;
|
|
146
|
+
};
|
|
147
|
+
weights?: {
|
|
148
|
+
mouseMovement?: number;
|
|
149
|
+
clickAccuracy?: number;
|
|
150
|
+
scrollBehavior?: number;
|
|
151
|
+
keyboardTiming?: number;
|
|
152
|
+
tabActivity?: number;
|
|
153
|
+
resizeBehavior?: number;
|
|
154
|
+
environmentFingerprint?: number;
|
|
155
|
+
};
|
|
156
|
+
customScorers?: {
|
|
157
|
+
mouseMovement?: ScoringFunction;
|
|
158
|
+
clickAccuracy?: ScoringFunction;
|
|
159
|
+
scrollBehavior?: ScoringFunction;
|
|
160
|
+
keyboardTiming?: ScoringFunction;
|
|
161
|
+
tabActivity?: ScoringFunction;
|
|
162
|
+
resizeBehavior?: ScoringFunction;
|
|
163
|
+
environmentFingerprint?: ScoringFunction;
|
|
164
|
+
};
|
|
165
|
+
clickMouseHistoryWindow?: number;
|
|
166
|
+
useWebWorker?: boolean;
|
|
167
|
+
}
|
|
168
|
+
export declare const DEFAULT_SETTINGS: Required<BehaviorSettings>;
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@axeptio/behavior-detection",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Lightweight behavior detection library to assess human likelihood of user sessions",
|
|
5
|
+
"main": "./dist/cjs/index.js",
|
|
6
|
+
"module": "./dist/esm/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/esm/index.js",
|
|
12
|
+
"require": "./dist/cjs/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "npm run build:cjs && npm run build:esm && npm run build:types",
|
|
20
|
+
"build:cjs": "tsc --module commonjs --outDir dist/cjs",
|
|
21
|
+
"build:esm": "tsc --module es2015 --outDir dist/esm",
|
|
22
|
+
"build:types": "tsc --declaration --emitDeclarationOnly --outDir dist",
|
|
23
|
+
"build:bundle": "npm run build:esm && esbuild dist/esm/index.js --bundle --minify --sourcemap --target=es2020 --tree-shaking=true --outfile=dist/behavior-detection.esm.min.js",
|
|
24
|
+
"build:browser": "npm run build:esm && esbuild dist/esm/browser.js --bundle --minify --sourcemap --format=iife --target=es2017 --tree-shaking=true --drop:console --drop:debugger --outfile=dist/behavior-detection.min.js",
|
|
25
|
+
"build:browser:dev": "npm run build:esm && esbuild dist/esm/browser.js --bundle --minify --sourcemap --format=iife --global-name=BehaviorDetector --target=es2020 --tree-shaking=true --outfile=dist/behavior-detection.min.js",
|
|
26
|
+
"build:all": "npm run build && npm run build:bundle && npm run build:browser",
|
|
27
|
+
"clean": "rm -rf dist",
|
|
28
|
+
"deploy": "node scripts/deploy.js",
|
|
29
|
+
"release:patch": "npm version patch && git push && git push --tags",
|
|
30
|
+
"release:minor": "npm version minor && git push && git push --tags",
|
|
31
|
+
"release:major": "npm version major && git push && git push --tags",
|
|
32
|
+
"tryme": "npm run build && node scripts/serve.js",
|
|
33
|
+
"test": "npm run build && node tests/adversarial/run-tests.js",
|
|
34
|
+
"test:adversarial": "npm run build && node tests/adversarial/run-all.js",
|
|
35
|
+
"test:playwright": "npm run build && node tests/adversarial/playwright-test.js",
|
|
36
|
+
"test:selenium": "npm run build && node tests/adversarial/selenium-test.js",
|
|
37
|
+
"test:puppeteer": "npm run build && node tests/adversarial/puppeteer-test.js",
|
|
38
|
+
"test:stress": "npm run build && node tests/adversarial/detector-stress-test.js",
|
|
39
|
+
"test:stress:quick": "npm run build && node tests/adversarial/detector-stress-test.js --cycles=3 --duration=5000",
|
|
40
|
+
"test:stress:intense": "npm run build && node tests/adversarial/detector-stress-test.js --cycles=10 --duration=20000"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"behavior-detection",
|
|
44
|
+
"bot-detection",
|
|
45
|
+
"user-tracking",
|
|
46
|
+
"analytics"
|
|
47
|
+
],
|
|
48
|
+
"author": "Axeptio",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"typescript": "latest",
|
|
52
|
+
"@playwright/test": "latest",
|
|
53
|
+
"puppeteer": "latest",
|
|
54
|
+
"selenium-webdriver": "latest",
|
|
55
|
+
"chromedriver": "latest",
|
|
56
|
+
"esbuild": "latest",
|
|
57
|
+
"@aws-sdk/client-s3": "^3.515.0",
|
|
58
|
+
"@aws-sdk/client-cloudfront": "^3.515.0"
|
|
59
|
+
}
|
|
60
|
+
}
|