@axeptio/behavior-detection 1.0.2 → 1.0.3

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.
@@ -1,173 +0,0 @@
1
- "use strict";
2
- /**
3
- * Click Behavior Detection Strategy
4
- * Monitors specific elements for click positioning patterns
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ClickStrategy = void 0;
8
- const strategy_js_1 = require("../strategy.js");
9
- class ClickStrategy extends strategy_js_1.BaseStrategy {
10
- constructor(options) {
11
- super();
12
- this.name = 'click';
13
- this.defaultWeight = 0.30;
14
- this.events = [];
15
- this.targetSelectors = ['button', 'a', 'input[type="submit"]', '[role="button"]'];
16
- this.lastMousePosition = null;
17
- this.mouseListener = null;
18
- this.clickListeners = new Map();
19
- this.isActive = false;
20
- if (options === null || options === void 0 ? void 0 : options.targetSelectors) {
21
- this.targetSelectors = options.targetSelectors;
22
- }
23
- }
24
- start() {
25
- if (this.isActive)
26
- return;
27
- this.isActive = true;
28
- // Track mouse position globally
29
- this.mouseListener = (e) => {
30
- const mouseEvent = e;
31
- this.lastMousePosition = {
32
- x: mouseEvent.clientX,
33
- y: mouseEvent.clientY,
34
- };
35
- };
36
- document.addEventListener('mousemove', this.mouseListener, { passive: true });
37
- // Find all matching elements and attach listeners
38
- this.attachClickListeners();
39
- }
40
- /**
41
- * Add a new target selector at runtime
42
- */
43
- addTarget(selector) {
44
- if (!this.targetSelectors.includes(selector)) {
45
- this.targetSelectors.push(selector);
46
- // Attach listeners if already active
47
- if (this.isActive) {
48
- this.attachClickListenersForSelector(selector);
49
- }
50
- }
51
- }
52
- attachClickListeners() {
53
- this.targetSelectors.forEach(selector => {
54
- this.attachClickListenersForSelector(selector);
55
- });
56
- }
57
- attachClickListenersForSelector(selector) {
58
- const elements = document.querySelectorAll(selector);
59
- elements.forEach(element => {
60
- if (this.clickListeners.has(element))
61
- return; // Already attached
62
- const listener = (e) => {
63
- var _a, _b;
64
- const clickEvent = e;
65
- const rect = element.getBoundingClientRect();
66
- // Check if element is in viewport
67
- const inViewport = (rect.top >= 0 &&
68
- rect.left >= 0 &&
69
- rect.bottom <= window.innerHeight &&
70
- rect.right <= window.innerWidth);
71
- // Analyze click position
72
- let position;
73
- if (!this.lastMousePosition) {
74
- position = 'no-mouse-data'; // Bot - no mouse movement
75
- }
76
- else {
77
- const mx = this.lastMousePosition.x;
78
- const my = this.lastMousePosition.y;
79
- // Check if mouse was over element
80
- const overElement = (mx >= rect.left &&
81
- mx <= rect.right &&
82
- my >= rect.top &&
83
- my <= rect.bottom);
84
- if (!overElement) {
85
- position = 'outside'; // Bot - mouse not over target
86
- }
87
- else {
88
- // Check if dead center (suspicious)
89
- const centerX = rect.left + rect.width / 2;
90
- const centerY = rect.top + rect.height / 2;
91
- const distanceFromCenter = Math.sqrt((mx - centerX) ** 2 + (my - centerY) ** 2);
92
- // Dead center = within 2px of center
93
- if (distanceFromCenter < 2) {
94
- position = 'dead-center'; // Suspicious - too perfect
95
- }
96
- else {
97
- position = 'over-element'; // Human - somewhere on the button
98
- }
99
- }
100
- }
101
- this.events.push({
102
- clickX: clickEvent.clientX,
103
- clickY: clickEvent.clientY,
104
- mouseX: (_a = this.lastMousePosition) === null || _a === void 0 ? void 0 : _a.x,
105
- mouseY: (_b = this.lastMousePosition) === null || _b === void 0 ? void 0 : _b.y,
106
- rect,
107
- inViewport,
108
- position,
109
- timestamp: Date.now(),
110
- });
111
- // Notify detector - clicks are high-value events
112
- this.notifyEvent(1.0);
113
- };
114
- element.addEventListener('click', listener);
115
- this.clickListeners.set(element, listener);
116
- });
117
- }
118
- stop() {
119
- if (!this.isActive)
120
- return;
121
- this.isActive = false;
122
- // Remove mouse listener
123
- if (this.mouseListener) {
124
- document.removeEventListener('mousemove', this.mouseListener);
125
- this.mouseListener = null;
126
- }
127
- // Remove all click listeners
128
- this.clickListeners.forEach((listener, element) => {
129
- element.removeEventListener('click', listener);
130
- });
131
- this.clickListeners.clear();
132
- }
133
- reset() {
134
- this.events = [];
135
- this.lastMousePosition = null;
136
- }
137
- score() {
138
- if (this.events.length === 0)
139
- return undefined;
140
- let totalScore = 0;
141
- for (const click of this.events) {
142
- switch (click.position) {
143
- case 'no-mouse-data':
144
- totalScore += 0.0; // Bot - no mouse movement
145
- break;
146
- case 'outside':
147
- totalScore += 0.0; // Bot - mouse not over target
148
- break;
149
- case 'dead-center':
150
- totalScore += 0.5; // Suspicious - too perfect
151
- break;
152
- case 'over-element':
153
- totalScore += 1.0; // Human - natural click
154
- break;
155
- }
156
- }
157
- return totalScore / this.events.length;
158
- }
159
- getDebugInfo() {
160
- return {
161
- eventCount: this.events.length,
162
- positions: {
163
- noMouseData: this.events.filter(e => e.position === 'no-mouse-data').length,
164
- outside: this.events.filter(e => e.position === 'outside').length,
165
- deadCenter: this.events.filter(e => e.position === 'dead-center').length,
166
- overElement: this.events.filter(e => e.position === 'over-element').length,
167
- },
168
- inViewport: this.events.filter(e => e.inViewport).length,
169
- trackedElements: this.clickListeners.size,
170
- };
171
- }
172
- }
173
- exports.ClickStrategy = ClickStrategy;
@@ -1,52 +0,0 @@
1
- /**
2
- * Environment Fingerprinting Strategy
3
- * Captures browser environment on initialization and tick updates
4
- */
5
- import { BaseStrategy } from '../strategy.js';
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 {};
@@ -1,148 +0,0 @@
1
- "use strict";
2
- /**
3
- * Environment Fingerprinting Strategy
4
- * Captures browser environment on initialization and tick updates
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.EnvironmentStrategy = void 0;
8
- const strategy_js_1 = require("../strategy.js");
9
- const math_utils_js_1 = require("../math-utils.js");
10
- class EnvironmentStrategy extends strategy_js_1.BaseStrategy {
11
- constructor() {
12
- super(...arguments);
13
- this.name = 'environment';
14
- this.defaultWeight = 0.08;
15
- this.data = null;
16
- }
17
- start() {
18
- this.captureEnvironment();
19
- }
20
- stop() {
21
- // Environment data persists
22
- }
23
- reset() {
24
- this.data = null;
25
- }
26
- onTick(_timestamp) {
27
- // Re-capture environment periodically to detect changes
28
- this.captureEnvironment();
29
- }
30
- score() {
31
- if (!this.data)
32
- return undefined;
33
- const env = this.data;
34
- let score = 0;
35
- let factors = 0;
36
- // Suspicious indicators
37
- score += env.suspiciousDimensions ? 0.1 : 1.0;
38
- score += env.suspiciousRatio ? 0.2 : 1.0;
39
- score += env.featureInconsistency ? 0.3 : 1.0;
40
- factors += 3;
41
- // Browser features
42
- const featureCount = [
43
- env.hasWebGL,
44
- env.hasLocalStorage,
45
- env.hasSessionStorage,
46
- env.hasIndexedDB,
47
- ].filter(Boolean).length;
48
- score += featureCount / 4;
49
- factors++;
50
- // Plugins
51
- score += (0, math_utils_js_1.inverseSigmoid)(env.plugins, -2, -0.5);
52
- score += (env.plugins > 0 ? 1.0 : 0.1);
53
- factors += 2;
54
- // Device
55
- score += (0, math_utils_js_1.gaussian)(env.devicePixelRatio, 2, 1.5);
56
- score += (env.colorDepth === 24 || env.colorDepth === 32) ? 1.0 : 0.4;
57
- factors += 2;
58
- return factors > 0 ? score / factors : undefined;
59
- }
60
- isMobileDevice() {
61
- // Multiple checks for mobile detection
62
- const hasTouchScreen = navigator.maxTouchPoints > 0 || 'ontouchstart' in window;
63
- const mobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
64
- const smallScreen = window.innerWidth < 768 && window.innerHeight < 1024;
65
- return (hasTouchScreen && smallScreen) || mobileUA;
66
- }
67
- captureEnvironment() {
68
- try {
69
- // WebGL detection
70
- let hasWebGL = false;
71
- try {
72
- const canvas = document.createElement('canvas');
73
- hasWebGL = !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
74
- }
75
- catch (e) {
76
- hasWebGL = false;
77
- }
78
- // WebRTC detection
79
- const hasWebRTC = !!(window.RTCPeerConnection ||
80
- window.mozRTCPeerConnection ||
81
- window.webkitRTCPeerConnection);
82
- // Mobile detection
83
- const isMobile = this.isMobileDevice();
84
- const windowWidth = window.innerWidth;
85
- const windowHeight = window.innerHeight;
86
- const screenWidth = window.screen.width;
87
- const screenHeight = window.screen.height;
88
- // Suspicious dimensions
89
- const suspiciousDimensions = (windowWidth === 800 && windowHeight === 600) ||
90
- (windowWidth === 1024 && windowHeight === 768) ||
91
- (windowWidth === 1280 && windowHeight === 720) ||
92
- (screenWidth === 800 && screenHeight === 600);
93
- // Suspicious ratio
94
- const windowScreenRatio = (windowWidth * windowHeight) / (screenWidth * screenHeight);
95
- const suspiciousRatio = windowScreenRatio === 1.0 ||
96
- windowScreenRatio < 0.1 ||
97
- windowScreenRatio > 1.0;
98
- // Feature inconsistency
99
- const hasStorage = typeof localStorage !== 'undefined' && typeof sessionStorage !== 'undefined';
100
- const featureInconsistency = (navigator.plugins.length === 0 && navigator.mimeTypes.length === 0) ||
101
- !hasWebGL ||
102
- !hasStorage;
103
- this.data = {
104
- screenWidth,
105
- screenHeight,
106
- windowWidth,
107
- windowHeight,
108
- devicePixelRatio: window.devicePixelRatio,
109
- colorDepth: window.screen.colorDepth,
110
- userAgent: navigator.userAgent,
111
- platform: navigator.platform,
112
- language: navigator.language,
113
- languages: navigator.languages ? Array.from(navigator.languages) : [navigator.language],
114
- hardwareConcurrency: navigator.hardwareConcurrency,
115
- maxTouchPoints: navigator.maxTouchPoints || 0,
116
- vendor: navigator.vendor,
117
- hasWebGL,
118
- hasWebRTC,
119
- hasLocalStorage: typeof localStorage !== 'undefined',
120
- hasSessionStorage: typeof sessionStorage !== 'undefined',
121
- hasIndexedDB: 'indexedDB' in window,
122
- plugins: navigator.plugins.length,
123
- mimeTypes: navigator.mimeTypes.length,
124
- suspiciousRatio,
125
- suspiciousDimensions,
126
- featureInconsistency,
127
- isMobile,
128
- timestamp: Date.now(),
129
- };
130
- }
131
- catch (error) {
132
- console.warn('Failed to capture environment:', error);
133
- }
134
- }
135
- getDebugInfo() {
136
- return this.data;
137
- }
138
- /**
139
- * Check if current device is mobile
140
- * Returns true if mobile, false otherwise
141
- * Returns null if environment hasn't been captured yet
142
- */
143
- isMobile() {
144
- var _a, _b;
145
- return (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.isMobile) !== null && _b !== void 0 ? _b : null;
146
- }
147
- }
148
- exports.EnvironmentStrategy = EnvironmentStrategy;
@@ -1,18 +0,0 @@
1
- /**
2
- * Detection Strategies - Modular behavior analysis
3
- * Import only what you need for optimal bundle size
4
- */
5
- export { MouseStrategy } from './mouse.js';
6
- export { ScrollStrategy } from './scroll.js';
7
- export { ClickStrategy } from './click.js';
8
- export { TapStrategy } from './tap.js';
9
- export { KeyboardStrategy } from './keyboard.js';
10
- export { EnvironmentStrategy } from './environment.js';
11
- export { ResizeStrategy } from './resize.js';
12
- export { MouseStrategy as Mouse } from './mouse.js';
13
- export { ScrollStrategy as Scroll } from './scroll.js';
14
- export { ClickStrategy as Click } from './click.js';
15
- export { TapStrategy as Tap } from './tap.js';
16
- export { KeyboardStrategy as Keyboard } from './keyboard.js';
17
- export { EnvironmentStrategy as Environment } from './environment.js';
18
- export { ResizeStrategy as Resize } from './resize.js';
@@ -1,36 +0,0 @@
1
- "use strict";
2
- /**
3
- * Detection Strategies - Modular behavior analysis
4
- * Import only what you need for optimal bundle size
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.Resize = exports.Environment = exports.Keyboard = exports.Tap = exports.Click = exports.Scroll = exports.Mouse = exports.ResizeStrategy = exports.EnvironmentStrategy = exports.KeyboardStrategy = exports.TapStrategy = exports.ClickStrategy = exports.ScrollStrategy = exports.MouseStrategy = void 0;
8
- var mouse_js_1 = require("./mouse.js");
9
- Object.defineProperty(exports, "MouseStrategy", { enumerable: true, get: function () { return mouse_js_1.MouseStrategy; } });
10
- var scroll_js_1 = require("./scroll.js");
11
- Object.defineProperty(exports, "ScrollStrategy", { enumerable: true, get: function () { return scroll_js_1.ScrollStrategy; } });
12
- var click_js_1 = require("./click.js");
13
- Object.defineProperty(exports, "ClickStrategy", { enumerable: true, get: function () { return click_js_1.ClickStrategy; } });
14
- var tap_js_1 = require("./tap.js");
15
- Object.defineProperty(exports, "TapStrategy", { enumerable: true, get: function () { return tap_js_1.TapStrategy; } });
16
- var keyboard_js_1 = require("./keyboard.js");
17
- Object.defineProperty(exports, "KeyboardStrategy", { enumerable: true, get: function () { return keyboard_js_1.KeyboardStrategy; } });
18
- var environment_js_1 = require("./environment.js");
19
- Object.defineProperty(exports, "EnvironmentStrategy", { enumerable: true, get: function () { return environment_js_1.EnvironmentStrategy; } });
20
- var resize_js_1 = require("./resize.js");
21
- Object.defineProperty(exports, "ResizeStrategy", { enumerable: true, get: function () { return resize_js_1.ResizeStrategy; } });
22
- // Convenience: All strategies
23
- var mouse_js_2 = require("./mouse.js");
24
- Object.defineProperty(exports, "Mouse", { enumerable: true, get: function () { return mouse_js_2.MouseStrategy; } });
25
- var scroll_js_2 = require("./scroll.js");
26
- Object.defineProperty(exports, "Scroll", { enumerable: true, get: function () { return scroll_js_2.ScrollStrategy; } });
27
- var click_js_2 = require("./click.js");
28
- Object.defineProperty(exports, "Click", { enumerable: true, get: function () { return click_js_2.ClickStrategy; } });
29
- var tap_js_2 = require("./tap.js");
30
- Object.defineProperty(exports, "Tap", { enumerable: true, get: function () { return tap_js_2.TapStrategy; } });
31
- var keyboard_js_2 = require("./keyboard.js");
32
- Object.defineProperty(exports, "Keyboard", { enumerable: true, get: function () { return keyboard_js_2.KeyboardStrategy; } });
33
- var environment_js_2 = require("./environment.js");
34
- Object.defineProperty(exports, "Environment", { enumerable: true, get: function () { return environment_js_2.EnvironmentStrategy; } });
35
- var resize_js_2 = require("./resize.js");
36
- Object.defineProperty(exports, "Resize", { enumerable: true, get: function () { return resize_js_2.ResizeStrategy; } });
@@ -1,43 +0,0 @@
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.js';
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
- }