@reldens/server-utils 0.42.0 → 0.44.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/.claude/api-reference.md +333 -0
- package/.claude/package-architecture.md +177 -0
- package/CLAUDE.md +61 -202
- package/README.md +81 -2
- package/lib/app-server-factory/cors-configurer.js +10 -0
- package/lib/app-server-factory/development-mode-detector.js +25 -0
- package/lib/app-server-factory/protocol-enforcer.js +11 -0
- package/lib/app-server-factory/rate-limit-configurer.js +10 -0
- package/lib/app-server-factory/reverse-proxy-configurer.js +26 -1
- package/lib/app-server-factory/security-configurer.js +18 -0
- package/lib/app-server-factory.js +122 -10
- package/lib/cdn-request-handler.js +130 -0
- package/lib/event-dispatcher.js +26 -0
- package/lib/file-handler.js +13 -0
- package/lib/http2-cdn-server.js +156 -46
- package/lib/request-logger.js +42 -0
- package/lib/server-error-handler.js +25 -0
- package/package.json +2 -2
package/CLAUDE.md
CHANGED
|
@@ -21,215 +21,74 @@ npm test
|
|
|
21
21
|
|
|
22
22
|
## Architecture
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
- Key file operations:
|
|
30
|
-
- `exists(filePath)` - Check if file/directory exists
|
|
31
|
-
- `readFile(filePath)` - Read file contents
|
|
32
|
-
- `writeFile(filePath, content)` - Write file
|
|
33
|
-
- `createFolder(folderPath)` - Create directory recursively
|
|
34
|
-
- `remove(fullPath)` - Remove file/folder recursively
|
|
35
|
-
- `copyFile(from, to)` - Copy file
|
|
36
|
-
- `copyFolderSync(from, to)` - Copy folder recursively
|
|
37
|
-
- `moveFile(from, to)` - Move/rename file
|
|
38
|
-
- Path operations:
|
|
39
|
-
- `joinPaths(...paths)` - Join path segments
|
|
40
|
-
- `getFileName(filePath)` - Get file name (basename)
|
|
41
|
-
- `getFolderName(filePath)` - Get directory name (dirname)
|
|
42
|
-
- `getRelativePath(from, to)` - Calculate relative path
|
|
43
|
-
- `normalizePath(filePath)` - Normalize path
|
|
44
|
-
- `isAbsolutePath(filePath)` - Check if path is absolute
|
|
45
|
-
- File inspection:
|
|
46
|
-
- `isFile(filePath)` - Check if path is a file
|
|
47
|
-
- `isFolder(dirPath)` - Check if path is a folder
|
|
48
|
-
- `getFileSize(filePath)` - Get file size in bytes
|
|
49
|
-
- `getFileStats(filePath)` - Get file stats
|
|
50
|
-
- `getFilesInFolder(dirPath, extensions)` - List files with optional filtering
|
|
51
|
-
- `fetchSubFoldersList(folder, options)` - Get subfolder list
|
|
52
|
-
- JSON operations:
|
|
53
|
-
- `fetchFileJson(filePath)` - Read and parse JSON file
|
|
54
|
-
- `isValidJson(filePath)` - Validate JSON file
|
|
55
|
-
- Security features:
|
|
56
|
-
- `generateSecureFilename(originalName)` - Generate secure random filename
|
|
57
|
-
- `validateFileType(filePath, type, allowedTypes, maxSize)` - Validate file
|
|
58
|
-
- `detectFileType(filePath)` - Detect MIME type from magic numbers
|
|
59
|
-
- `quarantineFile(filePath, reason)` - Move suspicious file to quarantine
|
|
60
|
-
- `isValidPath(filePath)` - Validate path for security
|
|
61
|
-
- `sanitizePath(filePath)` - Sanitize path string
|
|
62
|
-
- Advanced operations:
|
|
63
|
-
- `walkDirectory(dirPath, callback)` - Recursively process directory tree
|
|
64
|
-
- `getDirectorySize(dirPath)` - Calculate total directory size
|
|
65
|
-
- `emptyDirectory(dirPath)` - Remove all contents from directory
|
|
66
|
-
- `compareFiles(file1, file2)` - Compare file contents
|
|
67
|
-
- `appendToFile(filePath, content)` - Append to file
|
|
68
|
-
- `prependToFile(filePath, content)` - Prepend to file
|
|
69
|
-
- `replaceInFile(filePath, searchValue, replaceValue)` - Replace in file
|
|
70
|
-
- All methods include built-in error handling, no need for try/catch
|
|
71
|
-
- DO NOT use FileHandler.exists to validate other FileHandler methods
|
|
72
|
-
- DO NOT enclose FileHandler methods in try/catch blocks
|
|
24
|
+
See `.claude/package-architecture.md` for detailed information about:
|
|
25
|
+
- Design philosophy and independence principles
|
|
26
|
+
- Callback-based extensibility pattern
|
|
27
|
+
- Available callbacks (onError, onRequestSuccess, onRequestError, onEvent)
|
|
28
|
+
- Integration patterns
|
|
73
29
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- Hashing and verification:
|
|
112
|
-
- `hashData(data, algorithm)` - Hash with SHA-256, SHA-512, or MD5
|
|
113
|
-
- `generateHMAC(data, secret, algorithm)` - Generate HMAC signature
|
|
114
|
-
- `verifyHMAC(data, secret, signature, algorithm)` - Verify HMAC signature
|
|
115
|
-
- `constantTimeCompare(a, b)` - Constant-time string comparison
|
|
116
|
-
|
|
117
|
-
**UploaderFactory** (`lib/uploader-factory.js`):
|
|
118
|
-
- File upload handling with Multer
|
|
119
|
-
- Multi-level security validation:
|
|
120
|
-
- Filename security validation
|
|
121
|
-
- MIME type validation
|
|
122
|
-
- File extension validation
|
|
123
|
-
- File size validation
|
|
124
|
-
- Content validation using magic numbers
|
|
125
|
-
- Dangerous extension filtering
|
|
126
|
-
- Features:
|
|
127
|
-
- Multiple file upload support with field mapping
|
|
128
|
-
- Secure filename generation option
|
|
129
|
-
- Automatic cleanup on validation failure
|
|
130
|
-
- Custom error response handling
|
|
131
|
-
- Per-field destination mapping
|
|
132
|
-
- Methods:
|
|
133
|
-
- `createUploader(fields, buckets, allowedFileTypes)` - Create upload middleware
|
|
134
|
-
- `validateFilenameSecurity(filename)` - Validate filename
|
|
135
|
-
- `validateFile(file, allowedType, callback)` - Validate during upload
|
|
136
|
-
- `validateFileContents(file, allowedType)` - Validate after upload
|
|
137
|
-
- `convertToRegex(key)` - Convert MIME type patterns to regex
|
|
138
|
-
|
|
139
|
-
**Http2CdnServer** (`lib/http2-cdn-server.js`):
|
|
140
|
-
- HTTP/2 secure server for CDN-like static file serving
|
|
141
|
-
- Features:
|
|
142
|
-
- Optimized for CSS, JavaScript, images, and fonts
|
|
143
|
-
- Dynamic CORS origin validation with regex pattern support
|
|
144
|
-
- Configurable cache headers per file extension
|
|
145
|
-
- Comprehensive MIME type detection
|
|
146
|
-
- HTTP/1.1 fallback support
|
|
147
|
-
- Security headers (X-Content-Type-Options, X-Frame-Options, Vary)
|
|
148
|
-
- Query string stripping for cache optimization
|
|
149
|
-
- Methods:
|
|
150
|
-
- `create()` - Create HTTP/2 secure server
|
|
151
|
-
- `listen()` - Start listening on configured port
|
|
152
|
-
- `close()` - Gracefully close server
|
|
153
|
-
- `handleStream(stream, headers)` - Handle HTTP/2 stream
|
|
154
|
-
- `resolveFilePath(requestPath)` - Resolve file path from request
|
|
155
|
-
|
|
156
|
-
### Utility Classes
|
|
157
|
-
|
|
158
|
-
**ServerDefaultConfigurations** (`lib/server-default-configurations.js`):
|
|
159
|
-
- Static class providing default configurations
|
|
160
|
-
- `mimeTypes` - Comprehensive MIME type mappings for common file extensions
|
|
161
|
-
- `cacheConfig` - Default cache max-age settings (1 year for CSS/JS/fonts, 30 days for images)
|
|
162
|
-
|
|
163
|
-
**ServerFactoryUtils** (`lib/server-factory-utils.js`):
|
|
164
|
-
- Static utility methods for server operations
|
|
165
|
-
- `getCacheConfigForPath(path, cacheConfig)` - Get cache config for file path
|
|
166
|
-
- `validateOrigin(origin, corsOrigins, corsAllowAll)` - Validate CORS origin (supports strings and RegExp)
|
|
167
|
-
- `stripQueryString(url)` - Remove query string from URL
|
|
168
|
-
|
|
169
|
-
**ServerHeaders** (`lib/server-headers.js`):
|
|
170
|
-
- Centralized header management
|
|
171
|
-
- HTTP/2 headers configuration
|
|
172
|
-
- Express security headers
|
|
173
|
-
- Cache control headers
|
|
174
|
-
- Proxy forwarding headers
|
|
175
|
-
- `buildCacheControlHeader(maxAge)` - Build cache control header string
|
|
176
|
-
|
|
177
|
-
### Security Configurers (in `lib/app-server-factory/`)
|
|
178
|
-
|
|
179
|
-
**DevelopmentModeDetector** (`development-mode-detector.js`):
|
|
180
|
-
- Auto-detects development environment
|
|
181
|
-
- Checks NODE_ENV, domain patterns, and configured domains
|
|
182
|
-
- Built-in patterns: localhost, 127.0.0.1, .local, .test, .dev, .staging, etc.
|
|
183
|
-
- `detect(config)` - Detect if in development mode
|
|
184
|
-
- `matchesPattern(domain)` - Check if domain matches development pattern
|
|
185
|
-
|
|
186
|
-
**ProtocolEnforcer** (`protocol-enforcer.js`):
|
|
187
|
-
- Enforces HTTP/HTTPS protocol consistency
|
|
188
|
-
- Development mode awareness
|
|
189
|
-
- Automatic redirects when protocol doesn't match configuration
|
|
190
|
-
- `setup(app, config)` - Setup protocol enforcement middleware
|
|
191
|
-
|
|
192
|
-
**SecurityConfigurer** (`security-configurer.js`):
|
|
193
|
-
- Helmet integration with CSP management
|
|
194
|
-
- XSS protection with request body sanitization
|
|
195
|
-
- Development-friendly CSP configuration
|
|
196
|
-
- Supports CSP directive merging or override
|
|
197
|
-
- `setupHelmet(app, config)` - Setup Helmet middleware
|
|
198
|
-
- `setupXssProtection(app, config)` - Setup XSS protection
|
|
199
|
-
- `enableCSP(app, cspOptions)` - Enable Content Security Policy
|
|
200
|
-
- `addExternalDomainsToCsp(directives, externalDomains)` - Add external domains to CSP
|
|
201
|
-
|
|
202
|
-
**CorsConfigurer** (`cors-configurer.js`):
|
|
203
|
-
- Dynamic CORS origin validation
|
|
204
|
-
- Development domain support with automatic port variations
|
|
205
|
-
- Credential support configuration
|
|
206
|
-
- `setup(app, config)` - Setup CORS middleware
|
|
207
|
-
- `extractDevelopmentOrigins(domainMapping)` - Extract development origins
|
|
208
|
-
- `normalizeHost(originOrHost)` - Normalize host string
|
|
209
|
-
|
|
210
|
-
**RateLimitConfigurer** (`rate-limit-configurer.js`):
|
|
211
|
-
- Global and endpoint-specific rate limiting
|
|
212
|
-
- Development mode multiplier for lenient limits
|
|
213
|
-
- IP-based key generation option
|
|
214
|
-
- `setup(app, config)` - Setup global rate limiting
|
|
215
|
-
- `createHomeLimiter()` - Create homepage-specific limiter
|
|
216
|
-
|
|
217
|
-
**ReverseProxyConfigurer** (`reverse-proxy-configurer.js`):
|
|
218
|
-
- Domain-based reverse proxy routing
|
|
219
|
-
- WebSocket support
|
|
220
|
-
- SSL termination
|
|
221
|
-
- Header preservation (X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host)
|
|
222
|
-
- Virtual host integration
|
|
223
|
-
- Graceful error handling (502 Bad Gateway, 504 Gateway Timeout)
|
|
224
|
-
- `setup(app, config)` - Setup reverse proxy
|
|
225
|
-
- `createProxyMiddleware(rule)` - Create proxy middleware for rule
|
|
226
|
-
- `handleProxyError(err, req, res)` - Handle proxy errors
|
|
30
|
+
See `.claude/api-reference.md` for complete API documentation of all classes and methods.
|
|
31
|
+
|
|
32
|
+
## Core Classes Summary
|
|
33
|
+
|
|
34
|
+
**FileHandler** - Singleton wrapper for Node.js fs and path modules. Used instead of direct require('fs') or require('path') throughout Reldens.
|
|
35
|
+
|
|
36
|
+
**AppServerFactory** - Creates Express app servers with modular security components. Supports HTTP, HTTPS, HTTP/2, virtual hosts, CDN integration, reverse proxy, and callback-based logging.
|
|
37
|
+
|
|
38
|
+
**Encryptor** - Singleton for cryptographic operations including password hashing, data encryption, token generation, and HMAC verification.
|
|
39
|
+
|
|
40
|
+
**UploaderFactory** - File upload handling with Multer and multi-level security validation.
|
|
41
|
+
|
|
42
|
+
**Http2CdnServer** - HTTP/2 secure server for CDN-like static file serving with CORS, cache headers, and callback-based logging.
|
|
43
|
+
|
|
44
|
+
## Utility Classes Summary
|
|
45
|
+
|
|
46
|
+
**RequestLogger** - Express middleware for request logging that invokes callbacks based on status codes.
|
|
47
|
+
|
|
48
|
+
**EventDispatcher** - Static utility for dispatching lifecycle events with structured event data.
|
|
49
|
+
|
|
50
|
+
**ServerErrorHandler** - Centralized error handling with structured error context.
|
|
51
|
+
|
|
52
|
+
**ServerDefaultConfigurations** - Static class providing MIME types and cache configurations.
|
|
53
|
+
|
|
54
|
+
**ServerFactoryUtils** - Static utility methods for cache config, CORS validation, and URL manipulation.
|
|
55
|
+
|
|
56
|
+
**ServerHeaders** - Centralized header management for HTTP/2, security, cache, and proxy headers.
|
|
57
|
+
|
|
58
|
+
## Security Configurers Summary
|
|
59
|
+
|
|
60
|
+
Located in `lib/app-server-factory/`:
|
|
61
|
+
- **DevelopmentModeDetector** - Auto-detect development environment
|
|
62
|
+
- **ProtocolEnforcer** - HTTP/HTTPS protocol enforcement
|
|
63
|
+
- **SecurityConfigurer** - Helmet integration and XSS protection
|
|
64
|
+
- **CorsConfigurer** - CORS with dynamic origin validation
|
|
65
|
+
- **RateLimitConfigurer** - Global and endpoint-specific rate limiting
|
|
66
|
+
- **ReverseProxyConfigurer** - Domain-based reverse proxy with WebSocket support
|
|
227
67
|
|
|
228
68
|
## Important Notes
|
|
229
69
|
|
|
70
|
+
### FileHandler Usage
|
|
230
71
|
- **ALWAYS use FileHandler** instead of Node.js fs/path modules
|
|
231
72
|
- FileHandler methods have built-in error handling - no try/catch needed
|
|
232
73
|
- DO NOT enclose FileHandler methods in try/catch blocks
|
|
233
74
|
- DO NOT use FileHandler.exists to validate other FileHandler methods (e.g., before createFolder)
|
|
75
|
+
|
|
76
|
+
### Callback System
|
|
77
|
+
- Package provides callback hooks (onError, onRequestSuccess, onRequestError, onEvent)
|
|
78
|
+
- Applications provide implementations via configuration
|
|
79
|
+
- Package does NOT import @reldens/utils Logger
|
|
80
|
+
- Applications wire callbacks to their own logging/monitoring systems
|
|
81
|
+
|
|
82
|
+
### Server Configuration
|
|
234
83
|
- AppServerFactory handles all Express server configuration
|
|
235
84
|
- All server utilities support both HTTP and HTTPS
|
|
85
|
+
- Virtual hosts with SNI support for multiple domains
|
|
86
|
+
- HTTP/2 CDN server integration for static file serving
|
|
87
|
+
- Reverse proxy with WebSocket support
|
|
88
|
+
|
|
89
|
+
### Security
|
|
90
|
+
- Multi-level validation for file uploads
|
|
91
|
+
- XSS protection with request body sanitization
|
|
92
|
+
- CSP management with Helmet integration
|
|
93
|
+
- CORS with dynamic origin validation (supports strings and RegExp)
|
|
94
|
+
- Rate limiting with development mode awareness
|
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ A Node.js server toolkit providing secure application server creation, HTTP/2 CD
|
|
|
25
25
|
- Static file serving with security headers
|
|
26
26
|
- Compression middleware with smart filtering
|
|
27
27
|
- Input validation utilities
|
|
28
|
+
- Custom error handling with callback support
|
|
28
29
|
|
|
29
30
|
### Http2CdnServer
|
|
30
31
|
- Dedicated HTTP/2 server for static asset delivery
|
|
@@ -37,6 +38,8 @@ A Node.js server toolkit providing secure application server creation, HTTP/2 CD
|
|
|
37
38
|
- Standalone or integrated with AppServerFactory
|
|
38
39
|
- Multiple static path support
|
|
39
40
|
- Separate SSL certificate support from main server
|
|
41
|
+
- Comprehensive error handling (server, TLS, session, stream errors)
|
|
42
|
+
- Custom error handler callback support
|
|
40
43
|
|
|
41
44
|
#### Modular Security Components
|
|
42
45
|
The AppServerFactory now uses specialized security configurers:
|
|
@@ -47,6 +50,7 @@ The AppServerFactory now uses specialized security configurers:
|
|
|
47
50
|
- **RateLimitConfigurer** - Global and endpoint-specific rate limiting
|
|
48
51
|
- **ReverseProxyConfigurer** - Domain-based reverse proxy with WebSocket support
|
|
49
52
|
- **SecurityConfigurer** - Helmet integration with CSP management and XSS protection
|
|
53
|
+
- **ServerErrorHandler** - Centralized error handling with custom callback support
|
|
50
54
|
|
|
51
55
|
### FileHandler
|
|
52
56
|
- Secure file system operations with path validation
|
|
@@ -63,6 +67,8 @@ The AppServerFactory now uses specialized security configurers:
|
|
|
63
67
|
- Directory walking with callback processing
|
|
64
68
|
- File comparison and relative path calculations
|
|
65
69
|
- Comprehensive error handling with detailed context
|
|
70
|
+
- Read stream creation for efficient file streaming
|
|
71
|
+
- File modification time retrieval
|
|
66
72
|
|
|
67
73
|
### Encryptor
|
|
68
74
|
- Password hashing using PBKDF2 with configurable iterations
|
|
@@ -174,6 +180,34 @@ if(cdnServer.create()){
|
|
|
174
180
|
}
|
|
175
181
|
```
|
|
176
182
|
|
|
183
|
+
### Custom Error Handling
|
|
184
|
+
|
|
185
|
+
Configure custom error handlers for server errors:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
let appServerFactory = new AppServerFactory();
|
|
189
|
+
|
|
190
|
+
appServerFactory.onError = (errorData) => {
|
|
191
|
+
console.error('Server error:', errorData.key);
|
|
192
|
+
console.error('Error details:', errorData.error);
|
|
193
|
+
console.error('Context:', errorData);
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
let serverResult = appServerFactory.createAppServer({
|
|
197
|
+
port: 443,
|
|
198
|
+
useHttps: true,
|
|
199
|
+
http2CdnEnabled: true,
|
|
200
|
+
autoListen: true
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The `onError` callback receives structured error data:
|
|
205
|
+
- `instanceName` - Name of the component (e.g., 'http2CdnServer', 'appServerFactory')
|
|
206
|
+
- `instance` - Reference to the component instance
|
|
207
|
+
- `key` - Error type identifier (e.g., 'server-error', 'tls-client-error', 'proxy-error')
|
|
208
|
+
- `error` - The actual error object
|
|
209
|
+
- `...context` - Additional context data (port, path, hostname, etc.)
|
|
210
|
+
|
|
177
211
|
### HTTPS Server with Optimized Caching
|
|
178
212
|
|
|
179
213
|
```javascript
|
|
@@ -225,6 +259,18 @@ if(FileHandler.createFolder('/path/to/new/folder')){
|
|
|
225
259
|
// Generate a secure filename
|
|
226
260
|
let secureFilename = FileHandler.generateSecureFilename('user-upload.jpg');
|
|
227
261
|
console.log('Secure filename:', secureFilename);
|
|
262
|
+
|
|
263
|
+
// Create a read stream for efficient file handling
|
|
264
|
+
let stream = FileHandler.createReadStream('/path/to/large-file.txt');
|
|
265
|
+
if(stream){
|
|
266
|
+
stream.pipe(response);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Get file modification time
|
|
270
|
+
let modTime = FileHandler.getFileModificationTime('/path/to/file.txt');
|
|
271
|
+
if(modTime){
|
|
272
|
+
console.log('Last modified:', modTime);
|
|
273
|
+
}
|
|
228
274
|
```
|
|
229
275
|
|
|
230
276
|
### Password Encryption
|
|
@@ -515,7 +561,10 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
515
561
|
- Header preservation (X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host)
|
|
516
562
|
- Virtual host integration
|
|
517
563
|
- Path-based routing
|
|
518
|
-
-
|
|
564
|
+
- Comprehensive error handling with proper HTTP status codes:
|
|
565
|
+
- 502 Bad Gateway for connection refused errors
|
|
566
|
+
- 504 Gateway Timeout for timeout errors
|
|
567
|
+
- 500 Internal Server Error for other proxy errors
|
|
519
568
|
|
|
520
569
|
#### Rule Properties
|
|
521
570
|
|
|
@@ -569,6 +618,15 @@ reverseProxyRules: [
|
|
|
569
618
|
- `reverseProxyEnabled` - Enable reverse proxy (default: false)
|
|
570
619
|
- `reverseProxyRules` - Array of proxy rules (default: [])
|
|
571
620
|
|
|
621
|
+
### AppServerFactory Error Handling
|
|
622
|
+
|
|
623
|
+
- `onError` - Custom error handler callback function receiving error data:
|
|
624
|
+
- `instanceName` - Component name (e.g., 'appServerFactory', 'http2CdnServer')
|
|
625
|
+
- `instance` - Component instance reference
|
|
626
|
+
- `key` - Error type identifier (e.g., 'server-error', 'virtual-host-error')
|
|
627
|
+
- `error` - The error object
|
|
628
|
+
- Additional context data (port, hostname, path, etc.)
|
|
629
|
+
|
|
572
630
|
### Http2CdnServer Methods
|
|
573
631
|
|
|
574
632
|
- `create()` - Creates HTTP/2 secure server
|
|
@@ -591,6 +649,7 @@ reverseProxyRules: [
|
|
|
591
649
|
- `securityHeaders` - Custom security headers
|
|
592
650
|
- `varyHeader` - Vary header value (default: 'Accept-Encoding, Origin')
|
|
593
651
|
- `mimeTypes` - MIME type mappings
|
|
652
|
+
- `onError` - Custom error handler callback
|
|
594
653
|
|
|
595
654
|
### FileHandler Methods
|
|
596
655
|
|
|
@@ -620,6 +679,8 @@ reverseProxyRules: [
|
|
|
620
679
|
- `walkDirectory(path, callback)` - Recursively processes a directory tree
|
|
621
680
|
- `getDirectorySize(path)` - Calculates total directory size
|
|
622
681
|
- `emptyDirectory(path)` - Removes all contents from directory
|
|
682
|
+
- `createReadStream(path, options)` - Creates readable stream for file
|
|
683
|
+
- `getFileModificationTime(path)` - Gets file last modification time
|
|
623
684
|
|
|
624
685
|
### Encryptor Methods
|
|
625
686
|
|
|
@@ -643,6 +704,16 @@ reverseProxyRules: [
|
|
|
643
704
|
- `validateFileContents(file, allowedType)` - Validates file content after upload
|
|
644
705
|
- `convertToRegex(key)` - Converts MIME type patterns to regex
|
|
645
706
|
|
|
707
|
+
### ServerErrorHandler Methods
|
|
708
|
+
|
|
709
|
+
- `handleError(onErrorCallback, instanceName, instance, key, error, context)` - Static method for centralized error handling
|
|
710
|
+
- `onErrorCallback` - Custom error handler function (optional)
|
|
711
|
+
- `instanceName` - Name of the component ('http2CdnServer', 'appServerFactory', etc.)
|
|
712
|
+
- `instance` - Reference to the component instance
|
|
713
|
+
- `key` - Error type identifier
|
|
714
|
+
- `error` - The error object
|
|
715
|
+
- `context` - Additional context object (port, hostname, path, etc.)
|
|
716
|
+
|
|
646
717
|
## Security Features
|
|
647
718
|
|
|
648
719
|
### Path Traversal Protection
|
|
@@ -668,7 +739,15 @@ Industry-standard encryption using PBKDF2 for passwords, AES-256-GCM for data en
|
|
|
668
739
|
|
|
669
740
|
## Error Handling
|
|
670
741
|
|
|
671
|
-
All
|
|
742
|
+
All server components include comprehensive error handling with centralized error management through the ServerErrorHandler class. Custom error handlers can be configured via the `onError` callback to process errors according to application requirements. Errors are logged appropriately and never expose sensitive system information.
|
|
743
|
+
|
|
744
|
+
Error handling features:
|
|
745
|
+
- Centralized error management with ServerErrorHandler
|
|
746
|
+
- Custom error callback support across all components
|
|
747
|
+
- Structured error context with instance details and metadata
|
|
748
|
+
- Graceful HTTP status codes for proxy errors (502, 504, 500)
|
|
749
|
+
- TLS and session error handling for HTTP/2 servers
|
|
750
|
+
- Virtual host and SNI certificate error handling
|
|
672
751
|
|
|
673
752
|
---
|
|
674
753
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const cors = require('cors');
|
|
8
|
+
const { EventDispatcher } = require('../event-dispatcher');
|
|
8
9
|
|
|
9
10
|
class CorsConfigurer
|
|
10
11
|
{
|
|
@@ -18,6 +19,7 @@ class CorsConfigurer
|
|
|
18
19
|
this.corsHeaders = ['Content-Type','Authorization'];
|
|
19
20
|
this.developmentCorsOrigins = [];
|
|
20
21
|
this.developmentPorts = [];
|
|
22
|
+
this.onEvent = null;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
setup(app, config)
|
|
@@ -28,6 +30,7 @@ class CorsConfigurer
|
|
|
28
30
|
this.corsMethods = config.corsMethods || this.corsMethods;
|
|
29
31
|
this.corsHeaders = config.corsHeaders || this.corsHeaders;
|
|
30
32
|
this.developmentPorts = config.developmentPorts || this.developmentPorts;
|
|
33
|
+
this.onEvent = config.onEvent || null;
|
|
31
34
|
if(!this.useCors){
|
|
32
35
|
return;
|
|
33
36
|
}
|
|
@@ -58,6 +61,13 @@ class CorsConfigurer
|
|
|
58
61
|
};
|
|
59
62
|
}
|
|
60
63
|
app.use(cors(corsOptions));
|
|
64
|
+
EventDispatcher.dispatch(
|
|
65
|
+
this.onEvent,
|
|
66
|
+
'cors-configured',
|
|
67
|
+
'corsConfigurer',
|
|
68
|
+
this,
|
|
69
|
+
{useCors: this.useCors, isDevelopmentMode: this.isDevelopmentMode, corsOrigin: this.corsOrigin}
|
|
70
|
+
);
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
extractDevelopmentOrigins(domainMapping)
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const { EventDispatcher } = require('../event-dispatcher');
|
|
8
|
+
|
|
7
9
|
class DevelopmentModeDetector
|
|
8
10
|
{
|
|
9
11
|
|
|
@@ -27,10 +29,12 @@ class DevelopmentModeDetector
|
|
|
27
29
|
];
|
|
28
30
|
this.developmentEnvironments = ['development', 'dev', 'test'];
|
|
29
31
|
this.env = process?.env?.NODE_ENV || 'production';
|
|
32
|
+
this.onEvent = null;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
detect(config = {})
|
|
33
36
|
{
|
|
37
|
+
this.onEvent = config.onEvent || null;
|
|
34
38
|
if(config.developmentPatterns){
|
|
35
39
|
this.developmentPatterns = config.developmentPatterns;
|
|
36
40
|
}
|
|
@@ -38,11 +42,25 @@ class DevelopmentModeDetector
|
|
|
38
42
|
this.developmentEnvironments = config.developmentEnvironments;
|
|
39
43
|
}
|
|
40
44
|
if(this.developmentEnvironments.includes(this.env)){
|
|
45
|
+
EventDispatcher.dispatch(
|
|
46
|
+
this.onEvent,
|
|
47
|
+
'development-mode-detected',
|
|
48
|
+
'developmentModeDetector',
|
|
49
|
+
this,
|
|
50
|
+
{detectionMethod: 'environment', env: this.env}
|
|
51
|
+
);
|
|
41
52
|
return true;
|
|
42
53
|
}
|
|
43
54
|
if(config.developmentDomains && 0 < config.developmentDomains.length){
|
|
44
55
|
for(let domain of config.developmentDomains){
|
|
45
56
|
if(this.matchesPattern(domain)){
|
|
57
|
+
EventDispatcher.dispatch(
|
|
58
|
+
this.onEvent,
|
|
59
|
+
'development-mode-detected',
|
|
60
|
+
'developmentModeDetector',
|
|
61
|
+
this,
|
|
62
|
+
{detectionMethod: 'developmentDomain', domain: domain}
|
|
63
|
+
);
|
|
46
64
|
return true;
|
|
47
65
|
}
|
|
48
66
|
}
|
|
@@ -53,6 +71,13 @@ class DevelopmentModeDetector
|
|
|
53
71
|
continue;
|
|
54
72
|
}
|
|
55
73
|
if(this.matchesPattern(domainConfig.hostname)){
|
|
74
|
+
EventDispatcher.dispatch(
|
|
75
|
+
this.onEvent,
|
|
76
|
+
'development-mode-detected',
|
|
77
|
+
'developmentModeDetector',
|
|
78
|
+
this,
|
|
79
|
+
{detectionMethod: 'domainPattern', hostname: domainConfig.hostname}
|
|
80
|
+
);
|
|
56
81
|
return true;
|
|
57
82
|
}
|
|
58
83
|
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const { EventDispatcher } = require('../event-dispatcher');
|
|
8
|
+
|
|
7
9
|
class ProtocolEnforcer
|
|
8
10
|
{
|
|
9
11
|
|
|
@@ -12,6 +14,7 @@ class ProtocolEnforcer
|
|
|
12
14
|
this.isDevelopmentMode = false;
|
|
13
15
|
this.useHttps = false;
|
|
14
16
|
this.enforceProtocol = true;
|
|
17
|
+
this.onEvent = null;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
setup(app, config)
|
|
@@ -19,6 +22,7 @@ class ProtocolEnforcer
|
|
|
19
22
|
this.isDevelopmentMode = config.isDevelopmentMode || false;
|
|
20
23
|
this.useHttps = config.useHttps || false;
|
|
21
24
|
this.enforceProtocol = config.enforceProtocol !== false;
|
|
25
|
+
this.onEvent = config.onEvent || null;
|
|
22
26
|
app.use((req, res, next) => {
|
|
23
27
|
let forwardedProto = req.get('X-Forwarded-Proto');
|
|
24
28
|
let protocol = (forwardedProto || req.protocol || '').toLowerCase();
|
|
@@ -41,6 +45,13 @@ class ProtocolEnforcer
|
|
|
41
45
|
res.set('X-Forwarded-Proto', protocol);
|
|
42
46
|
next();
|
|
43
47
|
});
|
|
48
|
+
EventDispatcher.dispatch(
|
|
49
|
+
this.onEvent,
|
|
50
|
+
'protocol-enforcement-enabled',
|
|
51
|
+
'protocolEnforcer',
|
|
52
|
+
this,
|
|
53
|
+
{isDevelopmentMode: this.isDevelopmentMode, useHttps: this.useHttps, enforceProtocol: this.enforceProtocol}
|
|
54
|
+
);
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const rateLimit = require('express-rate-limit');
|
|
8
|
+
const { EventDispatcher } = require('../event-dispatcher');
|
|
8
9
|
|
|
9
10
|
class RateLimitConfigurer
|
|
10
11
|
{
|
|
@@ -19,6 +20,7 @@ class RateLimitConfigurer
|
|
|
19
20
|
this.applyKeyGenerator = false;
|
|
20
21
|
this.tooManyRequestsMessage = 'Too many requests, please try again later.';
|
|
21
22
|
this.rateLimit = rateLimit;
|
|
23
|
+
this.onEvent = null;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
setup(app, config)
|
|
@@ -30,6 +32,7 @@ class RateLimitConfigurer
|
|
|
30
32
|
this.developmentMultiplier = Number(config.developmentMultiplier || this.developmentMultiplier);
|
|
31
33
|
this.applyKeyGenerator = config.applyKeyGenerator || false;
|
|
32
34
|
this.tooManyRequestsMessage = config.tooManyRequestsMessage || this.tooManyRequestsMessage;
|
|
35
|
+
this.onEvent = config.onEvent || null;
|
|
33
36
|
if(!this.globalRateLimit){
|
|
34
37
|
return;
|
|
35
38
|
}
|
|
@@ -49,6 +52,13 @@ class RateLimitConfigurer
|
|
|
49
52
|
};
|
|
50
53
|
}
|
|
51
54
|
app.use(this.rateLimit(limiterParams));
|
|
55
|
+
EventDispatcher.dispatch(
|
|
56
|
+
this.onEvent,
|
|
57
|
+
'rate-limiting-configured',
|
|
58
|
+
'rateLimitConfigurer',
|
|
59
|
+
this,
|
|
60
|
+
{globalRateLimit: this.globalRateLimit, maxRequests: limiterParams.limit, windowMs: this.windowMs}
|
|
61
|
+
);
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
createHomeLimiter()
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
|
8
8
|
const { ServerHeaders } = require('../server-headers');
|
|
9
|
+
const { ServerErrorHandler } = require('../server-error-handler');
|
|
10
|
+
const { EventDispatcher } = require('../event-dispatcher');
|
|
9
11
|
|
|
10
12
|
class ReverseProxyConfigurer
|
|
11
13
|
{
|
|
@@ -22,6 +24,8 @@ class ReverseProxyConfigurer
|
|
|
22
24
|
logLevel: 'warn'
|
|
23
25
|
};
|
|
24
26
|
this.serverHeaders = new ServerHeaders();
|
|
27
|
+
this.onError = null;
|
|
28
|
+
this.onEvent = null;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
setup(app, config)
|
|
@@ -30,10 +34,19 @@ class ReverseProxyConfigurer
|
|
|
30
34
|
this.useVirtualHosts = config.useVirtualHosts || false;
|
|
31
35
|
this.reverseProxyRules = config.reverseProxyRules || [];
|
|
32
36
|
this.reverseProxyOptions = config.reverseProxyOptions || this.reverseProxyOptions;
|
|
37
|
+
this.onError = config.onError || null;
|
|
38
|
+
this.onEvent = config.onEvent || null;
|
|
33
39
|
if(0 === this.reverseProxyRules.length){
|
|
34
40
|
return;
|
|
35
41
|
}
|
|
36
42
|
this.applyRules(app);
|
|
43
|
+
EventDispatcher.dispatch(
|
|
44
|
+
this.onEvent,
|
|
45
|
+
'reverse-proxy-configured',
|
|
46
|
+
'reverseProxyConfigurer',
|
|
47
|
+
this,
|
|
48
|
+
{rulesCount: this.reverseProxyRules.length, useVirtualHosts: this.useVirtualHosts}
|
|
49
|
+
);
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
applyRules(app)
|
|
@@ -100,7 +113,9 @@ class ReverseProxyConfigurer
|
|
|
100
113
|
options.logLevel = rule.logLevel;
|
|
101
114
|
}
|
|
102
115
|
options.target = rule.target;
|
|
103
|
-
options.onError =
|
|
116
|
+
options.onError = (err, req, res) => {
|
|
117
|
+
this.handleProxyError(err, req, res);
|
|
118
|
+
};
|
|
104
119
|
options.onProxyReq = (proxyReq, req) => {
|
|
105
120
|
if(req.headers['x-forwarded-for']){
|
|
106
121
|
return;
|
|
@@ -115,6 +130,16 @@ class ReverseProxyConfigurer
|
|
|
115
130
|
|
|
116
131
|
handleProxyError(err, req, res)
|
|
117
132
|
{
|
|
133
|
+
let hostname = req.get('host') || 'unknown';
|
|
134
|
+
let requestPath = req.path || req.url || 'unknown';
|
|
135
|
+
ServerErrorHandler.handleError(
|
|
136
|
+
this.onError,
|
|
137
|
+
'reverseProxyConfigurer',
|
|
138
|
+
this,
|
|
139
|
+
'proxy-error',
|
|
140
|
+
err,
|
|
141
|
+
{request: req, response: res, hostname: hostname, path: requestPath}
|
|
142
|
+
);
|
|
118
143
|
if(res.headersSent){
|
|
119
144
|
return;
|
|
120
145
|
}
|