yinzerflow 0.4.4 → 0.5.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 +31 -26
- package/docs/configuration/configuration.md +815 -0
- package/docs/core/core-concepts.md +801 -0
- package/docs/core/error-handling.md +391 -153
- package/docs/core/logging.md +426 -68
- package/docs/modules/body-parsing.md +561 -0
- package/docs/modules/cors.md +369 -0
- package/docs/modules/index.md +125 -0
- package/docs/modules/ip-security.md +280 -0
- package/docs/modules/rate-limiting.md +795 -0
- package/index.d.ts +278 -76
- package/index.js +18 -18
- package/index.js.map +17 -8
- package/package.json +5 -3
- package/docs/configuration/advanced-configuration-options.md +0 -302
- package/docs/configuration/configuration-patterns.md +0 -500
- package/docs/core/context.md +0 -230
- package/docs/core/examples.md +0 -444
- package/docs/core/request.md +0 -161
- package/docs/core/response.md +0 -212
- package/docs/core/routes.md +0 -720
- package/docs/quick-reference.md +0 -346
- package/docs/security/body-parsing.md +0 -296
- package/docs/security/cors.md +0 -189
- package/docs/security/ip-security.md +0 -234
- package/docs/security/security-overview.md +0 -282
- package/docs/start-here.md +0 -184
package/docs/quick-reference.md
DELETED
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
# Quick Reference
|
|
2
|
-
|
|
3
|
-
This quick reference contains the most common patterns and examples for YinzerFlow. For detailed documentation, see the full documentation sections.
|
|
4
|
-
|
|
5
|
-
## Installation & Setup
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Install
|
|
9
|
-
npm install yinzerflow
|
|
10
|
-
|
|
11
|
-
# Basic setup
|
|
12
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
13
|
-
const app = new YinzerFlow({ port: 3000 });
|
|
14
|
-
await app.listen();
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Basic Routes
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
// GET route
|
|
21
|
-
app.get('/api/users', (ctx) => {
|
|
22
|
-
return { users: ['John', 'Jane'] };
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// POST route with body
|
|
26
|
-
app.post('/api/users', (ctx) => {
|
|
27
|
-
const userData = ctx.request.body;
|
|
28
|
-
return { message: 'User created', data: userData };
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Route with parameters
|
|
32
|
-
app.get('/api/users/:id', (ctx) => {
|
|
33
|
-
const userId = ctx.request.params.id;
|
|
34
|
-
return { userId, name: 'John Doe' };
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Route with query parameters
|
|
38
|
-
app.get('/api/search', (ctx) => {
|
|
39
|
-
const { q, limit } = ctx.request.query;
|
|
40
|
-
return { search: q, limit: parseInt(limit || '10') };
|
|
41
|
-
});
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## HTTP Methods
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
app.get('/api/users', handler); // GET
|
|
48
|
-
app.post('/api/users', handler); // POST
|
|
49
|
-
app.put('/api/users/:id', handler); // PUT
|
|
50
|
-
app.patch('/api/users/:id', handler); // PATCH
|
|
51
|
-
app.delete('/api/users/:id', handler); // DELETE
|
|
52
|
-
app.options('/api/users', handler); // OPTIONS
|
|
53
|
-
app.head('/api/users', handler); // HEAD (or auto-registered with GET)
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Route Groups
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
app.group('/api/v1', (group) => {
|
|
60
|
-
group.get('/users', handler);
|
|
61
|
-
group.post('/users', handler);
|
|
62
|
-
group.get('/users/:id', handler);
|
|
63
|
-
}, {
|
|
64
|
-
beforeHooks: [authHook]
|
|
65
|
-
});
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Hooks
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
// Route-specific hooks
|
|
72
|
-
app.post('/api/users', handler, {
|
|
73
|
-
beforeHooks: [authHook, logHook],
|
|
74
|
-
afterHooks: [responseHook]
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Global hooks
|
|
78
|
-
app.beforeAll([globalAuthHook]);
|
|
79
|
-
app.afterAll([globalLogHook]);
|
|
80
|
-
app.onError(errorHandler);
|
|
81
|
-
app.onNotFound(notFoundHandler);
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Request Data
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
app.post('/api/users', ({ request }) => {
|
|
88
|
-
// Body data
|
|
89
|
-
const userData = request.body;
|
|
90
|
-
|
|
91
|
-
// URL parameters
|
|
92
|
-
const userId = request.params.id;
|
|
93
|
-
|
|
94
|
-
// Query parameters
|
|
95
|
-
const { page, limit } = request.query;
|
|
96
|
-
|
|
97
|
-
// Headers
|
|
98
|
-
const token = request.headers['authorization'];
|
|
99
|
-
|
|
100
|
-
// Client IP
|
|
101
|
-
const clientIp = request.ipAddress;
|
|
102
|
-
|
|
103
|
-
// Request info
|
|
104
|
-
const { method, path, url } = request;
|
|
105
|
-
});
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Response Control
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
app.post('/api/users', ({ response }) => {
|
|
112
|
-
// Set status code
|
|
113
|
-
response.setStatusCode(201);
|
|
114
|
-
|
|
115
|
-
// Add headers
|
|
116
|
-
response.addHeaders({
|
|
117
|
-
'X-User-ID': '123',
|
|
118
|
-
'Content-Type': 'application/json'
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// Return data
|
|
122
|
-
return { message: 'User created' };
|
|
123
|
-
});
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Error Handling
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
// Global error handler
|
|
130
|
-
app.onError(({ response }, error) => {
|
|
131
|
-
response.setStatusCode(500);
|
|
132
|
-
return { error: 'Internal server error' };
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Route error handling
|
|
136
|
-
app.get('/api/users/:id', ({ request }) => {
|
|
137
|
-
const userId = request.params.id;
|
|
138
|
-
if (!userId) {
|
|
139
|
-
throw new Error('User ID required');
|
|
140
|
-
}
|
|
141
|
-
return { userId };
|
|
142
|
-
});
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Common Configurations
|
|
146
|
-
|
|
147
|
-
### Basic API
|
|
148
|
-
```typescript
|
|
149
|
-
const app = new YinzerFlow({
|
|
150
|
-
port: 3000,
|
|
151
|
-
cors: {
|
|
152
|
-
enabled: true,
|
|
153
|
-
origin: ['https://yourdomain.com']
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Production API
|
|
159
|
-
```typescript
|
|
160
|
-
const app = new YinzerFlow({
|
|
161
|
-
port: 443,
|
|
162
|
-
cors: {
|
|
163
|
-
enabled: true,
|
|
164
|
-
origin: ['https://yourdomain.com'],
|
|
165
|
-
credentials: true
|
|
166
|
-
},
|
|
167
|
-
bodyParser: {
|
|
168
|
-
json: {
|
|
169
|
-
maxSize: 262144, // 256KB
|
|
170
|
-
allowPrototypeProperties: false
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
ipSecurity: {
|
|
174
|
-
trustedProxies: ['127.0.0.1'],
|
|
175
|
-
detectSpoofing: true
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### File Upload Service
|
|
181
|
-
```typescript
|
|
182
|
-
const app = new YinzerFlow({
|
|
183
|
-
port: 3000,
|
|
184
|
-
bodyParser: {
|
|
185
|
-
fileUploads: {
|
|
186
|
-
maxFileSize: 10485760, // 10MB
|
|
187
|
-
maxFiles: 10,
|
|
188
|
-
allowedExtensions: ['.jpg', '.png', '.pdf']
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## TypeScript Support
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
interface UserBody {
|
|
198
|
-
name: string;
|
|
199
|
-
email: string;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
interface UserResponse {
|
|
203
|
-
id: string;
|
|
204
|
-
name: string;
|
|
205
|
-
email: string;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const createUser: HandlerCallback<{
|
|
209
|
-
body: UserBody;
|
|
210
|
-
response: UserResponse;
|
|
211
|
-
}> = ({ request }) => {
|
|
212
|
-
const userData = request.body; // Typed as UserBody
|
|
213
|
-
return {
|
|
214
|
-
id: 'user-123',
|
|
215
|
-
name: userData.name,
|
|
216
|
-
email: userData.email
|
|
217
|
-
}; // Typed as UserResponse
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
app.post('/api/users', createUser);
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
## Common Patterns
|
|
224
|
-
|
|
225
|
-
### Authentication Hook
|
|
226
|
-
```typescript
|
|
227
|
-
const authHook = ({ request, response }) => {
|
|
228
|
-
const token = request.headers['authorization'];
|
|
229
|
-
if (!token) {
|
|
230
|
-
response.setStatusCode(401);
|
|
231
|
-
return { error: 'Unauthorized' };
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Logging Hook
|
|
237
|
-
```typescript
|
|
238
|
-
const logHook = ({ request }) => {
|
|
239
|
-
console.log(`${request.method} ${request.path} - ${request.ipAddress}`);
|
|
240
|
-
};
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### Rate Limiting Hook
|
|
244
|
-
```typescript
|
|
245
|
-
const rateLimitHook = ({ request, response }) => {
|
|
246
|
-
const clientIp = request.ipAddress;
|
|
247
|
-
const requests = getRequestCount(clientIp);
|
|
248
|
-
|
|
249
|
-
if (requests > 100) {
|
|
250
|
-
response.setStatusCode(429);
|
|
251
|
-
return { error: 'Too many requests' };
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### Validation Hook
|
|
257
|
-
```typescript
|
|
258
|
-
const validateUserData = ({ request, response }) => {
|
|
259
|
-
const userData = request.body;
|
|
260
|
-
|
|
261
|
-
if (!userData.name || !userData.email) {
|
|
262
|
-
response.setStatusCode(400);
|
|
263
|
-
return { error: 'Name and email required' };
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## File Organization
|
|
269
|
-
|
|
270
|
-
### routes/users.ts
|
|
271
|
-
```typescript
|
|
272
|
-
import type { YinzerFlow } from 'yinzerflow';
|
|
273
|
-
|
|
274
|
-
export const registerUserRoutes = (app: YinzerFlow) => {
|
|
275
|
-
app.get('/api/users', getAllUsers);
|
|
276
|
-
app.post('/api/users', createUser);
|
|
277
|
-
app.get('/api/users/:id', getUserById);
|
|
278
|
-
app.put('/api/users/:id', updateUser);
|
|
279
|
-
app.delete('/api/users/:id', deleteUser);
|
|
280
|
-
};
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### Main app
|
|
284
|
-
```typescript
|
|
285
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
286
|
-
import { registerUserRoutes } from './routes/users';
|
|
287
|
-
|
|
288
|
-
const app = new YinzerFlow({ port: 3000 });
|
|
289
|
-
registerUserRoutes(app);
|
|
290
|
-
await app.listen();
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
## Security Checklist
|
|
294
|
-
|
|
295
|
-
- [ ] CORS configured with specific origins
|
|
296
|
-
- [ ] Body parsing limits set appropriately
|
|
297
|
-
- [ ] File upload restrictions in place
|
|
298
|
-
- [ ] IP security configured for infrastructure
|
|
299
|
-
- [ ] Error handling prevents information leakage
|
|
300
|
-
- [ ] Authentication hooks implemented
|
|
301
|
-
- [ ] Rate limiting configured
|
|
302
|
-
- [ ] HTTPS enabled (production)
|
|
303
|
-
- [ ] Security headers configured
|
|
304
|
-
- [ ] Logging configured to avoid sensitive data
|
|
305
|
-
|
|
306
|
-
## Common Issues
|
|
307
|
-
|
|
308
|
-
### CORS Errors
|
|
309
|
-
```typescript
|
|
310
|
-
cors: {
|
|
311
|
-
enabled: true,
|
|
312
|
-
origin: ['https://yourdomain.com'], // Specific origin
|
|
313
|
-
credentials: true // If using cookies
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### File Upload Issues
|
|
318
|
-
```typescript
|
|
319
|
-
bodyParser: {
|
|
320
|
-
fileUploads: {
|
|
321
|
-
maxFileSize: 10485760, // 10MB
|
|
322
|
-
allowedExtensions: ['.jpg', '.png', '.pdf']
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### IP Address Issues
|
|
328
|
-
```typescript
|
|
329
|
-
ipSecurity: {
|
|
330
|
-
trustedProxies: ['127.0.0.1', '192.168.1.10'],
|
|
331
|
-
headerPreference: ['x-forwarded-for', 'x-real-ip']
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
## Documentation Sections
|
|
336
|
-
|
|
337
|
-
- **[Getting Started](./start-here.md)** - Installation and basic setup
|
|
338
|
-
- **[Routes](./core/routes.md)** - Complete routing system
|
|
339
|
-
- **[Context Object](./core/context.md)** - Request/response interface
|
|
340
|
-
- **[Request Object](./core/request.md)** - Request data access
|
|
341
|
-
- **[Response Object](./core/response.md)** - Response control
|
|
342
|
-
- **[Error Handling](./core/error-handling.md)** - Error management
|
|
343
|
-
- **[Examples](./core/examples.md)** - Common patterns and examples
|
|
344
|
-
- **[Security Overview](./security/security-overview.md)** - Security features
|
|
345
|
-
- **[Configuration Patterns](./configuration/configuration-patterns.md)** - Configuration examples
|
|
346
|
-
- **[Advanced Configuration](./configuration/advanced-configuration-options.md)** - Complete configuration reference
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
# Body Parsing Security
|
|
2
|
-
|
|
3
|
-
YinzerFlow provides comprehensive body parsing with built-in security protections against DoS attacks, prototype pollution, and memory exhaustion vulnerabilities. The body parser automatically handles JSON, file uploads, and URL-encoded form data with configurable security limits.
|
|
4
|
-
|
|
5
|
-
For an overview of all security features, see [Security Overview](./security-overview.md).
|
|
6
|
-
|
|
7
|
-
## Configuration
|
|
8
|
-
|
|
9
|
-
Body parsing is automatically enabled with secure defaults that protect against common attack vectors:
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
13
|
-
|
|
14
|
-
const app = new YinzerFlow({
|
|
15
|
-
port: 3000,
|
|
16
|
-
bodyParser: {
|
|
17
|
-
json: {
|
|
18
|
-
maxSize: 262144, // 256KB (reasonable for JSON APIs)
|
|
19
|
-
maxDepth: 10,
|
|
20
|
-
allowPrototypeProperties: false, // Blocks prototype pollution
|
|
21
|
-
maxKeys: 1000,
|
|
22
|
-
maxStringLength: 1048576, // 1MB per string
|
|
23
|
-
maxArrayLength: 10000
|
|
24
|
-
},
|
|
25
|
-
fileUploads: {
|
|
26
|
-
maxFileSize: 10485760, // 10MB per file
|
|
27
|
-
maxTotalSize: 52428800, // 50MB total
|
|
28
|
-
maxFiles: 10,
|
|
29
|
-
allowedExtensions: [], // Empty = allow all
|
|
30
|
-
blockedExtensions: ['.exe', '.bat', '.cmd', '.scr', '.pif', '.com'],
|
|
31
|
-
maxFilenameLength: 255
|
|
32
|
-
},
|
|
33
|
-
urlEncoded: {
|
|
34
|
-
maxSize: 1048576, // 1MB
|
|
35
|
-
maxFields: 1000,
|
|
36
|
-
maxFieldNameLength: 100,
|
|
37
|
-
maxFieldLength: 1048576 // 1MB per field
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Configuration Options
|
|
44
|
-
|
|
45
|
-
#### JSON Parser Configuration
|
|
46
|
-
|
|
47
|
-
Controls how JSON request bodies are parsed and validated:
|
|
48
|
-
|
|
49
|
-
| Option | Type | Default | Description |
|
|
50
|
-
|-----|---|---|---|
|
|
51
|
-
| `maxSize` | `number` | `262144` (256KB) | Maximum JSON body size in bytes |
|
|
52
|
-
| `maxDepth` | `number` | `10` | Maximum nesting depth to prevent stack overflow |
|
|
53
|
-
| `allowPrototypeProperties` | `boolean` | `false` | Allow dangerous prototype properties (⚠️ Security Risk) |
|
|
54
|
-
| `maxKeys` | `number` | `1000` | Maximum object keys to prevent memory exhaustion |
|
|
55
|
-
| `maxStringLength` | `number` | `1048576` (1MB) | Maximum string length per property |
|
|
56
|
-
| `maxArrayLength` | `number` | `10000` | Maximum array elements per property |
|
|
57
|
-
|
|
58
|
-
#### File Upload Configuration
|
|
59
|
-
|
|
60
|
-
Controls file upload processing and security:
|
|
61
|
-
|
|
62
|
-
| Option | Type | Default | Description |
|
|
63
|
-
|-----|---|---|---|
|
|
64
|
-
| `maxFileSize` | `number` | `10485760` (10MB) | Maximum size per individual file |
|
|
65
|
-
| `maxTotalSize` | `number` | `52428800` (50MB) | Maximum total upload size per request |
|
|
66
|
-
| `maxFiles` | `number` | `10` | Maximum number of files per request |
|
|
67
|
-
| `allowedExtensions` | `string[]` | `[]` | Allowed file extensions (empty = allow all) |
|
|
68
|
-
| `blockedExtensions` | `string[]` | `['.exe', '.bat', ...]` | Blocked file extensions for security |
|
|
69
|
-
| `maxFilenameLength` | `number` | `255` | Maximum filename length |
|
|
70
|
-
|
|
71
|
-
#### URL-Encoded Form Configuration
|
|
72
|
-
|
|
73
|
-
Controls form data parsing and validation:
|
|
74
|
-
|
|
75
|
-
| Option | Type | Default | Description |
|
|
76
|
-
|-----|---|---|---|
|
|
77
|
-
| `maxSize` | `number` | `1048576` (1MB) | Maximum form data size |
|
|
78
|
-
| `maxFields` | `number` | `1000` | Maximum form fields to prevent DoS |
|
|
79
|
-
| `maxFieldNameLength` | `number` | `100` | Maximum field name length |
|
|
80
|
-
| `maxFieldLength` | `number` | `1048576` (1MB) | Maximum field value length |
|
|
81
|
-
|
|
82
|
-
## Examples
|
|
83
|
-
|
|
84
|
-
#### Strict API Configuration
|
|
85
|
-
```typescript
|
|
86
|
-
const strictApiApp = new YinzerFlow({
|
|
87
|
-
port: 3000,
|
|
88
|
-
bodyParser: {
|
|
89
|
-
json: {
|
|
90
|
-
maxSize: 131072, // 128KB - smaller for strict APIs
|
|
91
|
-
maxDepth: 5, // Shallow nesting only
|
|
92
|
-
allowPrototypeProperties: false, // Always keep false!
|
|
93
|
-
maxKeys: 100, // Fewer keys allowed
|
|
94
|
-
maxStringLength: 10240, // 10KB strings max
|
|
95
|
-
maxArrayLength: 100 // Small arrays only
|
|
96
|
-
},
|
|
97
|
-
fileUploads: {
|
|
98
|
-
maxFileSize: 1048576, // 1MB files only
|
|
99
|
-
maxFiles: 3, // Very few files
|
|
100
|
-
allowedExtensions: ['.jpg', '.png', '.pdf'], // Specific types only
|
|
101
|
-
maxFilenameLength: 50 // Short filenames
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
#### Media Upload Configuration
|
|
108
|
-
```typescript
|
|
109
|
-
const mediaApp = new YinzerFlow({
|
|
110
|
-
port: 3000,
|
|
111
|
-
bodyParser: {
|
|
112
|
-
json: {
|
|
113
|
-
maxSize: 512000, // 500KB for metadata
|
|
114
|
-
maxDepth: 3, // Simple metadata only
|
|
115
|
-
allowPrototypeProperties: false
|
|
116
|
-
},
|
|
117
|
-
fileUploads: {
|
|
118
|
-
maxFileSize: 104857600, // 100MB per file for media
|
|
119
|
-
maxTotalSize: 524288000, // 500MB total
|
|
120
|
-
maxFiles: 20,
|
|
121
|
-
allowedExtensions: ['.jpg', '.jpeg', '.png', '.gif', '.mp4', '.webm', '.pdf'],
|
|
122
|
-
blockedExtensions: [], // Using allowlist instead
|
|
123
|
-
maxFilenameLength: 200
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
#### High-Security Configuration
|
|
130
|
-
```typescript
|
|
131
|
-
const secureApp = new YinzerFlow({
|
|
132
|
-
port: 443,
|
|
133
|
-
bodyParser: {
|
|
134
|
-
json: {
|
|
135
|
-
maxSize: 32768, // 32KB only
|
|
136
|
-
maxDepth: 3,
|
|
137
|
-
maxKeys: 50
|
|
138
|
-
},
|
|
139
|
-
fileUploads: {
|
|
140
|
-
maxFileSize: 0, // No file uploads
|
|
141
|
-
maxFiles: 0
|
|
142
|
-
},
|
|
143
|
-
urlEncoded: {
|
|
144
|
-
maxSize: 8192, // 8KB forms only
|
|
145
|
-
maxFields: 20
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## Common Use Cases
|
|
152
|
-
|
|
153
|
-
- **API Data Processing**: Parse JSON payloads with automatic security validation and DoS protection
|
|
154
|
-
- **File Upload Handling**: Secure file upload processing with size, type, and count restrictions
|
|
155
|
-
- **Form Data Processing**: Handle HTML form submissions with field validation and memory protection
|
|
156
|
-
- **Content Type Detection**: Automatic parsing based on Content-Type headers with fallback handling
|
|
157
|
-
- **Security Compliance**: Built-in protection against common web vulnerabilities and attack vectors
|
|
158
|
-
- **Memory Protection**: Prevent DoS attacks through configurable size and complexity limits
|
|
159
|
-
|
|
160
|
-
## API Reference
|
|
161
|
-
|
|
162
|
-
### Request Body Properties
|
|
163
|
-
|
|
164
|
-
When body parsing is successful, the parsed data is available on `request.body`:
|
|
165
|
-
|
|
166
|
-
#### JSON Requests
|
|
167
|
-
```typescript
|
|
168
|
-
// Content-Type: application/json
|
|
169
|
-
request.body: unknown // Parsed JSON object or array
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
#### File Upload Requests
|
|
173
|
-
```typescript
|
|
174
|
-
// Content-Type: multipart/form-data
|
|
175
|
-
request.body: {
|
|
176
|
-
fields: Record<string, string | string[]>; // Form fields
|
|
177
|
-
files: Array<{
|
|
178
|
-
fieldname: string;
|
|
179
|
-
filename: string;
|
|
180
|
-
mimetype: string;
|
|
181
|
-
size: number;
|
|
182
|
-
buffer: Buffer;
|
|
183
|
-
}>;
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
#### URL-Encoded Form Requests
|
|
188
|
-
```typescript
|
|
189
|
-
// Content-Type: application/x-www-form-urlencoded
|
|
190
|
-
request.body: Record<string, string | string[]> // Parsed form data
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Configuration Methods
|
|
194
|
-
|
|
195
|
-
Body parser configuration is set during YinzerFlow initialization:
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
const app = new YinzerFlow({
|
|
199
|
-
bodyParser: {
|
|
200
|
-
json: JsonParserOptions,
|
|
201
|
-
fileUploads: FileUploadOptions,
|
|
202
|
-
urlEncoded: UrlEncodedOptions
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
## Configuration Validation and Warnings
|
|
208
|
-
|
|
209
|
-
YinzerFlow validates all body parser configuration options and provides security warnings for potentially risky settings:
|
|
210
|
-
|
|
211
|
-
### Automatic Validation
|
|
212
|
-
- **Minimum limits**: Prevents broken configurations (e.g., maxSize: 0)
|
|
213
|
-
- **Type checking**: Ensures proper data types for all options
|
|
214
|
-
- **Logical validation**: Checks for contradictory settings
|
|
215
|
-
|
|
216
|
-
### Security Warnings
|
|
217
|
-
YinzerFlow will log warnings (but not block) potentially risky configurations:
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
// This will trigger security warnings
|
|
221
|
-
const riskyApp = new YinzerFlow({
|
|
222
|
-
bodyParser: {
|
|
223
|
-
json: {
|
|
224
|
-
maxSize: 52428800, // 50MB JSON - warning about memory risk
|
|
225
|
-
allowPrototypeProperties: true, // Warning about prototype pollution
|
|
226
|
-
maxDepth: 100 // Warning about stack overflow risk
|
|
227
|
-
},
|
|
228
|
-
fileUploads: {
|
|
229
|
-
maxFileSize: 1073741824, // 1GB files - warning about resources
|
|
230
|
-
allowedExtensions: ['.exe'] // Warning about dangerous file types
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
## Error Handling
|
|
237
|
-
|
|
238
|
-
YinzerFlow automatically handles body parsing errors and provides clear error messages:
|
|
239
|
-
|
|
240
|
-
**JSON parsing errors:**
|
|
241
|
-
- `Invalid JSON in request body: Unexpected token at position X`
|
|
242
|
-
- `JSON body too large: maximum 256KB allowed`
|
|
243
|
-
- `JSON nesting too deep: maximum 10 levels allowed`
|
|
244
|
-
- `JSON object has too many keys: maximum 1000 allowed`
|
|
245
|
-
|
|
246
|
-
**File upload errors:**
|
|
247
|
-
- `File too large: maximum 10MB per file allowed`
|
|
248
|
-
- `Too many files: maximum 10 files per request`
|
|
249
|
-
- `File type not allowed: .exe files are blocked`
|
|
250
|
-
- `Total upload size exceeded: maximum 50MB total allowed`
|
|
251
|
-
|
|
252
|
-
**URL-encoded form errors:**
|
|
253
|
-
- `Form data too large: maximum 1MB allowed`
|
|
254
|
-
- `Too many form fields: maximum 1000 fields allowed`
|
|
255
|
-
- `Form field name too long: maximum 100 characters`
|
|
256
|
-
- `Form field value too large: maximum 1MB per field`
|
|
257
|
-
|
|
258
|
-
These errors automatically result in appropriate HTTP status codes (400 Bad Request) and prevent malformed or malicious requests from reaching your application handlers.
|
|
259
|
-
|
|
260
|
-
## Security Considerations
|
|
261
|
-
|
|
262
|
-
YinzerFlow implements comprehensive security measures to prevent body parsing vulnerabilities:
|
|
263
|
-
|
|
264
|
-
### 🛡️ JSON DoS Attack Prevention
|
|
265
|
-
- **Problem**: Large or deeply nested JSON can cause memory exhaustion and stack overflow attacks
|
|
266
|
-
- **YinzerFlow Solution**: Configurable size limits, nesting depth limits, key count restrictions, and string/array length limits prevent resource exhaustion
|
|
267
|
-
|
|
268
|
-
### 🛡️ Prototype Pollution Protection
|
|
269
|
-
- **Problem**: Malicious JSON can pollute JavaScript prototypes using `__proto__`, `constructor`, and `prototype` properties
|
|
270
|
-
- **YinzerFlow Solution**: Blocks dangerous properties by default with `allowPrototypeProperties: false` and validates all object keys
|
|
271
|
-
|
|
272
|
-
### 🛡️ File Upload Security
|
|
273
|
-
- **Problem**: Malicious file uploads can execute code, consume server resources, or bypass security controls
|
|
274
|
-
- **YinzerFlow Solution**: File type filtering, size limits, filename validation, and extension-based security controls
|
|
275
|
-
|
|
276
|
-
### 🛡️ Memory Exhaustion Protection
|
|
277
|
-
- **Problem**: Large form data, arrays, or objects can exhaust server memory and cause crashes
|
|
278
|
-
- **YinzerFlow Solution**: Configurable limits on strings, arrays, fields, object keys, and total request sizes
|
|
279
|
-
|
|
280
|
-
### 🛡️ Request Size Validation
|
|
281
|
-
- **Problem**: Extremely large requests can cause DoS through resource exhaustion
|
|
282
|
-
- **YinzerFlow Solution**: Content-type specific size limits with early validation before full parsing
|
|
283
|
-
|
|
284
|
-
### 🛡️ Malformed Data Handling
|
|
285
|
-
- **Problem**: Invalid or malformed data can crash parsers, cause security issues, or bypass validation
|
|
286
|
-
- **YinzerFlow Solution**: Graceful error handling with detailed security context and safe fallback parsing
|
|
287
|
-
|
|
288
|
-
### 🛡️ Filename Injection Prevention
|
|
289
|
-
- **Problem**: Malicious filenames can contain path traversal attacks or dangerous characters
|
|
290
|
-
- **YinzerFlow Solution**: Filename length validation, character sanitization, and path traversal prevention
|
|
291
|
-
|
|
292
|
-
### 🛡️ MIME Type Validation
|
|
293
|
-
- **Problem**: Spoofed or incorrect MIME types can bypass security filters
|
|
294
|
-
- **YinzerFlow Solution**: Content-Type header validation and file extension cross-checking for uploaded files
|
|
295
|
-
|
|
296
|
-
These security measures ensure YinzerFlow's body parsing implementation follows security best practices and prevents common attack vectors while maintaining spec compliance.
|