@bloomneo/appkit 1.2.9 โ†’ 1.5.2

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 (118) hide show
  1. package/AGENTS.md +195 -0
  2. package/CHANGELOG.md +253 -0
  3. package/README.md +147 -799
  4. package/bin/commands/generate.js +7 -7
  5. package/cookbook/README.md +26 -0
  6. package/cookbook/api-key-service.ts +106 -0
  7. package/cookbook/auth-protected-crud.ts +112 -0
  8. package/cookbook/file-upload-pipeline.ts +113 -0
  9. package/cookbook/multi-tenant-saas.ts +87 -0
  10. package/cookbook/real-time-chat.ts +121 -0
  11. package/dist/auth/auth.d.ts +21 -4
  12. package/dist/auth/auth.d.ts.map +1 -1
  13. package/dist/auth/auth.js +56 -44
  14. package/dist/auth/auth.js.map +1 -1
  15. package/dist/auth/defaults.d.ts +1 -1
  16. package/dist/auth/defaults.js +35 -35
  17. package/dist/cache/cache.d.ts +29 -6
  18. package/dist/cache/cache.d.ts.map +1 -1
  19. package/dist/cache/cache.js +72 -44
  20. package/dist/cache/cache.js.map +1 -1
  21. package/dist/cache/defaults.js +29 -29
  22. package/dist/cache/index.d.ts +19 -10
  23. package/dist/cache/index.d.ts.map +1 -1
  24. package/dist/cache/index.js +21 -18
  25. package/dist/cache/index.js.map +1 -1
  26. package/dist/config/defaults.d.ts +1 -1
  27. package/dist/config/defaults.js +11 -11
  28. package/dist/config/index.d.ts +3 -3
  29. package/dist/config/index.js +4 -4
  30. package/dist/database/adapters/mongoose.d.ts +4 -4
  31. package/dist/database/adapters/mongoose.js +7 -7
  32. package/dist/database/adapters/prisma.d.ts +4 -4
  33. package/dist/database/adapters/prisma.js +7 -7
  34. package/dist/database/defaults.d.ts +1 -1
  35. package/dist/database/defaults.js +4 -4
  36. package/dist/database/index.js +2 -2
  37. package/dist/database/index.js.map +1 -1
  38. package/dist/email/defaults.js +26 -26
  39. package/dist/email/index.js +7 -7
  40. package/dist/email/strategies/resend.js +1 -1
  41. package/dist/error/defaults.d.ts +1 -1
  42. package/dist/error/defaults.js +13 -13
  43. package/dist/error/error.d.ts +12 -0
  44. package/dist/error/error.d.ts.map +1 -1
  45. package/dist/error/error.js +19 -0
  46. package/dist/error/error.js.map +1 -1
  47. package/dist/error/index.d.ts +14 -3
  48. package/dist/error/index.d.ts.map +1 -1
  49. package/dist/error/index.js +14 -3
  50. package/dist/error/index.js.map +1 -1
  51. package/dist/event/defaults.js +35 -35
  52. package/dist/event/index.js +7 -7
  53. package/dist/logger/defaults.d.ts +1 -1
  54. package/dist/logger/defaults.js +40 -40
  55. package/dist/logger/index.d.ts +1 -0
  56. package/dist/logger/index.d.ts.map +1 -1
  57. package/dist/logger/index.js.map +1 -1
  58. package/dist/logger/logger.d.ts +8 -0
  59. package/dist/logger/logger.d.ts.map +1 -1
  60. package/dist/logger/logger.js +13 -3
  61. package/dist/logger/logger.js.map +1 -1
  62. package/dist/logger/transports/console.js +2 -2
  63. package/dist/logger/transports/http.d.ts +1 -1
  64. package/dist/logger/transports/http.js +2 -2
  65. package/dist/logger/transports/webhook.d.ts +1 -1
  66. package/dist/logger/transports/webhook.js +3 -3
  67. package/dist/queue/defaults.d.ts +2 -2
  68. package/dist/queue/defaults.js +38 -38
  69. package/dist/security/defaults.d.ts +1 -1
  70. package/dist/security/defaults.js +30 -30
  71. package/dist/security/index.d.ts +1 -1
  72. package/dist/security/index.js +3 -3
  73. package/dist/security/security.d.ts +1 -1
  74. package/dist/security/security.js +4 -4
  75. package/dist/storage/defaults.js +26 -26
  76. package/dist/storage/index.js +3 -3
  77. package/dist/util/defaults.d.ts +1 -1
  78. package/dist/util/defaults.js +41 -41
  79. package/dist/util/env.d.ts +35 -0
  80. package/dist/util/env.d.ts.map +1 -0
  81. package/dist/util/env.js +50 -0
  82. package/dist/util/env.js.map +1 -0
  83. package/dist/util/errors.d.ts +52 -0
  84. package/dist/util/errors.d.ts.map +1 -0
  85. package/dist/util/errors.js +82 -0
  86. package/dist/util/errors.js.map +1 -0
  87. package/dist/util/util.js +1 -1
  88. package/examples/.env.example +80 -0
  89. package/examples/README.md +16 -0
  90. package/examples/auth.ts +228 -0
  91. package/examples/cache.ts +36 -0
  92. package/examples/config.ts +45 -0
  93. package/examples/database.ts +69 -0
  94. package/examples/email.ts +53 -0
  95. package/examples/error.ts +50 -0
  96. package/examples/event.ts +42 -0
  97. package/examples/logger.ts +41 -0
  98. package/examples/queue.ts +58 -0
  99. package/examples/security.ts +46 -0
  100. package/examples/storage.ts +44 -0
  101. package/examples/util.ts +47 -0
  102. package/llms.txt +591 -0
  103. package/package.json +19 -10
  104. package/src/auth/README.md +850 -0
  105. package/src/cache/README.md +756 -0
  106. package/src/config/README.md +604 -0
  107. package/src/database/README.md +818 -0
  108. package/src/email/README.md +759 -0
  109. package/src/error/README.md +660 -0
  110. package/src/event/README.md +729 -0
  111. package/src/logger/README.md +435 -0
  112. package/src/queue/README.md +851 -0
  113. package/src/security/README.md +612 -0
  114. package/src/storage/README.md +1008 -0
  115. package/src/util/README.md +955 -0
  116. package/bin/templates/backend/docs/APPKIT_CLI.md +0 -507
  117. package/bin/templates/backend/docs/APPKIT_COMMENTS_GUIDELINES.md +0 -61
  118. package/bin/templates/backend/docs/APPKIT_LLM_GUIDE.md +0 -2539
@@ -0,0 +1,612 @@
1
+ # @bloomneo/appkit - Security Module ๐Ÿ”’
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@bloomneo/appkit.svg)](https://www.npmjs.com/package/@bloomneo/appkit)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ > Ultra-simple enterprise security that just works
7
+
8
+ **One function** returns a security object with enterprise-grade protection.
9
+ Zero configuration needed, production-ready by default, with built-in CSRF
10
+ protection, rate limiting, input sanitization, and AES-256-GCM encryption.
11
+
12
+ ## ๐Ÿš€ Why Choose This?
13
+
14
+ - **โšก One Function** - Just `securityClass.get()`, everything else is automatic
15
+ - **๐Ÿ”’ Enterprise Security** - Production-grade CSRF, rate limiting, encryption
16
+ - **๐Ÿ”ง Zero Configuration** - Smart defaults with environment variable override
17
+ - **๐ŸŒ Environment-First** - Auto-detects from `BLOOM_SECURITY_*` variables
18
+ - **๐Ÿ›ก๏ธ Complete Protection** - CSRF, XSS, rate limiting, data encryption
19
+ - **๐ŸŽฏ Framework Ready** - Express middleware with proper headers
20
+ - **๐Ÿค– AI-Ready** - Optimized for LLM code generation
21
+
22
+ ## ๐Ÿ“ฆ Installation
23
+
24
+ ```bash
25
+ npm install @bloomneo/appkit
26
+ ```
27
+
28
+ ## ๐Ÿƒโ€โ™‚๏ธ Quick Start (30 seconds)
29
+
30
+ ### 1. Environment Variables
31
+
32
+ ```bash
33
+ # Essential security configuration
34
+ BLOOM_SECURITY_CSRF_SECRET=your-csrf-secret-key-2024-minimum-32-chars
35
+ BLOOM_SECURITY_ENCRYPTION_KEY=64-char-hex-key-for-aes256-encryption
36
+ ```
37
+
38
+ ### 2. Basic Setup
39
+
40
+ ```typescript
41
+ import express from 'express';
42
+ import session from 'express-session';
43
+ import { securityClass } from '@bloomneo/appkit/security';
44
+
45
+ const app = express();
46
+ const security = securityClass.get();
47
+
48
+ // Session middleware (required for CSRF)
49
+ app.use(session({ secret: process.env.SESSION_SECRET }));
50
+
51
+ // Security middleware
52
+ app.use(secure.forms()); // CSRF protection
53
+ app.use('/api', secure.requests()); // Rate limiting
54
+
55
+ // Secure route
56
+ app.post('/profile', (req, res) => {
57
+ const safeName = secure.input(req.body.name);
58
+ const safeBio = secure.html(req.body.bio, { allowedTags: ['p', 'b'] });
59
+ const encryptedSSN = secure.encrypt(req.body.ssn);
60
+
61
+ // Save to database...
62
+ res.json({ success: true });
63
+ });
64
+ ```
65
+
66
+ ## ๐Ÿง  Mental Model
67
+
68
+ ### Security Layer Architecture
69
+
70
+ ```
71
+ Request โ†’ CSRF Check โ†’ Rate Limit โ†’ Input Sanitization โ†’ Business Logic
72
+ ```
73
+
74
+ ### Protection Types
75
+
76
+ ```typescript
77
+ // Form Protection (CSRF)
78
+ secure.forms(); // Prevents cross-site request forgery
79
+
80
+ // Traffic Protection (Rate Limiting)
81
+ secure.requests(); // Prevents abuse and brute force
82
+
83
+ // Input Protection (XSS Prevention)
84
+ secure.input(text); // Cleans user text input
85
+ secure.html(content); // Sanitizes HTML content
86
+
87
+ // Data Protection (Encryption)
88
+ secure.encrypt(data); // AES-256-GCM encryption
89
+ secure.decrypt(data); // Authenticated decryption
90
+ ```
91
+
92
+ ## ๐Ÿค– LLM Quick Reference - Copy These Patterns
93
+
94
+ ### **Basic Security Setup (Copy Exactly)**
95
+
96
+ ```typescript
97
+ // โœ… CORRECT - Complete security setup
98
+ import { securityClass } from '@bloomneo/appkit/security';
99
+ const security = securityClass.get();
100
+
101
+ // Required order
102
+ app.use(session({ secret: process.env.SESSION_SECRET }));
103
+ app.use(secure.forms()); // CSRF protection
104
+ app.use('/api', secure.requests()); // Rate limiting
105
+
106
+ // Form with CSRF token
107
+ app.get('/form', (req, res) => {
108
+ const csrfToken = req.csrfToken();
109
+ res.render('form', { csrfToken });
110
+ });
111
+
112
+ // Secure input processing
113
+ app.post('/form', (req, res) => {
114
+ const clean = secure.input(req.body.data);
115
+ const safeHtml = secure.html(req.body.content, { allowedTags: ['p'] });
116
+ const encrypted = secure.encrypt(req.body.sensitive);
117
+ // Process...
118
+ });
119
+ ```
120
+
121
+ ### **Different Rate Limits (Copy These)**
122
+
123
+ ```typescript
124
+ // โœ… CORRECT - Endpoint-specific limits
125
+ app.use('/api', secure.requests(100, 900000)); // 100/15min
126
+ app.use('/auth', secure.requests(5, 3600000)); // 5/hour
127
+ app.post('/upload', secure.requests(10), handler); // 10/15min
128
+ ```
129
+
130
+ ### **Input Sanitization (Copy These)**
131
+
132
+ ```typescript
133
+ // โœ… CORRECT - Clean all user input
134
+ const safeName = secure.input(req.body.name, { maxLength: 50 });
135
+ const safeEmail = secure.input(req.body.email?.toLowerCase());
136
+ const safeContent = secure.html(req.body.content, {
137
+ allowedTags: ['p', 'b', 'i', 'a'],
138
+ });
139
+ const safeDisplay = secure.escape(userText);
140
+ ```
141
+
142
+ ### **Encryption Patterns (Copy These)**
143
+
144
+ ```typescript
145
+ // โœ… CORRECT - Encrypt sensitive data
146
+ const encryptedSSN = secure.encrypt(user.ssn);
147
+ const encryptedPhone = secure.encrypt(user.phone);
148
+
149
+ // โœ… CORRECT - Decrypt for authorized access
150
+ const originalSSN = secure.decrypt(encryptedSSN);
151
+ const originalPhone = secure.decrypt(encryptedPhone);
152
+
153
+ // โœ… CORRECT - Generate keys
154
+ const newKey = secure.generateKey(); // For production use
155
+ ```
156
+
157
+ ## โš ๏ธ Common LLM Mistakes - Avoid These
158
+
159
+ ### **Wrong Middleware Order**
160
+
161
+ ```typescript
162
+ // โŒ WRONG - CSRF without sessions
163
+ app.use(secure.forms());
164
+ app.use(session(config)); // Too late!
165
+
166
+ // โœ… CORRECT - Sessions first
167
+ app.use(session(config));
168
+ app.use(secure.forms());
169
+ ```
170
+
171
+ ### **Raw Input Storage**
172
+
173
+ ```typescript
174
+ // โŒ WRONG - Store raw user input
175
+ await db.save({ content: req.body.content });
176
+
177
+ // โœ… CORRECT - Clean first
178
+ const clean = secure.input(req.body.content);
179
+ await db.save({ content: clean });
180
+ ```
181
+
182
+ ### **Missing CSRF Tokens**
183
+
184
+ ```typescript
185
+ // โŒ WRONG - Form without CSRF
186
+ res.send('<form method="POST">...');
187
+
188
+ // โœ… CORRECT - Include CSRF token
189
+ const csrfToken = req.csrfToken();
190
+ res.send(
191
+ `<form method="POST"><input type="hidden" name="_csrf" value="${csrfToken}">...`
192
+ );
193
+ ```
194
+
195
+ ### **Unsafe Output Display**
196
+
197
+ ```typescript
198
+ // โŒ WRONG - Direct user content
199
+ res.send(`<p>User: ${userComment}</p>`);
200
+
201
+ // โœ… CORRECT - Escape output
202
+ const safe = secure.escape(userComment);
203
+ res.send(`<p>User: ${safe}</p>`);
204
+ ```
205
+
206
+ ## ๐Ÿšจ Error Handling Patterns
207
+
208
+ ### **Startup Validation**
209
+
210
+ ```typescript
211
+ // โœ… App startup validation
212
+ try {
213
+ securityClass.validateRequired({ csrf: true, encryption: true });
214
+ console.log('โœ… Security validation passed');
215
+ } catch (error) {
216
+ console.error('โŒ Security failed:', error.message);
217
+ process.exit(1);
218
+ }
219
+ ```
220
+
221
+ ### **Runtime Error Handling**
222
+
223
+ ```typescript
224
+ // โœ… Safe configuration access
225
+ function getDatabaseConfig() {
226
+ try {
227
+ return {
228
+ host: config.getRequired('database.host'),
229
+ ssl: config.get('database.ssl', false),
230
+ };
231
+ } catch (error) {
232
+ throw new Error(`Database config error: ${error.message}`);
233
+ }
234
+ }
235
+ ```
236
+
237
+ ## ๐ŸŽฏ Usage Examples
238
+
239
+ ### **User Registration**
240
+
241
+ ```typescript
242
+ app.post('/auth/register', secure.requests(10, 3600000), async (req, res) => {
243
+ // Clean input
244
+ const email = secure.input(req.body.email?.toLowerCase());
245
+ const name = secure.input(req.body.name, { maxLength: 50 });
246
+
247
+ // Validate
248
+ if (!email || !name || !req.body.password) {
249
+ return res.status(400).json({ error: 'Missing required fields' });
250
+ }
251
+
252
+ // Hash password
253
+ const hashedPassword = await bcrypt.hash(req.body.password, 12);
254
+
255
+ // Encrypt sensitive data
256
+ const encryptedPhone = req.body.phone ? secure.encrypt(req.body.phone) : null;
257
+
258
+ // Save user
259
+ const user = await createUser({
260
+ email,
261
+ name,
262
+ password: hashedPassword,
263
+ phone: encryptedPhone,
264
+ });
265
+ res.status(201).json({ user: { id: user.id, email, name } });
266
+ });
267
+ ```
268
+
269
+ ### **Blog Post Creation**
270
+
271
+ ```typescript
272
+ app.post('/api/posts', async (req, res) => {
273
+ // Sanitize content
274
+ const title = secure.input(req.body.title, { maxLength: 200 });
275
+ const content = secure.html(req.body.content, {
276
+ allowedTags: ['p', 'h1', 'h2', 'b', 'i', 'a', 'ul', 'ol', 'li'],
277
+ });
278
+
279
+ // Validate
280
+ if (!title || !content) {
281
+ return res.status(400).json({ error: 'Title and content required' });
282
+ }
283
+
284
+ // Create post
285
+ const post = await createBlogPost({ title, content, authorId: req.user.id });
286
+ res.status(201).json({ post });
287
+ });
288
+ ```
289
+
290
+ ### **Comment System**
291
+
292
+ ```typescript
293
+ app.post(
294
+ '/api/posts/:id/comments',
295
+ secure.requests(5, 300000),
296
+ async (req, res) => {
297
+ const postId = secure.input(req.params.id);
298
+ const content = secure.html(req.body.content, {
299
+ allowedTags: ['p', 'b', 'i'],
300
+ });
301
+
302
+ if (!content || content.length < 10) {
303
+ return res.status(400).json({ error: 'Comment too short' });
304
+ }
305
+
306
+ const comment = await createComment({
307
+ postId: parseInt(postId),
308
+ content,
309
+ authorId: req.user.id,
310
+ });
311
+ res.status(201).json({ comment });
312
+ }
313
+ );
314
+ ```
315
+
316
+ ### **Data Encryption Service**
317
+
318
+ ```typescript
319
+ class UserDataService {
320
+ static async createProfile(userData) {
321
+ // Encrypt PII
322
+ const encryptedSSN = userData.ssn ? secure.encrypt(userData.ssn) : null;
323
+ const encryptedPhone = userData.phone
324
+ ? secure.encrypt(userData.phone)
325
+ : null;
326
+
327
+ // Clean public data
328
+ const name = secure.input(userData.name, { maxLength: 100 });
329
+ const bio = secure.html(userData.bio, { allowedTags: ['p', 'b', 'i'] });
330
+
331
+ return await db.users.create({
332
+ name,
333
+ bio,
334
+ email: userData.email,
335
+ ssn: encryptedSSN,
336
+ phone: encryptedPhone,
337
+ });
338
+ }
339
+
340
+ static async getProfile(userId, requestingUserId) {
341
+ const user = await db.users.findById(userId);
342
+ if (!user) throw new Error('User not found');
343
+
344
+ const profile = {
345
+ id: user.id,
346
+ name: user.name,
347
+ bio: user.bio,
348
+ email: user.email,
349
+ };
350
+
351
+ // Decrypt for authorized users
352
+ if (userId === requestingUserId || (await isAdmin(requestingUserId))) {
353
+ if (user.ssn) profile.ssn = secure.decrypt(user.ssn);
354
+ if (user.phone) profile.phone = secure.decrypt(user.phone);
355
+ }
356
+
357
+ return profile;
358
+ }
359
+ }
360
+ ```
361
+
362
+ ## ๐Ÿ“– Complete API Reference
363
+
364
+ ### **Core Function**
365
+
366
+ ```typescript
367
+ const security = securityClass.get(); // One function, everything you need
368
+ ```
369
+
370
+ ### **Middleware Methods**
371
+
372
+ ```typescript
373
+ secure.forms(options?); // CSRF protection
374
+ secure.requests(max?, window?); // Rate limiting
375
+ securityClass.quickSetup(options?); // Quick middleware array
376
+ ```
377
+
378
+ ### **Input Sanitization**
379
+
380
+ ```typescript
381
+ secure.input(text, options?); // XSS prevention
382
+ secure.html(html, options?); // HTML sanitization
383
+ secure.escape(text); // HTML entity escaping
384
+ ```
385
+
386
+ ### **Data Encryption**
387
+
388
+ ```typescript
389
+ secure.encrypt(data, key?); // AES-256-GCM encryption
390
+ secure.decrypt(data, key?); // Authenticated decryption
391
+ secure.generateKey(); // 256-bit key generation
392
+ ```
393
+
394
+ ### **Utility Methods**
395
+
396
+ ```typescript
397
+ securityClass.getConfig(); // Current configuration
398
+ securityClass.getStatus(); // Security feature status
399
+ securityClass.validateRequired(checks); // Startup validation
400
+ securityClass.isDevelopment(); // Environment helpers
401
+ securityClass.isProduction();
402
+ ```
403
+
404
+ ## ๐ŸŒ Environment Variables
405
+
406
+ ### **Required Configuration**
407
+
408
+ ```bash
409
+ # CSRF Protection
410
+ BLOOM_SECURITY_CSRF_SECRET=your-csrf-secret-key-2024-minimum-32-chars
411
+
412
+ # Data Encryption
413
+ BLOOM_SECURITY_ENCRYPTION_KEY=64-char-hex-key-for-aes256-encryption
414
+
415
+ # Generate encryption key:
416
+ # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
417
+ ```
418
+
419
+ ### **Optional Configuration**
420
+
421
+ ```bash
422
+ # Rate Limiting
423
+ BLOOM_SECURITY_RATE_LIMIT=100 # Requests per window
424
+ BLOOM_SECURITY_RATE_WINDOW=900000 # Window in ms (15 min)
425
+
426
+ # Input Sanitization
427
+ BLOOM_SECURITY_MAX_INPUT_LENGTH=1000 # Max input length
428
+ BLOOM_SECURITY_ALLOWED_TAGS=p,b,i,a # Allowed HTML tags
429
+
430
+ # CSRF Settings
431
+ BLOOM_SECURITY_CSRF_EXPIRY=60 # Token expiry minutes
432
+ ```
433
+
434
+ ## ๐Ÿ”’ Security Features
435
+
436
+ ### **CSRF Protection** (`secure.forms()`)
437
+
438
+ - Generates cryptographically secure tokens using `crypto.randomBytes()`
439
+ - Stores tokens in sessions with expiration timestamps
440
+ - Validates using timing-safe comparison with `crypto.timingSafeEqual()`
441
+ - Automatically checks POST/PUT/DELETE/PATCH requests
442
+
443
+ ### **Rate Limiting** (`secure.requests()`)
444
+
445
+ - In-memory tracking with automatic cleanup
446
+ - Sliding window algorithm for accurate limiting
447
+ - Standard HTTP headers (X-RateLimit-\*, Retry-After)
448
+ - Configurable per endpoint
449
+
450
+ ### **Input Sanitization** (`secure.input()`, `secure.html()`)
451
+
452
+ - Removes dangerous patterns: `<script>`, `javascript:`, `on*=` handlers
453
+ - Whitelist-based HTML tag filtering
454
+ - Length limiting to prevent memory exhaustion
455
+ - HTML entity escaping for safe display
456
+
457
+ ### **Data Encryption** (`secure.encrypt()`, `secure.decrypt()`)
458
+
459
+ - AES-256-GCM authenticated encryption
460
+ - Random IV per encryption operation
461
+ - Authentication tags to detect tampering
462
+ - Optional Associated Additional Data (AAD)
463
+
464
+ ## ๐Ÿ›ก๏ธ Production Deployment
465
+
466
+ ### **Environment Setup**
467
+
468
+ ```bash
469
+ # โœ… Required in production
470
+ BLOOM_SECURITY_CSRF_SECRET=64-char-random-string
471
+ BLOOM_SECURITY_ENCRYPTION_KEY=64-char-hex-string
472
+
473
+ # โœ… Optional but recommended
474
+ BLOOM_SECURITY_RATE_LIMIT=100
475
+ BLOOM_SECURITY_RATE_WINDOW=900000
476
+ ```
477
+
478
+ ### **Security Middleware Order**
479
+
480
+ ```typescript
481
+ // โœ… Correct order for maximum protection
482
+ app.use(express.json({ limit: '10mb' }));
483
+ app.use(session(config)); // 1. Sessions first
484
+ app.use(secure.forms()); // 2. CSRF protection
485
+ app.use('/api', secure.requests()); // 3. Rate limiting
486
+ app.use('/auth', secure.requests(5, 3600000)); // 4. Strict auth limits
487
+ app.use('/api', apiRoutes); // 5. Application routes
488
+ ```
489
+
490
+ ### **Input Validation Pattern**
491
+
492
+ ```typescript
493
+ // โœ… Comprehensive input validation middleware
494
+ function validateInput(req, res, next) {
495
+ if (req.body.name)
496
+ req.body.name = secure.input(req.body.name, { maxLength: 50 });
497
+ if (req.body.email)
498
+ req.body.email = secure.input(req.body.email?.toLowerCase());
499
+ if (req.body.content)
500
+ req.body.content = secure.html(req.body.content, {
501
+ allowedTags: ['p', 'b', 'i'],
502
+ });
503
+
504
+ if (!req.body.name || !req.body.email) {
505
+ return res.status(400).json({ error: 'Name and email required' });
506
+ }
507
+ next();
508
+ }
509
+ ```
510
+
511
+ ### **Key Management**
512
+
513
+ ```typescript
514
+ // โœ… Generate production keys
515
+ const encryptionKey = securityClass.generateKey();
516
+ console.log(`BLOOM_SECURITY_ENCRYPTION_KEY=${encryptionKey}`);
517
+
518
+ // โœ… Validate configuration at startup
519
+ securityClass.validateRequired({ csrf: true, encryption: true });
520
+ ```
521
+
522
+ ## ๐Ÿงช Testing
523
+
524
+ ```typescript
525
+ import { securityClass } from '@bloomneo/appkit/security';
526
+
527
+ describe('Security Tests', () => {
528
+ beforeEach(() => securityClass.clearCache());
529
+
530
+ test('should generate and verify CSRF tokens', () => {
531
+ const secure = securityClass.reset({
532
+ csrf: { secret: 'test-secret-32-characters-long' },
533
+ });
534
+
535
+ const mockReq = { session: {} };
536
+ const middleware = secure.forms();
537
+ middleware(mockReq, {}, () => {});
538
+
539
+ const token = mockReq.csrfToken();
540
+ expect(token).toBeDefined();
541
+ expect(typeof token).toBe('string');
542
+ });
543
+
544
+ test('should encrypt and decrypt correctly', () => {
545
+ const secure = securityClass.reset({
546
+ encryption: { key: 'a'.repeat(64) },
547
+ });
548
+
549
+ const data = 'sensitive information';
550
+ const encrypted = secure.encrypt(data);
551
+ const decrypted = secure.decrypt(encrypted);
552
+
553
+ expect(decrypted).toBe(data);
554
+ expect(encrypted).toMatch(/^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$/);
555
+ });
556
+
557
+ test('should sanitize malicious input', () => {
558
+ const security = securityClass.get();
559
+ const malicious = '<script>alert("xss")</script><p>Safe</p>';
560
+ const cleaned = secure.html(malicious, { allowedTags: ['p'] });
561
+
562
+ expect(cleaned).toBe('<p>Safe</p>');
563
+ expect(cleaned).not.toContain('<script>');
564
+ });
565
+ });
566
+ ```
567
+
568
+ ### **Mock Configuration**
569
+
570
+ ```typescript
571
+ function createTestSecurity(overrides = {}) {
572
+ return securityClass.reset({
573
+ csrf: { secret: 'test-secret-32-characters-long' },
574
+ encryption: { key: 'a'.repeat(64) },
575
+ environment: { isDevelopment: true, isTest: true },
576
+ ...overrides,
577
+ });
578
+ }
579
+ ```
580
+
581
+ ## ๐Ÿ“ˆ Performance
582
+
583
+ - **CSRF Operations**: ~1ms per token generation/verification
584
+ - **Rate Limiting**: In-memory with O(1) lookup, automatic cleanup
585
+ - **Input Sanitization**: ~0.1ms per operation
586
+ - **Encryption**: ~2ms per encrypt/decrypt (AES-256-GCM)
587
+ - **Memory Usage**: <2MB additional overhead
588
+
589
+ ## ๐Ÿ” TypeScript Support
590
+
591
+ ```typescript
592
+ import type {
593
+ SecurityConfig,
594
+ ExpressMiddleware,
595
+ CSRFOptions,
596
+ RateLimitOptions,
597
+ } from '@bloomneo/appkit/security';
598
+
599
+ const security = securityClass.get();
600
+ const middleware: ExpressMiddleware = secure.forms();
601
+ const encrypted: string = secure.encrypt(sensitiveData);
602
+ ```
603
+
604
+ ## ๐Ÿ“„ License
605
+
606
+ MIT ยฉ [Bloomneo](https://github.com/bloomneo)
607
+
608
+ ---
609
+
610
+ <p align="center">
611
+ Built with โค๏ธ in India by the <a href="https://github.com/orgs/bloomneo/people">Bloomneo Team</a>
612
+ </p>