@surbee/cipher 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -0
- package/dist/checks/index.d.mts +215 -0
- package/dist/checks/index.d.ts +215 -0
- package/dist/checks/index.js +1157 -0
- package/dist/checks/index.mjs +60 -0
- package/dist/chunk-P2MIOVFQ.mjs +1104 -0
- package/dist/index.d.mts +38 -244
- package/dist/index.d.ts +38 -244
- package/dist/index.js +1716 -35
- package/dist/index.mjs +649 -35
- package/dist/types-C8t_T3bP.d.mts +251 -0
- package/dist/types-C8t_T3bP.d.ts +251 -0
- package/package.json +16 -4
- package/src/checks/behavioral.ts +0 -527
- package/src/checks/content.ts +0 -372
- package/src/checks/device.ts +0 -384
- package/src/checks/index.ts +0 -59
- package/src/checks/timing.ts +0 -256
- package/src/cipher.ts +0 -225
- package/src/index.ts +0 -75
- package/src/tiers.ts +0 -507
- package/src/types.ts +0 -366
- package/test/cipher.test.ts +0 -245
- package/test/fixtures.ts +0 -627
- package/tsconfig.json +0 -20
package/test/fixtures.ts
DELETED
|
@@ -1,627 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test fixtures for Cipher SDK
|
|
3
|
-
*
|
|
4
|
-
* Contains mock data for testing different validation scenarios.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type {
|
|
8
|
-
ValidationInput,
|
|
9
|
-
ResponseInput,
|
|
10
|
-
BehavioralMetrics,
|
|
11
|
-
DeviceInfo,
|
|
12
|
-
MouseMovement,
|
|
13
|
-
KeystrokeEvent,
|
|
14
|
-
MouseClick,
|
|
15
|
-
ScrollEvent,
|
|
16
|
-
FocusEvent,
|
|
17
|
-
} from '../src/types';
|
|
18
|
-
|
|
19
|
-
// =============================================================================
|
|
20
|
-
// RESPONSE FIXTURES
|
|
21
|
-
// =============================================================================
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* High-quality, legitimate survey responses
|
|
25
|
-
*/
|
|
26
|
-
export const legitimateResponses: ResponseInput[] = [
|
|
27
|
-
{
|
|
28
|
-
question: 'What do you like most about our product?',
|
|
29
|
-
answer: 'I really appreciate the intuitive interface and how easy it is to navigate. The customer support team has also been incredibly helpful whenever I had questions.',
|
|
30
|
-
questionType: 'text',
|
|
31
|
-
responseTimeMs: 45000, // 45 seconds - thoughtful
|
|
32
|
-
questionIndex: 0,
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
question: 'How would you rate our service? (1-5)',
|
|
36
|
-
answer: '4',
|
|
37
|
-
questionType: 'rating',
|
|
38
|
-
responseTimeMs: 3000,
|
|
39
|
-
questionIndex: 1,
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
question: 'How likely are you to recommend us? (1-10)',
|
|
43
|
-
answer: '8',
|
|
44
|
-
questionType: 'scale',
|
|
45
|
-
responseTimeMs: 4000,
|
|
46
|
-
questionIndex: 2,
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
question: 'What improvements would you suggest?',
|
|
50
|
-
answer: 'It would be great to have a mobile app version. Also, adding dark mode would be helpful for late-night work sessions.',
|
|
51
|
-
questionType: 'text',
|
|
52
|
-
responseTimeMs: 38000,
|
|
53
|
-
questionIndex: 3,
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
question: 'Which features do you use most?',
|
|
57
|
-
answer: 'Dashboard',
|
|
58
|
-
questionType: 'multiple_choice',
|
|
59
|
-
responseTimeMs: 5000,
|
|
60
|
-
questionIndex: 4,
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Low-effort/spam responses
|
|
66
|
-
*/
|
|
67
|
-
export const spamResponses: ResponseInput[] = [
|
|
68
|
-
{
|
|
69
|
-
question: 'What do you like most about our product?',
|
|
70
|
-
answer: 'good',
|
|
71
|
-
questionType: 'text',
|
|
72
|
-
responseTimeMs: 1200, // Way too fast
|
|
73
|
-
questionIndex: 0,
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
question: 'How would you rate our service? (1-5)',
|
|
77
|
-
answer: '5',
|
|
78
|
-
questionType: 'rating',
|
|
79
|
-
responseTimeMs: 500,
|
|
80
|
-
questionIndex: 1,
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
question: 'How likely are you to recommend us? (1-10)',
|
|
84
|
-
answer: '5',
|
|
85
|
-
questionType: 'scale',
|
|
86
|
-
responseTimeMs: 400,
|
|
87
|
-
questionIndex: 2,
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
question: 'What improvements would you suggest?',
|
|
91
|
-
answer: 'n/a',
|
|
92
|
-
questionType: 'text',
|
|
93
|
-
responseTimeMs: 800,
|
|
94
|
-
questionIndex: 3,
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
question: 'Which features do you use most?',
|
|
98
|
-
answer: 'Dashboard',
|
|
99
|
-
questionType: 'multiple_choice',
|
|
100
|
-
responseTimeMs: 300,
|
|
101
|
-
questionIndex: 4,
|
|
102
|
-
},
|
|
103
|
-
];
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Straight-lining responses (same answer for all scale questions)
|
|
107
|
-
*/
|
|
108
|
-
export const straightLiningResponses: ResponseInput[] = [
|
|
109
|
-
{
|
|
110
|
-
question: 'How satisfied are you with feature A? (1-5)',
|
|
111
|
-
answer: '3',
|
|
112
|
-
questionType: 'rating',
|
|
113
|
-
responseTimeMs: 2000,
|
|
114
|
-
questionIndex: 0,
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
question: 'How satisfied are you with feature B? (1-5)',
|
|
118
|
-
answer: '3',
|
|
119
|
-
questionType: 'rating',
|
|
120
|
-
responseTimeMs: 1800,
|
|
121
|
-
questionIndex: 1,
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
question: 'How satisfied are you with feature C? (1-5)',
|
|
125
|
-
answer: '3',
|
|
126
|
-
questionType: 'rating',
|
|
127
|
-
responseTimeMs: 1900,
|
|
128
|
-
questionIndex: 2,
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
question: 'How satisfied are you with feature D? (1-5)',
|
|
132
|
-
answer: '3',
|
|
133
|
-
questionType: 'rating',
|
|
134
|
-
responseTimeMs: 1700,
|
|
135
|
-
questionIndex: 3,
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
question: 'How satisfied are you with feature E? (1-5)',
|
|
139
|
-
answer: '3',
|
|
140
|
-
questionType: 'rating',
|
|
141
|
-
responseTimeMs: 1850,
|
|
142
|
-
questionIndex: 4,
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
question: 'How satisfied are you with feature F? (1-5)',
|
|
146
|
-
answer: '3',
|
|
147
|
-
questionType: 'rating',
|
|
148
|
-
responseTimeMs: 1750,
|
|
149
|
-
questionIndex: 5,
|
|
150
|
-
},
|
|
151
|
-
];
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Bot-like rapid completion
|
|
155
|
-
*/
|
|
156
|
-
export const botResponses: ResponseInput[] = [
|
|
157
|
-
{
|
|
158
|
-
question: 'Describe your experience',
|
|
159
|
-
answer: 'The experience was satisfactory and met expectations adequately.',
|
|
160
|
-
questionType: 'text',
|
|
161
|
-
responseTimeMs: 800, // Impossibly fast for this text length
|
|
162
|
-
questionIndex: 0,
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
question: 'Rate overall satisfaction (1-5)',
|
|
166
|
-
answer: '4',
|
|
167
|
-
questionType: 'rating',
|
|
168
|
-
responseTimeMs: 100, // Way too fast
|
|
169
|
-
questionIndex: 1,
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
question: 'Additional comments',
|
|
173
|
-
answer: 'No additional comments at this time. Thank you for the survey.',
|
|
174
|
-
questionType: 'text',
|
|
175
|
-
responseTimeMs: 500, // Impossibly fast
|
|
176
|
-
questionIndex: 2,
|
|
177
|
-
},
|
|
178
|
-
];
|
|
179
|
-
|
|
180
|
-
// =============================================================================
|
|
181
|
-
// BEHAVIORAL METRICS FIXTURES
|
|
182
|
-
// =============================================================================
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Normal human behavioral metrics
|
|
186
|
-
*/
|
|
187
|
-
export const normalBehavior: BehavioralMetrics = {
|
|
188
|
-
sessionId: 'test-session-001',
|
|
189
|
-
startedAt: Date.now() - 180000,
|
|
190
|
-
duration: 180000, // 3 minutes
|
|
191
|
-
lastActiveAt: Date.now(),
|
|
192
|
-
mouseMovements: generateHumanMouseMovements(100),
|
|
193
|
-
mouseClicks: generateHumanClicks(15),
|
|
194
|
-
mouseMovementCount: 450,
|
|
195
|
-
avgMouseVelocity: 8.5,
|
|
196
|
-
keystrokeDynamics: generateHumanKeystrokes(50),
|
|
197
|
-
keypressCount: 280,
|
|
198
|
-
backspaceCount: 28,
|
|
199
|
-
avgKeystrokeDwell: 120,
|
|
200
|
-
keystrokeVariance: 0.35,
|
|
201
|
-
scrollEvents: generateHumanScrolls(10),
|
|
202
|
-
scrollEventCount: 35,
|
|
203
|
-
focusEvents: [{ type: 'focus', t: 0 }, { type: 'blur', t: 60000 }, { type: 'focus', t: 65000 }],
|
|
204
|
-
tabSwitchCount: 2,
|
|
205
|
-
totalBlurDuration: 5000,
|
|
206
|
-
pasteEvents: 0,
|
|
207
|
-
copyEvents: 0,
|
|
208
|
-
hoverEvents: [],
|
|
209
|
-
responseTime: [45000, 3000, 4000, 38000, 5000],
|
|
210
|
-
questionStartTimes: { 'q0': 0, 'q1': 45000, 'q2': 48000, 'q3': 52000, 'q4': 90000 },
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Bot-like behavioral metrics
|
|
215
|
-
*/
|
|
216
|
-
export const botBehavior: BehavioralMetrics = {
|
|
217
|
-
sessionId: 'test-session-bot',
|
|
218
|
-
startedAt: Date.now() - 15000,
|
|
219
|
-
duration: 15000, // 15 seconds - way too fast
|
|
220
|
-
lastActiveAt: Date.now(),
|
|
221
|
-
mouseMovements: generateRoboticMouseMovements(20),
|
|
222
|
-
mouseClicks: generateRoboticClicks(5),
|
|
223
|
-
mouseMovementCount: 20,
|
|
224
|
-
avgMouseVelocity: 10, // Constant
|
|
225
|
-
keystrokeDynamics: [], // No typing
|
|
226
|
-
keypressCount: 0,
|
|
227
|
-
backspaceCount: 0, // No corrections
|
|
228
|
-
avgKeystrokeDwell: 0,
|
|
229
|
-
keystrokeVariance: 0,
|
|
230
|
-
scrollEvents: generateRoboticScrolls(2),
|
|
231
|
-
scrollEventCount: 2,
|
|
232
|
-
focusEvents: [{ type: 'focus', t: 0 }],
|
|
233
|
-
tabSwitchCount: 0,
|
|
234
|
-
totalBlurDuration: 0,
|
|
235
|
-
pasteEvents: 5, // All pasted
|
|
236
|
-
copyEvents: 0,
|
|
237
|
-
hoverEvents: [],
|
|
238
|
-
responseTime: [800, 100, 500],
|
|
239
|
-
questionStartTimes: { 'q0': 0, 'q1': 800, 'q2': 900 },
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Suspicious behavioral metrics (paste-heavy)
|
|
244
|
-
*/
|
|
245
|
-
export const pasteHeavyBehavior: BehavioralMetrics = {
|
|
246
|
-
sessionId: 'test-session-paste',
|
|
247
|
-
startedAt: Date.now() - 60000,
|
|
248
|
-
duration: 60000, // 1 minute
|
|
249
|
-
lastActiveAt: Date.now(),
|
|
250
|
-
mouseMovements: generateHumanMouseMovements(50),
|
|
251
|
-
mouseClicks: generateHumanClicks(8),
|
|
252
|
-
mouseMovementCount: 150,
|
|
253
|
-
avgMouseVelocity: 7.2,
|
|
254
|
-
keystrokeDynamics: generateHumanKeystrokes(10),
|
|
255
|
-
keypressCount: 10,
|
|
256
|
-
backspaceCount: 0,
|
|
257
|
-
avgKeystrokeDwell: 110,
|
|
258
|
-
keystrokeVariance: 0.28,
|
|
259
|
-
scrollEvents: generateHumanScrolls(5),
|
|
260
|
-
scrollEventCount: 8,
|
|
261
|
-
focusEvents: [
|
|
262
|
-
{ type: 'focus', t: 0 },
|
|
263
|
-
{ type: 'blur', t: 5000 },
|
|
264
|
-
{ type: 'focus', t: 10000 },
|
|
265
|
-
{ type: 'blur', t: 15000 },
|
|
266
|
-
{ type: 'focus', t: 25000 },
|
|
267
|
-
{ type: 'blur', t: 30000 },
|
|
268
|
-
{ type: 'focus', t: 50000 },
|
|
269
|
-
],
|
|
270
|
-
tabSwitchCount: 12, // Many tab switches
|
|
271
|
-
totalBlurDuration: 40000, // 66% time away
|
|
272
|
-
pasteEvents: 8, // Heavy pasting
|
|
273
|
-
copyEvents: 0,
|
|
274
|
-
hoverEvents: [],
|
|
275
|
-
responseTime: [15000, 8000, 12000, 18000, 7000],
|
|
276
|
-
questionStartTimes: { 'q0': 0, 'q1': 15000, 'q2': 23000, 'q3': 35000, 'q4': 53000 },
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
// =============================================================================
|
|
280
|
-
// DEVICE INFO FIXTURES
|
|
281
|
-
// =============================================================================
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Normal desktop device
|
|
285
|
-
*/
|
|
286
|
-
export const normalDevice: DeviceInfo = {
|
|
287
|
-
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
288
|
-
platform: 'MacIntel',
|
|
289
|
-
language: 'en-US',
|
|
290
|
-
languages: ['en-US', 'en'],
|
|
291
|
-
timezone: 'America/New_York',
|
|
292
|
-
timezoneOffset: 300,
|
|
293
|
-
screenWidth: 1920,
|
|
294
|
-
screenHeight: 1080,
|
|
295
|
-
screenAvailWidth: 1920,
|
|
296
|
-
screenAvailHeight: 1055,
|
|
297
|
-
colorDepth: 24,
|
|
298
|
-
pixelRatio: 2,
|
|
299
|
-
touchSupport: false,
|
|
300
|
-
maxTouchPoints: 0,
|
|
301
|
-
hardwareConcurrency: 8,
|
|
302
|
-
deviceMemory: 16,
|
|
303
|
-
cookiesEnabled: true,
|
|
304
|
-
webDriver: false,
|
|
305
|
-
automationDetected: false,
|
|
306
|
-
canvasFingerprint: 'abc123xyz',
|
|
307
|
-
webglVendor: 'Apple Inc.',
|
|
308
|
-
webglRenderer: 'Apple M1',
|
|
309
|
-
pluginCount: 5,
|
|
310
|
-
collectedAt: Date.now(),
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Normal mobile device
|
|
315
|
-
*/
|
|
316
|
-
export const mobileDevice: DeviceInfo = {
|
|
317
|
-
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
|
|
318
|
-
platform: 'iPhone',
|
|
319
|
-
language: 'en-US',
|
|
320
|
-
languages: ['en-US'],
|
|
321
|
-
timezone: 'America/Los_Angeles',
|
|
322
|
-
timezoneOffset: 480,
|
|
323
|
-
screenWidth: 390,
|
|
324
|
-
screenHeight: 844,
|
|
325
|
-
screenAvailWidth: 390,
|
|
326
|
-
screenAvailHeight: 844,
|
|
327
|
-
colorDepth: 24,
|
|
328
|
-
pixelRatio: 3,
|
|
329
|
-
touchSupport: true,
|
|
330
|
-
maxTouchPoints: 5,
|
|
331
|
-
hardwareConcurrency: 6,
|
|
332
|
-
deviceMemory: 4,
|
|
333
|
-
cookiesEnabled: true,
|
|
334
|
-
webDriver: false,
|
|
335
|
-
automationDetected: false,
|
|
336
|
-
canvasFingerprint: 'mobile123',
|
|
337
|
-
webglVendor: 'Apple Inc.',
|
|
338
|
-
webglRenderer: 'Apple GPU',
|
|
339
|
-
pluginCount: 0, // Normal for mobile
|
|
340
|
-
collectedAt: Date.now(),
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Headless browser / bot device
|
|
345
|
-
*/
|
|
346
|
-
export const headlessDevice: DeviceInfo = {
|
|
347
|
-
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/120.0.0.0 Safari/537.36',
|
|
348
|
-
platform: 'Linux x86_64',
|
|
349
|
-
language: 'en-US',
|
|
350
|
-
languages: ['en-US'],
|
|
351
|
-
timezone: 'UTC',
|
|
352
|
-
timezoneOffset: 0,
|
|
353
|
-
screenWidth: 800,
|
|
354
|
-
screenHeight: 600,
|
|
355
|
-
screenAvailWidth: 800,
|
|
356
|
-
screenAvailHeight: 600,
|
|
357
|
-
colorDepth: 24,
|
|
358
|
-
pixelRatio: 1,
|
|
359
|
-
touchSupport: false,
|
|
360
|
-
maxTouchPoints: 0,
|
|
361
|
-
hardwareConcurrency: 4,
|
|
362
|
-
deviceMemory: 8,
|
|
363
|
-
cookiesEnabled: true,
|
|
364
|
-
webDriver: true,
|
|
365
|
-
automationDetected: true,
|
|
366
|
-
canvasFingerprint: null,
|
|
367
|
-
webglVendor: null,
|
|
368
|
-
webglRenderer: null,
|
|
369
|
-
pluginCount: 0,
|
|
370
|
-
collectedAt: Date.now(),
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Spoofed/mismatched device
|
|
375
|
-
*/
|
|
376
|
-
export const spoofedDevice: DeviceInfo = {
|
|
377
|
-
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
378
|
-
platform: 'Win32',
|
|
379
|
-
language: 'en-US',
|
|
380
|
-
languages: ['en-US'],
|
|
381
|
-
timezone: 'America/New_York',
|
|
382
|
-
timezoneOffset: 1000, // Invalid offset
|
|
383
|
-
screenWidth: 1920,
|
|
384
|
-
screenHeight: 1080,
|
|
385
|
-
screenAvailWidth: 2000, // Impossible: larger than screen
|
|
386
|
-
screenAvailHeight: 1200,
|
|
387
|
-
colorDepth: 24,
|
|
388
|
-
pixelRatio: 0, // Invalid
|
|
389
|
-
touchSupport: true,
|
|
390
|
-
maxTouchPoints: 0, // Mismatch with touchSupport
|
|
391
|
-
hardwareConcurrency: 256, // Impossible
|
|
392
|
-
deviceMemory: 512, // Impossible
|
|
393
|
-
cookiesEnabled: true,
|
|
394
|
-
webDriver: false,
|
|
395
|
-
automationDetected: false,
|
|
396
|
-
canvasFingerprint: 'spoofed',
|
|
397
|
-
webglVendor: 'Spoofed Vendor',
|
|
398
|
-
webglRenderer: 'Spoofed Renderer',
|
|
399
|
-
pluginCount: 0,
|
|
400
|
-
collectedAt: Date.now(),
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
// =============================================================================
|
|
404
|
-
// COMPLETE VALIDATION INPUT FIXTURES
|
|
405
|
-
// =============================================================================
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Legitimate survey submission
|
|
409
|
-
*/
|
|
410
|
-
export const legitimateSubmission: ValidationInput = {
|
|
411
|
-
responses: legitimateResponses,
|
|
412
|
-
behavioralMetrics: normalBehavior,
|
|
413
|
-
deviceInfo: normalDevice,
|
|
414
|
-
context: {
|
|
415
|
-
surveyId: 'test-survey-1',
|
|
416
|
-
expectedMinTime: 60000, // 1 minute minimum
|
|
417
|
-
expectedMaxTime: 600000, // 10 minutes max
|
|
418
|
-
questionCount: 5,
|
|
419
|
-
},
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
* Spam/low-effort submission
|
|
424
|
-
*/
|
|
425
|
-
export const spamSubmission: ValidationInput = {
|
|
426
|
-
responses: spamResponses,
|
|
427
|
-
behavioralMetrics: botBehavior,
|
|
428
|
-
deviceInfo: normalDevice,
|
|
429
|
-
context: {
|
|
430
|
-
surveyId: 'test-survey-1',
|
|
431
|
-
expectedMinTime: 60000,
|
|
432
|
-
expectedMaxTime: 600000,
|
|
433
|
-
questionCount: 5,
|
|
434
|
-
},
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Bot submission
|
|
439
|
-
*/
|
|
440
|
-
export const botSubmission: ValidationInput = {
|
|
441
|
-
responses: botResponses,
|
|
442
|
-
behavioralMetrics: botBehavior,
|
|
443
|
-
deviceInfo: headlessDevice,
|
|
444
|
-
context: {
|
|
445
|
-
surveyId: 'test-survey-1',
|
|
446
|
-
expectedMinTime: 60000,
|
|
447
|
-
expectedMaxTime: 600000,
|
|
448
|
-
questionCount: 3,
|
|
449
|
-
},
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Straight-lining submission
|
|
454
|
-
*/
|
|
455
|
-
export const straightLiningSubmission: ValidationInput = {
|
|
456
|
-
responses: straightLiningResponses,
|
|
457
|
-
behavioralMetrics: normalBehavior,
|
|
458
|
-
deviceInfo: normalDevice,
|
|
459
|
-
context: {
|
|
460
|
-
surveyId: 'test-survey-2',
|
|
461
|
-
expectedMinTime: 30000,
|
|
462
|
-
expectedMaxTime: 300000,
|
|
463
|
-
questionCount: 6,
|
|
464
|
-
},
|
|
465
|
-
};
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* AI-assisted submission (paste-heavy)
|
|
469
|
-
*/
|
|
470
|
-
export const aiAssistedSubmission: ValidationInput = {
|
|
471
|
-
responses: legitimateResponses,
|
|
472
|
-
behavioralMetrics: pasteHeavyBehavior,
|
|
473
|
-
deviceInfo: normalDevice,
|
|
474
|
-
context: {
|
|
475
|
-
surveyId: 'test-survey-1',
|
|
476
|
-
expectedMinTime: 60000,
|
|
477
|
-
expectedMaxTime: 600000,
|
|
478
|
-
questionCount: 5,
|
|
479
|
-
},
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
// =============================================================================
|
|
483
|
-
// HELPER FUNCTIONS
|
|
484
|
-
// =============================================================================
|
|
485
|
-
|
|
486
|
-
function generateHumanMouseMovements(count: number): MouseMovement[] {
|
|
487
|
-
const movements: MouseMovement[] = [];
|
|
488
|
-
let x = 500;
|
|
489
|
-
let y = 400;
|
|
490
|
-
let t = 0;
|
|
491
|
-
|
|
492
|
-
for (let i = 0; i < count; i++) {
|
|
493
|
-
// Human-like random movement with varying velocities
|
|
494
|
-
const dx = (Math.random() - 0.5) * 100;
|
|
495
|
-
const dy = (Math.random() - 0.5) * 100;
|
|
496
|
-
const dt = 16 + Math.random() * 50; // 16-66ms between movements
|
|
497
|
-
|
|
498
|
-
x = Math.max(0, Math.min(1920, x + dx));
|
|
499
|
-
y = Math.max(0, Math.min(1080, y + dy));
|
|
500
|
-
t += dt;
|
|
501
|
-
|
|
502
|
-
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
503
|
-
const velocity = distance / dt;
|
|
504
|
-
|
|
505
|
-
movements.push({ x, y, t, velocity });
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
return movements;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
function generateRoboticMouseMovements(count: number): MouseMovement[] {
|
|
512
|
-
const movements: MouseMovement[] = [];
|
|
513
|
-
let x = 0;
|
|
514
|
-
let y = 0;
|
|
515
|
-
let t = 0;
|
|
516
|
-
|
|
517
|
-
for (let i = 0; i < count; i++) {
|
|
518
|
-
// Perfectly linear movement at constant speed
|
|
519
|
-
x += 100;
|
|
520
|
-
y += 50;
|
|
521
|
-
t += 10; // Uniform timing
|
|
522
|
-
|
|
523
|
-
movements.push({ x, y, t, velocity: 10 }); // Constant velocity
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
return movements;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
function generateHumanKeystrokes(count: number): KeystrokeEvent[] {
|
|
530
|
-
const keystrokes: KeystrokeEvent[] = [];
|
|
531
|
-
let t = 0;
|
|
532
|
-
|
|
533
|
-
for (let i = 0; i < count; i++) {
|
|
534
|
-
// Human typing has variable dwell and flight times
|
|
535
|
-
const dwell = 80 + Math.random() * 120; // 80-200ms key hold
|
|
536
|
-
const flightTime = 100 + Math.random() * 200; // 100-300ms between keys
|
|
537
|
-
const downAt = t;
|
|
538
|
-
const upAt = t + dwell;
|
|
539
|
-
|
|
540
|
-
keystrokes.push({
|
|
541
|
-
key: String.fromCharCode(97 + Math.floor(Math.random() * 26)),
|
|
542
|
-
downAt,
|
|
543
|
-
upAt,
|
|
544
|
-
dwell,
|
|
545
|
-
flightTime,
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
t = upAt + flightTime;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
return keystrokes;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
function generateHumanClicks(count: number): MouseClick[] {
|
|
555
|
-
const clicks: MouseClick[] = [];
|
|
556
|
-
let t = 0;
|
|
557
|
-
|
|
558
|
-
for (let i = 0; i < count; i++) {
|
|
559
|
-
clicks.push({
|
|
560
|
-
x: Math.random() * 1920,
|
|
561
|
-
y: Math.random() * 1080,
|
|
562
|
-
t,
|
|
563
|
-
hadHover: Math.random() > 0.2, // 80% have hover first
|
|
564
|
-
});
|
|
565
|
-
|
|
566
|
-
t += 2000 + Math.random() * 5000; // 2-7 seconds between clicks
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
return clicks;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
function generateRoboticClicks(count: number): MouseClick[] {
|
|
573
|
-
const clicks: MouseClick[] = [];
|
|
574
|
-
let t = 0;
|
|
575
|
-
|
|
576
|
-
for (let i = 0; i < count; i++) {
|
|
577
|
-
clicks.push({
|
|
578
|
-
x: 500 + i * 100,
|
|
579
|
-
y: 300,
|
|
580
|
-
t,
|
|
581
|
-
hadHover: false, // No hover before click
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
t += 500; // Uniform 500ms between clicks
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
return clicks;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
function generateHumanScrolls(count: number): ScrollEvent[] {
|
|
591
|
-
const scrolls: ScrollEvent[] = [];
|
|
592
|
-
let y = 0;
|
|
593
|
-
let t = 0;
|
|
594
|
-
|
|
595
|
-
for (let i = 0; i < count; i++) {
|
|
596
|
-
const deltaY = (Math.random() - 0.3) * 200;
|
|
597
|
-
y += deltaY;
|
|
598
|
-
scrolls.push({
|
|
599
|
-
y,
|
|
600
|
-
velocity: 2 + Math.random() * 8, // Variable velocity
|
|
601
|
-
t,
|
|
602
|
-
});
|
|
603
|
-
|
|
604
|
-
t += 500 + Math.random() * 2000;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
return scrolls;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
function generateRoboticScrolls(count: number): ScrollEvent[] {
|
|
611
|
-
const scrolls: ScrollEvent[] = [];
|
|
612
|
-
let y = 0;
|
|
613
|
-
let t = 0;
|
|
614
|
-
|
|
615
|
-
for (let i = 0; i < count; i++) {
|
|
616
|
-
y += 100;
|
|
617
|
-
scrolls.push({
|
|
618
|
-
y,
|
|
619
|
-
velocity: 5, // Constant velocity
|
|
620
|
-
t,
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
t += 1000; // Uniform timing
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
return scrolls;
|
|
627
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ES2022"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"declarationMap": true,
|
|
13
|
-
"outDir": "./dist",
|
|
14
|
-
"rootDir": "./src",
|
|
15
|
-
"resolveJsonModule": true,
|
|
16
|
-
"isolatedModules": true
|
|
17
|
-
},
|
|
18
|
-
"include": ["src/**/*"],
|
|
19
|
-
"exclude": ["node_modules", "dist"]
|
|
20
|
-
}
|