nextjs-secure 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bot.d.cts ADDED
@@ -0,0 +1,567 @@
1
+ import { NextRequest } from 'next/server';
2
+
3
+ /**
4
+ * Bot Detection Types
5
+ * @module nextjs-secure/bot
6
+ */
7
+
8
+ /**
9
+ * Bot classification categories
10
+ */
11
+ type BotCategory = 'search_engine' | 'social_media' | 'monitoring' | 'seo' | 'ai_crawler' | 'feed_reader' | 'preview' | 'security' | 'scraper' | 'spam' | 'malicious' | 'unknown';
12
+ /**
13
+ * Bot detection result
14
+ */
15
+ interface BotDetectionResult {
16
+ isBot: boolean;
17
+ category?: BotCategory;
18
+ name?: string;
19
+ confidence: number;
20
+ reason?: string;
21
+ userAgent?: string;
22
+ ip?: string;
23
+ }
24
+ /**
25
+ * Known bot pattern definition
26
+ */
27
+ interface BotPattern {
28
+ name: string;
29
+ pattern: RegExp;
30
+ category: BotCategory;
31
+ allowed: boolean;
32
+ description?: string;
33
+ }
34
+ /**
35
+ * User-Agent analysis options
36
+ */
37
+ interface UserAgentOptions {
38
+ /**
39
+ * Block all detected bots
40
+ * @default false
41
+ */
42
+ blockAllBots?: boolean;
43
+ /**
44
+ * Allow specific bot categories
45
+ * @default ['search_engine', 'social_media', 'monitoring']
46
+ */
47
+ allowCategories?: BotCategory[];
48
+ /**
49
+ * Allow specific bots by name
50
+ * @default ['Googlebot', 'Bingbot', 'Slurp']
51
+ */
52
+ allowList?: string[];
53
+ /**
54
+ * Block specific bots by name (overrides allowList)
55
+ */
56
+ blockList?: string[];
57
+ /**
58
+ * Custom bot patterns
59
+ */
60
+ customPatterns?: BotPattern[];
61
+ /**
62
+ * Block empty user agents
63
+ * @default true
64
+ */
65
+ blockEmptyUA?: boolean;
66
+ /**
67
+ * Block suspicious user agents (very short, random strings)
68
+ * @default true
69
+ */
70
+ blockSuspiciousUA?: boolean;
71
+ }
72
+ /**
73
+ * Honeypot field configuration
74
+ */
75
+ interface HoneypotOptions {
76
+ /**
77
+ * Field name for the honeypot (should look like a real field)
78
+ * @default '_hp_email'
79
+ */
80
+ fieldName?: string;
81
+ /**
82
+ * Additional honeypot field names
83
+ */
84
+ additionalFields?: string[];
85
+ /**
86
+ * Check for honeypot in these sources
87
+ * @default ['body', 'query']
88
+ */
89
+ checkIn?: ('body' | 'query' | 'headers')[];
90
+ /**
91
+ * Custom validation function
92
+ */
93
+ validate?: (value: unknown) => boolean;
94
+ }
95
+ /**
96
+ * Behavior analysis options
97
+ */
98
+ interface BehaviorOptions {
99
+ /**
100
+ * Minimum time between requests from same IP (ms)
101
+ * @default 100
102
+ */
103
+ minRequestInterval?: number;
104
+ /**
105
+ * Maximum requests per second from same IP
106
+ * @default 10
107
+ */
108
+ maxRequestsPerSecond?: number;
109
+ /**
110
+ * Time window for behavior analysis (ms)
111
+ * @default 60000 (1 minute)
112
+ */
113
+ windowMs?: number;
114
+ /**
115
+ * Store for tracking request patterns
116
+ */
117
+ store?: BehaviorStore;
118
+ /**
119
+ * Identifier function for grouping requests
120
+ * @default IP-based
121
+ */
122
+ identifier?: (req: NextRequest) => string | Promise<string>;
123
+ /**
124
+ * Suspicious patterns to detect
125
+ */
126
+ patterns?: {
127
+ /**
128
+ * Detect sequential URL access patterns
129
+ * @default true
130
+ */
131
+ sequentialAccess?: boolean;
132
+ /**
133
+ * Detect unusual request timing (too regular)
134
+ * @default true
135
+ */
136
+ regularTiming?: boolean;
137
+ /**
138
+ * Detect missing typical browser headers
139
+ * @default true
140
+ */
141
+ missingHeaders?: boolean;
142
+ };
143
+ }
144
+ /**
145
+ * Behavior tracking store interface
146
+ */
147
+ interface BehaviorStore {
148
+ /**
149
+ * Record a request
150
+ */
151
+ record(identifier: string, timestamp: number, path: string): Promise<void>;
152
+ /**
153
+ * Get request history for an identifier
154
+ */
155
+ getHistory(identifier: string, windowMs: number): Promise<RequestRecord[]>;
156
+ /**
157
+ * Clear old records
158
+ */
159
+ cleanup?(maxAge: number): Promise<void>;
160
+ }
161
+ /**
162
+ * Request record for behavior tracking
163
+ */
164
+ interface RequestRecord {
165
+ timestamp: number;
166
+ path: string;
167
+ }
168
+ /**
169
+ * Behavior analysis result
170
+ */
171
+ interface BehaviorAnalysisResult {
172
+ suspicious: boolean;
173
+ score: number;
174
+ reasons: string[];
175
+ requestCount: number;
176
+ avgInterval: number;
177
+ }
178
+ /**
179
+ * Supported CAPTCHA providers
180
+ */
181
+ type CaptchaProvider = 'recaptcha' | 'hcaptcha' | 'turnstile';
182
+ /**
183
+ * CAPTCHA verification options
184
+ */
185
+ interface CaptchaOptions {
186
+ /**
187
+ * CAPTCHA provider
188
+ */
189
+ provider: CaptchaProvider;
190
+ /**
191
+ * Site key (public)
192
+ */
193
+ siteKey: string;
194
+ /**
195
+ * Secret key (private)
196
+ */
197
+ secretKey: string;
198
+ /**
199
+ * Minimum score threshold (for reCAPTCHA v3)
200
+ * @default 0.5
201
+ */
202
+ threshold?: number;
203
+ /**
204
+ * Field name for the CAPTCHA token
205
+ * @default 'captchaToken' or provider-specific
206
+ */
207
+ tokenField?: string;
208
+ /**
209
+ * Action name (for reCAPTCHA v3)
210
+ */
211
+ action?: string;
212
+ /**
213
+ * Skip CAPTCHA for certain conditions
214
+ */
215
+ skip?: (req: NextRequest) => boolean | Promise<boolean>;
216
+ }
217
+ /**
218
+ * CAPTCHA verification result
219
+ */
220
+ interface CaptchaResult {
221
+ success: boolean;
222
+ score?: number;
223
+ action?: string;
224
+ hostname?: string;
225
+ errorCodes?: string[];
226
+ challengeTs?: string;
227
+ }
228
+ /**
229
+ * Challenge types
230
+ */
231
+ type ChallengeType = 'javascript' | 'cookie' | 'pow' | 'redirect';
232
+ /**
233
+ * Challenge options
234
+ */
235
+ interface ChallengeOptions {
236
+ /**
237
+ * Challenge type
238
+ * @default 'javascript'
239
+ */
240
+ type?: ChallengeType;
241
+ /**
242
+ * Challenge difficulty (for PoW)
243
+ * @default 4
244
+ */
245
+ difficulty?: number;
246
+ /**
247
+ * Challenge expiry time (ms)
248
+ * @default 300000 (5 minutes)
249
+ */
250
+ expiryMs?: number;
251
+ /**
252
+ * Cookie name for challenge token
253
+ * @default '__bot_challenge'
254
+ */
255
+ cookieName?: string;
256
+ /**
257
+ * Secret for signing challenge tokens
258
+ */
259
+ secret?: string;
260
+ }
261
+ /**
262
+ * Combined bot protection options
263
+ */
264
+ interface BotProtectionOptions {
265
+ /**
266
+ * User-Agent analysis options
267
+ */
268
+ userAgent?: UserAgentOptions | boolean;
269
+ /**
270
+ * Honeypot options
271
+ */
272
+ honeypot?: HoneypotOptions | boolean;
273
+ /**
274
+ * Behavior analysis options
275
+ */
276
+ behavior?: BehaviorOptions | boolean;
277
+ /**
278
+ * CAPTCHA options
279
+ */
280
+ captcha?: CaptchaOptions;
281
+ /**
282
+ * Challenge-response options
283
+ */
284
+ challenge?: ChallengeOptions | boolean;
285
+ /**
286
+ * Skip bot protection for certain conditions
287
+ */
288
+ skip?: (req: NextRequest) => boolean | Promise<boolean>;
289
+ /**
290
+ * Custom response when bot is detected
291
+ */
292
+ onBot?: (req: NextRequest, result: BotDetectionResult) => Response | Promise<Response>;
293
+ /**
294
+ * Log bot detections
295
+ * @default false
296
+ */
297
+ log?: boolean | ((result: BotDetectionResult) => void);
298
+ /**
299
+ * Mode: 'block' blocks bots, 'detect' only detects
300
+ * @default 'block'
301
+ */
302
+ mode?: 'block' | 'detect';
303
+ }
304
+ /**
305
+ * Extended context with bot detection info
306
+ */
307
+ interface BotContext {
308
+ bot?: BotDetectionResult;
309
+ }
310
+ /**
311
+ * Bot-protected handler type
312
+ */
313
+ type BotProtectedHandler<T = unknown> = (req: NextRequest, ctx: T & BotContext) => Response | Promise<Response>;
314
+
315
+ /**
316
+ * User-Agent Analysis for Bot Detection
317
+ * @module nextjs-secure/bot
318
+ */
319
+
320
+ /**
321
+ * Comprehensive list of known bot patterns
322
+ */
323
+ declare const KNOWN_BOT_PATTERNS: BotPattern[];
324
+ /**
325
+ * Default allowed bot categories
326
+ */
327
+ declare const DEFAULT_ALLOWED_CATEGORIES: BotCategory[];
328
+ /**
329
+ * Default allowed bot names
330
+ */
331
+ declare const DEFAULT_ALLOWED_BOTS: string[];
332
+ /**
333
+ * Analyze a User-Agent string for bot patterns
334
+ */
335
+ declare function analyzeUserAgent(userAgent: string | null, options?: UserAgentOptions): BotDetectionResult;
336
+ /**
337
+ * Check if User-Agent appears suspicious
338
+ */
339
+ declare function isSuspiciousUA(userAgent: string): boolean;
340
+ /**
341
+ * Check if a specific bot is allowed
342
+ */
343
+ declare function isBotAllowed(botName: string, options?: UserAgentOptions): boolean;
344
+ /**
345
+ * Get all known bot patterns for a category
346
+ */
347
+ declare function getBotsByCategory(category: BotCategory): BotPattern[];
348
+ /**
349
+ * Create a custom bot pattern
350
+ */
351
+ declare function createBotPattern(name: string, pattern: RegExp | string, category: BotCategory, allowed?: boolean, description?: string): BotPattern;
352
+
353
+ /**
354
+ * Honeypot Protection for Bot Detection
355
+ * @module nextjs-secure/bot
356
+ */
357
+
358
+ /**
359
+ * Default honeypot field names that look legitimate
360
+ */
361
+ declare const DEFAULT_HONEYPOT_FIELDS: string[];
362
+ /**
363
+ * Default honeypot options
364
+ */
365
+ declare const DEFAULT_HONEYPOT_OPTIONS: Required<Omit<HoneypotOptions, 'validate'>> & Pick<HoneypotOptions, 'validate'>;
366
+ /**
367
+ * Check for honeypot field values in request
368
+ */
369
+ declare function checkHoneypot(req: NextRequest, options?: HoneypotOptions): Promise<BotDetectionResult>;
370
+ /**
371
+ * Create honeypot middleware
372
+ */
373
+ declare function withHoneypot<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options?: HoneypotOptions): (req: NextRequest, ctx: T) => Promise<Response>;
374
+ /**
375
+ * Generate honeypot field HTML
376
+ * These fields should be hidden with CSS, not display:none
377
+ * Bots often ignore display:none but fill visible fields
378
+ */
379
+ declare function generateHoneypotHTML(options?: HoneypotOptions): string;
380
+ /**
381
+ * Generate CSS for honeypot fields
382
+ */
383
+ declare function generateHoneypotCSS(options?: HoneypotOptions): string;
384
+
385
+ /**
386
+ * Behavior Analysis for Bot Detection
387
+ * @module nextjs-secure/bot
388
+ */
389
+
390
+ /**
391
+ * Default behavior analysis options
392
+ */
393
+ declare const DEFAULT_BEHAVIOR_OPTIONS: Required<Omit<BehaviorOptions, 'store' | 'identifier'>> & Pick<BehaviorOptions, 'store' | 'identifier'>;
394
+ /**
395
+ * In-memory behavior tracking store with LRU eviction
396
+ */
397
+ declare class MemoryBehaviorStore implements BehaviorStore {
398
+ private records;
399
+ private maxIdentifiers;
400
+ private accessOrder;
401
+ constructor(options?: {
402
+ maxIdentifiers?: number;
403
+ });
404
+ record(identifier: string, timestamp: number, path: string): Promise<void>;
405
+ getHistory(identifier: string, windowMs: number): Promise<RequestRecord[]>;
406
+ cleanup(maxAge: number): Promise<void>;
407
+ /**
408
+ * Get store statistics
409
+ */
410
+ getStats(): {
411
+ identifiers: number;
412
+ totalRecords: number;
413
+ };
414
+ /**
415
+ * Clear all records
416
+ */
417
+ clear(): void;
418
+ }
419
+ /**
420
+ * Analyze request behavior for bot patterns
421
+ */
422
+ declare function analyzeBehavior(req: NextRequest, history: RequestRecord[], options?: BehaviorOptions): Promise<BehaviorAnalysisResult>;
423
+ /**
424
+ * Check behavior and return bot detection result
425
+ */
426
+ declare function checkBehavior(req: NextRequest, options?: BehaviorOptions): Promise<BotDetectionResult>;
427
+ /**
428
+ * Get or create global behavior store
429
+ */
430
+ declare function getGlobalBehaviorStore(): MemoryBehaviorStore;
431
+ /**
432
+ * Create behavior analysis middleware
433
+ */
434
+ declare function withBehaviorAnalysis<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options?: BehaviorOptions): (req: NextRequest, ctx: T) => Promise<Response>;
435
+
436
+ /**
437
+ * CAPTCHA Integration for Bot Detection
438
+ * @module nextjs-secure/bot
439
+ *
440
+ * Supports:
441
+ * - Google reCAPTCHA v2 & v3
442
+ * - hCaptcha
443
+ * - Cloudflare Turnstile
444
+ */
445
+
446
+ /**
447
+ * Verify CAPTCHA token with provider
448
+ */
449
+ declare function verifyCaptcha(token: string, options: CaptchaOptions): Promise<CaptchaResult>;
450
+ /**
451
+ * Extract CAPTCHA token from request
452
+ */
453
+ declare function extractCaptchaToken(req: NextRequest, options: CaptchaOptions): Promise<string | null>;
454
+ /**
455
+ * Check CAPTCHA and return bot detection result
456
+ */
457
+ declare function checkCaptcha(req: NextRequest, options: CaptchaOptions): Promise<BotDetectionResult>;
458
+ /**
459
+ * Create CAPTCHA verification middleware
460
+ */
461
+ declare function withCaptcha<T = unknown>(handler: (req: NextRequest, ctx: T) => Response | Promise<Response>, options: CaptchaOptions): (req: NextRequest, ctx: T) => Promise<Response>;
462
+ /**
463
+ * Generate reCAPTCHA v2 checkbox HTML
464
+ */
465
+ declare function generateRecaptchaV2(siteKey: string, options?: {
466
+ theme?: 'light' | 'dark';
467
+ size?: 'normal' | 'compact';
468
+ }): string;
469
+ /**
470
+ * Generate reCAPTCHA v3 HTML
471
+ */
472
+ declare function generateRecaptchaV3(siteKey: string, action?: string): string;
473
+ /**
474
+ * Generate hCaptcha HTML
475
+ */
476
+ declare function generateHCaptcha(siteKey: string, options?: {
477
+ theme?: 'light' | 'dark';
478
+ size?: 'normal' | 'compact';
479
+ }): string;
480
+ /**
481
+ * Generate Cloudflare Turnstile HTML
482
+ */
483
+ declare function generateTurnstile(siteKey: string, options?: {
484
+ theme?: 'light' | 'dark' | 'auto';
485
+ size?: 'normal' | 'compact';
486
+ }): string;
487
+
488
+ /**
489
+ * Bot Protection Middleware
490
+ * @module nextjs-secure/bot
491
+ *
492
+ * Combined bot detection middleware that integrates:
493
+ * - User-Agent analysis
494
+ * - Honeypot fields
495
+ * - Behavior analysis
496
+ * - CAPTCHA verification
497
+ */
498
+
499
+ /**
500
+ * Run all enabled bot detection checks
501
+ */
502
+ declare function detectBot(req: NextRequest, options?: BotProtectionOptions): Promise<BotDetectionResult>;
503
+ /**
504
+ * Create bot protection middleware
505
+ *
506
+ * @example
507
+ * ```typescript
508
+ * import { withBotProtection } from 'nextjs-secure/bot'
509
+ *
510
+ * export const POST = withBotProtection(handler, {
511
+ * userAgent: {
512
+ * blockAllBots: false,
513
+ * allowList: ['Googlebot', 'Bingbot'],
514
+ * },
515
+ * honeypot: {
516
+ * fieldName: '_hp_email',
517
+ * },
518
+ * behavior: {
519
+ * maxRequestsPerSecond: 10,
520
+ * },
521
+ * })
522
+ * ```
523
+ */
524
+ declare function withBotProtection<T = unknown>(handler: (req: NextRequest, ctx: T & BotContext) => Response | Promise<Response>, options?: BotProtectionOptions): (req: NextRequest, ctx: T) => Promise<Response>;
525
+ /**
526
+ * User-Agent only bot protection
527
+ */
528
+ declare function withUserAgentProtection<T = unknown>(handler: (req: NextRequest, ctx: T & BotContext) => Response | Promise<Response>, options?: UserAgentOptions): (req: NextRequest, ctx: T) => Promise<Response>;
529
+ /**
530
+ * Honeypot only protection
531
+ */
532
+ declare function withHoneypotProtection<T = unknown>(handler: (req: NextRequest, ctx: T & BotContext) => Response | Promise<Response>, options?: HoneypotOptions): (req: NextRequest, ctx: T) => Promise<Response>;
533
+ /**
534
+ * Behavior analysis only protection
535
+ */
536
+ declare function withBehaviorProtection<T = unknown>(handler: (req: NextRequest, ctx: T & BotContext) => Response | Promise<Response>, options?: BehaviorOptions): (req: NextRequest, ctx: T) => Promise<Response>;
537
+ /**
538
+ * CAPTCHA only protection
539
+ */
540
+ declare function withCaptchaProtection<T = unknown>(handler: (req: NextRequest, ctx: T & BotContext) => Response | Promise<Response>, options: CaptchaOptions): (req: NextRequest, ctx: T) => Promise<Response>;
541
+ /**
542
+ * Preset bot protection configurations
543
+ */
544
+ declare const BOT_PROTECTION_PRESETS: {
545
+ /**
546
+ * Relaxed - Only blocks obvious bots
547
+ */
548
+ readonly relaxed: BotProtectionOptions;
549
+ /**
550
+ * Standard - Good balance of protection
551
+ */
552
+ readonly standard: BotProtectionOptions;
553
+ /**
554
+ * Strict - Maximum protection
555
+ */
556
+ readonly strict: BotProtectionOptions;
557
+ /**
558
+ * API - For API endpoints
559
+ */
560
+ readonly api: BotProtectionOptions;
561
+ };
562
+ /**
563
+ * Create bot protection with preset
564
+ */
565
+ declare function withBotProtectionPreset<T = unknown>(handler: (req: NextRequest, ctx: T & BotContext) => Response | Promise<Response>, preset: keyof typeof BOT_PROTECTION_PRESETS, overrides?: BotProtectionOptions): (req: NextRequest, ctx: T) => Promise<Response>;
566
+
567
+ export { BOT_PROTECTION_PRESETS, type BehaviorAnalysisResult, type BehaviorOptions, type BehaviorStore, type BotCategory, type BotContext, type BotDetectionResult, type BotPattern, type BotProtectedHandler, type BotProtectionOptions, type CaptchaOptions, type CaptchaProvider, type CaptchaResult, type ChallengeOptions, type ChallengeType, DEFAULT_ALLOWED_BOTS, DEFAULT_ALLOWED_CATEGORIES, DEFAULT_BEHAVIOR_OPTIONS, DEFAULT_HONEYPOT_FIELDS, DEFAULT_HONEYPOT_OPTIONS, type HoneypotOptions, KNOWN_BOT_PATTERNS, MemoryBehaviorStore, type RequestRecord, type UserAgentOptions, analyzeBehavior, analyzeUserAgent, checkBehavior, checkCaptcha, checkHoneypot, createBotPattern, detectBot, extractCaptchaToken, generateHCaptcha, generateHoneypotCSS, generateHoneypotHTML, generateRecaptchaV2, generateRecaptchaV3, generateTurnstile, getBotsByCategory, getGlobalBehaviorStore, isBotAllowed, isSuspiciousUA, verifyCaptcha, withBehaviorAnalysis, withBehaviorProtection, withBotProtection, withBotProtectionPreset, withCaptcha, withCaptchaProtection, withHoneypot, withHoneypotProtection, withUserAgentProtection };