yinzerflow 0.2.7 → 0.2.9
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/docs/{advanced-configuration-options.md → configuration/advanced-configuration-options.md} +2 -0
- package/docs/configuration/configuration-patterns.md +500 -0
- package/docs/core/context.md +92 -0
- package/docs/core/error-handling.md +293 -0
- package/docs/core/examples.md +195 -0
- package/docs/{request.md → core/request.md} +3 -36
- package/docs/{response.md → core/response.md} +1 -40
- package/docs/{routes.md → core/routes.md} +17 -116
- package/docs/quick-reference.md +346 -0
- package/docs/{body-parsing.md → security/body-parsing.md} +3 -1
- package/docs/{cors.md → security/cors.md} +3 -1
- package/docs/{ip-security.md → security/ip-security.md} +3 -1
- package/docs/security/security-overview.md +282 -0
- package/docs/start-here.md +14 -8
- package/example/app/handlers/example.ts +1 -4
- package/example/app/index.ts +10 -15
- package/example/docker-compose.yml +1 -1
- package/index.d.ts +1 -1
- package/index.js +11 -11
- package/index.js.map +10 -10
- package/package.json +1 -1
- /package/docs/{logging.md → security/logging.md} +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# Security Overview
|
|
2
|
+
|
|
3
|
+
YinzerFlow implements a comprehensive security-first approach with built-in protections against common web vulnerabilities. This overview covers the key security features and how they work together to protect your applications.
|
|
4
|
+
|
|
5
|
+
## Security Architecture
|
|
6
|
+
|
|
7
|
+
YinzerFlow's security is built on multiple layers of protection:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Application Layer │
|
|
12
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
|
|
13
|
+
│ │ Route Security│ │ Error Handling │ │ Logging │ │
|
|
14
|
+
│ │ - Validation │ │ - Catching │ │ - Audit │ │
|
|
15
|
+
│ │ - Sanitization│ │ - Reporting │ │ - Monitor │ │
|
|
16
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
|
|
17
|
+
└─────────────────────────────────────────────────────────────┘
|
|
18
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ Framework Layer │
|
|
20
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
|
|
21
|
+
│ │ Body Parsing │ │ CORS │ │ IP Security │ │
|
|
22
|
+
│ │ - DoS Protection│ │ - Origin Valid │ │ - Spoofing │ │
|
|
23
|
+
│ │ - Size Limits │ │ - Headers │ │ - Detection │ │
|
|
24
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
|
|
25
|
+
└─────────────────────────────────────────────────────────────┘
|
|
26
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
27
|
+
│ Network Layer │
|
|
28
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
|
|
29
|
+
│ │ HTTP Headers │ │ Request Size │ │ Timeouts │ │
|
|
30
|
+
│ │ - Validation │ │ - Limits │ │ - Limits │ │
|
|
31
|
+
│ │ - Sanitization│ │ - Protection │ │ - Graceful │ │
|
|
32
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
|
|
33
|
+
└─────────────────────────────────────────────────────────────┘
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Core Security Features
|
|
37
|
+
|
|
38
|
+
### 🛡️ Body Parsing Security
|
|
39
|
+
**Protection**: DoS attacks, prototype pollution, memory exhaustion
|
|
40
|
+
**Implementation**: Configurable size limits, depth validation, type checking
|
|
41
|
+
**Documentation**: [Body Parsing Security](./body-parsing.md)
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const secureApp = new YinzerFlow({
|
|
45
|
+
bodyParser: {
|
|
46
|
+
json: {
|
|
47
|
+
maxSize: 262144, // 256KB limit
|
|
48
|
+
maxDepth: 10, // Prevent stack overflow
|
|
49
|
+
allowPrototypeProperties: false, // Block prototype pollution
|
|
50
|
+
maxKeys: 1000 // Prevent memory exhaustion
|
|
51
|
+
},
|
|
52
|
+
fileUploads: {
|
|
53
|
+
maxFileSize: 10485760, // 10MB per file
|
|
54
|
+
blockedExtensions: ['.exe', '.bat', '.cmd'], // Block dangerous files
|
|
55
|
+
maxFiles: 10
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 🛡️ CORS Security
|
|
62
|
+
**Protection**: Cross-origin attacks, unauthorized access
|
|
63
|
+
**Implementation**: Origin validation, header sanitization, preflight handling
|
|
64
|
+
**Documentation**: [CORS Security](./cors.md)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const secureApp = new YinzerFlow({
|
|
68
|
+
cors: {
|
|
69
|
+
enabled: true,
|
|
70
|
+
origin: ['https://yourdomain.com'], // Specific origins only
|
|
71
|
+
credentials: true,
|
|
72
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
73
|
+
allowedHeaders: ['Content-Type', 'Authorization']
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 🛡️ IP Security
|
|
79
|
+
**Protection**: IP spoofing, load balancer bypass
|
|
80
|
+
**Implementation**: Trusted proxy validation, chain length limits
|
|
81
|
+
**Documentation**: [IP Security](./ip-security.md)
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const secureApp = new YinzerFlow({
|
|
85
|
+
ipSecurity: {
|
|
86
|
+
trustedProxies: ['127.0.0.1', '192.168.1.10'],
|
|
87
|
+
allowPrivateIps: true,
|
|
88
|
+
headerPreference: ['x-forwarded-for', 'x-real-ip'],
|
|
89
|
+
maxChainLength: 10,
|
|
90
|
+
detectSpoofing: true
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 🛡️ Route Security
|
|
96
|
+
**Protection**: Path traversal, parameter injection, method confusion
|
|
97
|
+
**Implementation**: Parameter validation, path normalization, method validation
|
|
98
|
+
**Documentation**: [Route Security](../core/routes.md#security-considerations)
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Automatic protection against:
|
|
102
|
+
// - Path traversal: /api/../etc/passwd
|
|
103
|
+
// - Parameter injection: /api/users/'; DROP TABLE users; --
|
|
104
|
+
// - Method confusion: Invalid HTTP methods
|
|
105
|
+
app.get('/api/users/:id', ({ request }) => {
|
|
106
|
+
const userId = request.params.id; // Automatically validated
|
|
107
|
+
return { userId };
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 🛡️ Error Handling Security
|
|
112
|
+
**Protection**: Information leakage, error-based attacks
|
|
113
|
+
**Implementation**: Safe error responses, no stack traces in production
|
|
114
|
+
**Documentation**: [Error Handling Security](../core/error-handling.md)
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// Global error handler prevents information leakage
|
|
118
|
+
app.onError(({ response }, error) => {
|
|
119
|
+
response.setStatusCode(500);
|
|
120
|
+
return { error: 'Internal server error' }; // No sensitive details
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 🛡️ Logging Security
|
|
125
|
+
**Protection**: Log injection, sensitive data exposure
|
|
126
|
+
**Implementation**: Structured logging, sensitive data filtering
|
|
127
|
+
**Documentation**: [Logging Security](./logging.md)
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const secureApp = new YinzerFlow({
|
|
131
|
+
logger: {
|
|
132
|
+
level: 'info',
|
|
133
|
+
sensitiveFields: ['password', 'token', 'secret'],
|
|
134
|
+
maskPatterns: [/credit_card_\d+/, /ssn_\d+/]
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Security Configuration Patterns
|
|
140
|
+
|
|
141
|
+
For detailed configuration examples and patterns, see [Configuration Patterns](../configuration/configuration-patterns.md).
|
|
142
|
+
|
|
143
|
+
### Security-First Configuration Principles
|
|
144
|
+
|
|
145
|
+
1. **Principle of Least Privilege**
|
|
146
|
+
- Configure only the features you need
|
|
147
|
+
- Use specific origins instead of wildcards
|
|
148
|
+
- Limit file upload types and sizes
|
|
149
|
+
- Restrict HTTP methods to those you use
|
|
150
|
+
|
|
151
|
+
2. **Defense in Depth**
|
|
152
|
+
- Combine multiple security layers
|
|
153
|
+
- Validate at both framework and application levels
|
|
154
|
+
- Use hooks for additional validation
|
|
155
|
+
- Implement custom security checks
|
|
156
|
+
|
|
157
|
+
3. **Secure by Default**
|
|
158
|
+
- YinzerFlow's defaults are secure
|
|
159
|
+
- Explicitly configure only when needed
|
|
160
|
+
- Test security configurations thoroughly
|
|
161
|
+
- Monitor for security events
|
|
162
|
+
|
|
163
|
+
4. **Regular Security Updates**
|
|
164
|
+
- Keep YinzerFlow updated
|
|
165
|
+
- Monitor security advisories
|
|
166
|
+
- Review and update configurations
|
|
167
|
+
- Test security features regularly
|
|
168
|
+
|
|
169
|
+
## Security Best Practices
|
|
170
|
+
|
|
171
|
+
For detailed security configuration examples and best practices, see [Configuration Patterns](../configuration/configuration-patterns.md).
|
|
172
|
+
|
|
173
|
+
### Key Security Principles
|
|
174
|
+
|
|
175
|
+
1. **Principle of Least Privilege** - Configure only what you need
|
|
176
|
+
2. **Defense in Depth** - Multiple security layers
|
|
177
|
+
3. **Secure by Default** - YinzerFlow's defaults are secure
|
|
178
|
+
4. **Regular Security Updates** - Keep configurations current
|
|
179
|
+
|
|
180
|
+
## Security Monitoring
|
|
181
|
+
|
|
182
|
+
### Built-in Security Logging
|
|
183
|
+
YinzerFlow automatically logs security events:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Automatic logging of:
|
|
187
|
+
// - CORS violations
|
|
188
|
+
// - Body parsing errors
|
|
189
|
+
// - IP spoofing attempts
|
|
190
|
+
// - Route validation failures
|
|
191
|
+
// - Security configuration errors
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Custom Security Monitoring
|
|
195
|
+
Add custom security monitoring with hooks:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
app.beforeAll([
|
|
199
|
+
({ request, response }) => {
|
|
200
|
+
// Monitor for suspicious patterns
|
|
201
|
+
const suspiciousPatterns = [
|
|
202
|
+
/\.\.\//, // Path traversal
|
|
203
|
+
/<script>/i, // XSS attempts
|
|
204
|
+
/union\s+select/i, // SQL injection
|
|
205
|
+
/javascript:/i // Protocol injection
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
const url = request.url;
|
|
209
|
+
const body = JSON.stringify(request.body);
|
|
210
|
+
|
|
211
|
+
for (const pattern of suspiciousPatterns) {
|
|
212
|
+
if (pattern.test(url) || pattern.test(body)) {
|
|
213
|
+
console.warn('🚨 Suspicious request detected:', {
|
|
214
|
+
ip: request.ipAddress,
|
|
215
|
+
url: request.url,
|
|
216
|
+
pattern: pattern.source
|
|
217
|
+
});
|
|
218
|
+
response.setStatusCode(400);
|
|
219
|
+
return { error: 'Invalid request' };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
]);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Security Testing
|
|
227
|
+
|
|
228
|
+
### Automated Security Testing
|
|
229
|
+
Test your security configuration:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// Test body parsing limits
|
|
233
|
+
const testBodyLimits = async () => {
|
|
234
|
+
const response = await fetch('http://localhost:3000/api/test', {
|
|
235
|
+
method: 'POST',
|
|
236
|
+
headers: { 'Content-Type': 'application/json' },
|
|
237
|
+
body: JSON.stringify({ data: 'x'.repeat(300000) }) // Exceeds 256KB limit
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
console.assert(response.status === 413, 'Body size limit not enforced');
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Test CORS configuration
|
|
244
|
+
const testCORS = async () => {
|
|
245
|
+
const response = await fetch('http://localhost:3000/api/test', {
|
|
246
|
+
method: 'OPTIONS',
|
|
247
|
+
headers: { 'Origin': 'https://malicious.com' }
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
console.assert(response.status === 403, 'CORS origin validation not working');
|
|
251
|
+
};
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Security Checklist
|
|
255
|
+
|
|
256
|
+
Before deploying to production, verify:
|
|
257
|
+
|
|
258
|
+
- [ ] Body parsing limits configured appropriately
|
|
259
|
+
- [ ] CORS origins restricted to trusted domains
|
|
260
|
+
- [ ] IP security configured for your infrastructure
|
|
261
|
+
- [ ] File upload restrictions in place
|
|
262
|
+
- [ ] Error handling prevents information leakage
|
|
263
|
+
- [ ] Logging configured to avoid sensitive data exposure
|
|
264
|
+
- [ ] Security headers enabled
|
|
265
|
+
- [ ] HTTPS configured (if applicable)
|
|
266
|
+
- [ ] Security monitoring in place
|
|
267
|
+
- [ ] Regular security updates scheduled
|
|
268
|
+
|
|
269
|
+
## Getting Help
|
|
270
|
+
|
|
271
|
+
For detailed security documentation:
|
|
272
|
+
- **[Body Parsing](./body-parsing.md)** - File upload and JSON parsing security
|
|
273
|
+
- **[CORS](./cors.md)** - Cross-origin request security
|
|
274
|
+
- **[IP Security](./ip-security.md)** - Client IP validation and protection
|
|
275
|
+
- **[Logging](./logging.md)** - Secure logging practices
|
|
276
|
+
- **[Error Handling](../core/error-handling.md)** - Secure error handling patterns
|
|
277
|
+
|
|
278
|
+
For security issues or questions:
|
|
279
|
+
- Check the security documentation above
|
|
280
|
+
- Review the security configuration examples
|
|
281
|
+
- Test your security setup thoroughly
|
|
282
|
+
- Consider security implications of all custom code
|
package/docs/start-here.md
CHANGED
|
@@ -13,6 +13,8 @@ YinzerFlow is designed for developers who want:
|
|
|
13
13
|
|
|
14
14
|
## Quick Start
|
|
15
15
|
|
|
16
|
+
For a complete quick reference with all common patterns, see [Quick Reference](./quick-reference.md).
|
|
17
|
+
|
|
16
18
|
### Installation
|
|
17
19
|
|
|
18
20
|
```bash
|
|
@@ -106,17 +108,21 @@ For custom shutdown handling, see [Advanced Configuration](./advanced-configurat
|
|
|
106
108
|
|
|
107
109
|
### Core Features
|
|
108
110
|
|
|
109
|
-
- **[Routes](./routes.md)** - Comprehensive routing system with HTTP methods, parameters, hooks, and groups
|
|
110
|
-
- **[
|
|
111
|
-
- **[
|
|
112
|
-
- **[
|
|
111
|
+
- **[Routes](./core/routes.md)** - Comprehensive routing system with HTTP methods, parameters, hooks, and groups
|
|
112
|
+
- **[Context Object](./core/context.md)** - Central interface for request data, response controls, and request lifecycle
|
|
113
|
+
- **[Request Object](./core/request.md)** - Access headers, body, query parameters, route parameters, and raw body
|
|
114
|
+
- **[Response Object](./core/response.md)** - Set status codes, headers, and return various response types
|
|
115
|
+
- **[Error Handling](./core/error-handling.md)** - Automatic error catching, custom error handlers, and comprehensive error management
|
|
113
116
|
|
|
114
117
|
### Security & Configuration
|
|
115
118
|
|
|
116
|
-
- **[
|
|
117
|
-
- **[
|
|
118
|
-
- **[CORS](./cors.md)** - Cross-Origin Resource Sharing with comprehensive security measures
|
|
119
|
-
- **[
|
|
119
|
+
- **[Security Overview](./security/security-overview.md)** - Comprehensive security features and configuration patterns
|
|
120
|
+
- **[Body Parsing](./security/body-parsing.md)** - Secure parsing of JSON, file uploads, and form data with DoS protection
|
|
121
|
+
- **[CORS](./security/cors.md)** - Cross-Origin Resource Sharing with comprehensive security measures
|
|
122
|
+
- **[IP Security](./security/ip-security.md)** - Client IP validation and spoofing protection for load balancers and CDNs
|
|
123
|
+
- **[Logging](./security/logging.md)** - Flexible logging with custom logger support and Pittsburgh personality
|
|
124
|
+
- **[Configuration Patterns](./configuration/configuration-patterns.md)** - Common configuration patterns and best practices
|
|
125
|
+
- **[Advanced Configuration](./configuration/advanced-configuration-options.md)** - Fine-tune security, performance, and functionality
|
|
120
126
|
|
|
121
127
|
### Common Use Cases
|
|
122
128
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import type { HandlerCallback } from 'yinzerflow';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
4
|
export const exampleHandler: HandlerCallback<{
|
|
8
5
|
body: {
|
|
9
6
|
something: string;
|
|
@@ -15,10 +12,10 @@ export const exampleHandler: HandlerCallback<{
|
|
|
15
12
|
something: string;
|
|
16
13
|
}
|
|
17
14
|
}
|
|
18
|
-
|
|
19
15
|
}> = async ({ request }) => {
|
|
20
16
|
const { something } = request.body;
|
|
21
17
|
|
|
18
|
+
throw new Error("test");
|
|
22
19
|
|
|
23
20
|
return {
|
|
24
21
|
success: true,
|
package/example/app/index.ts
CHANGED
|
@@ -6,17 +6,11 @@ import { YinzerFlow, type HandlerCallback } from "yinzerflow";
|
|
|
6
6
|
const app = new YinzerFlow({
|
|
7
7
|
cors: {
|
|
8
8
|
enabled: true,
|
|
9
|
-
origin: "
|
|
9
|
+
origin: "http://localhost:8085",
|
|
10
10
|
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
11
11
|
allowedHeaders: ["Content-Type", "Authorization", "x-session-id"],
|
|
12
12
|
preflightContinue: false,
|
|
13
13
|
},
|
|
14
|
-
bodyParser: {
|
|
15
|
-
json: {
|
|
16
|
-
maxDepth: 500
|
|
17
|
-
},
|
|
18
|
-
|
|
19
|
-
},
|
|
20
14
|
logLevel: "info",
|
|
21
15
|
networkLogs: true,
|
|
22
16
|
// logger: log,
|
|
@@ -25,13 +19,13 @@ const app = new YinzerFlow({
|
|
|
25
19
|
|
|
26
20
|
|
|
27
21
|
|
|
28
|
-
app.onError((ctx) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
22
|
+
// app.onError((ctx) => {
|
|
23
|
+
// ctx.response.setStatusCode(500);
|
|
24
|
+
// return {
|
|
25
|
+
// success: false,
|
|
26
|
+
// message: "Something went wrong",
|
|
27
|
+
// };
|
|
28
|
+
// });
|
|
35
29
|
|
|
36
30
|
app.onNotFound((ctx) => {
|
|
37
31
|
ctx.response.setStatusCode(404);
|
|
@@ -49,7 +43,7 @@ app.beforeAll([
|
|
|
49
43
|
|
|
50
44
|
app.afterAll([
|
|
51
45
|
(ctx) => {
|
|
52
|
-
ctx.response.setStatusCode(202);
|
|
46
|
+
// ctx.response.setStatusCode(202);
|
|
53
47
|
console.log("afterAll");
|
|
54
48
|
},
|
|
55
49
|
]);
|
|
@@ -110,3 +104,4 @@ registerGroupExampleRoutes(app);
|
|
|
110
104
|
|
|
111
105
|
// Start the server AFTER defining all routes
|
|
112
106
|
await app.listen();
|
|
107
|
+
|
package/index.d.ts
CHANGED
|
@@ -159,7 +159,7 @@ export interface Context<T extends InternalHandlerCallbackGenerics = InternalHan
|
|
|
159
159
|
* @param ctx - The request context containing request and response objects
|
|
160
160
|
* @returns A response body or a promise that resolves to a response body
|
|
161
161
|
*/
|
|
162
|
-
export type HandlerCallback<T extends InternalHandlerCallbackGenerics = InternalHandlerCallbackGenerics> = (ctx: Context<T
|
|
162
|
+
export type HandlerCallback<T extends InternalHandlerCallbackGenerics = InternalHandlerCallbackGenerics> = (ctx: Context<T>, error?: unknown) => Promise<T["response"] | void> | T["response"] | void;
|
|
163
163
|
export type InternalGlobalHookOptions = {
|
|
164
164
|
routesToExclude: Array<string>;
|
|
165
165
|
} & {
|