@reldens/server-utils 0.27.0 → 0.29.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 +36 -7
- package/lib/app-server-factory/cors-configurer.js +25 -10
- package/lib/app-server-factory/development-mode-detector.js +31 -5
- package/lib/app-server-factory/protocol-enforcer.js +4 -6
- package/lib/app-server-factory/rate-limit-configurer.js +5 -5
- package/lib/app-server-factory/security-configurer.js +23 -5
- package/lib/app-server-factory.js +40 -45
- package/package.json +1 -1
- package/app-server-factory-v2.patch +0 -29
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Reldens - Server Utils
|
|
2
2
|
|
|
3
|
-
A Node.js server toolkit providing secure application server creation, file handling, encryption, and file upload capabilities for production-ready applications.
|
|
3
|
+
A Node.js server toolkit providing secure application server creation, file handling, encryption, and file upload capabilities for production-ready applications with modular security configurations.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/damian-pastorini/reldens)
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
### AppServerFactory
|
|
10
|
-
- Complete Express.js server configuration with security
|
|
10
|
+
- Complete Express.js server configuration with modular security
|
|
11
11
|
- HTTPS/HTTP server creation with SSL certificate management
|
|
12
12
|
- SNI (Server Name Indication) support for multi-domain hosting
|
|
13
13
|
- Virtual host management with domain mapping
|
|
@@ -20,8 +20,18 @@ A Node.js server toolkit providing secure application server creation, file hand
|
|
|
20
20
|
- Trusted proxy configuration
|
|
21
21
|
- Request parsing with size limits and validation
|
|
22
22
|
- Static file serving with security headers
|
|
23
|
+
- Compression middleware with smart filtering
|
|
23
24
|
- Input validation utilities
|
|
24
25
|
|
|
26
|
+
#### Modular Security Components
|
|
27
|
+
The AppServerFactory now uses specialized security configurers:
|
|
28
|
+
|
|
29
|
+
- **CorsConfigurer** - Dynamic CORS origin validation with development domain support
|
|
30
|
+
- **DevelopmentModeDetector** - Automatic development environment detection
|
|
31
|
+
- **ProtocolEnforcer** - Protocol redirection with development mode awareness
|
|
32
|
+
- **RateLimitConfigurer** - Global and endpoint-specific rate limiting
|
|
33
|
+
- **SecurityConfigurer** - Helmet integration with CSP management and XSS protection
|
|
34
|
+
|
|
25
35
|
### FileHandler
|
|
26
36
|
- Secure file system operations with path validation
|
|
27
37
|
- File and folder creation, copying, and removal
|
|
@@ -34,6 +44,8 @@ A Node.js server toolkit providing secure application server creation, file hand
|
|
|
34
44
|
- Temporary file creation
|
|
35
45
|
- File quarantine functionality for security threats
|
|
36
46
|
- Binary file head reading for type detection
|
|
47
|
+
- Directory walking with callback processing
|
|
48
|
+
- File comparison and relative path calculations
|
|
37
49
|
- Comprehensive error handling with detailed context
|
|
38
50
|
|
|
39
51
|
### Encryptor
|
|
@@ -77,7 +89,8 @@ let appServerFactory = new AppServerFactory();
|
|
|
77
89
|
let serverResult = appServerFactory.createAppServer({
|
|
78
90
|
port: 3000,
|
|
79
91
|
useHttps: false,
|
|
80
|
-
autoListen: true
|
|
92
|
+
autoListen: true,
|
|
93
|
+
useCompression: true
|
|
81
94
|
});
|
|
82
95
|
|
|
83
96
|
if(serverResult){
|
|
@@ -183,7 +196,9 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
183
196
|
useVirtualHosts: true,
|
|
184
197
|
keyPath: '/ssl/default.key',
|
|
185
198
|
certPath: '/ssl/default.crt',
|
|
186
|
-
port: 443
|
|
199
|
+
port: 443,
|
|
200
|
+
enforceProtocol: true,
|
|
201
|
+
developmentMultiplier: 10
|
|
187
202
|
});
|
|
188
203
|
```
|
|
189
204
|
|
|
@@ -192,7 +207,7 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
192
207
|
```javascript
|
|
193
208
|
let appServerFactory = new AppServerFactory();
|
|
194
209
|
|
|
195
|
-
// Add development domains
|
|
210
|
+
// Add development domains (automatically detected)
|
|
196
211
|
appServerFactory.addDevelopmentDomain('localhost');
|
|
197
212
|
appServerFactory.addDevelopmentDomain('dev.myapp.local');
|
|
198
213
|
|
|
@@ -200,6 +215,11 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
200
215
|
port: 3000,
|
|
201
216
|
corsOrigin: ['http://localhost:3000', 'http://dev.myapp.local:3000'],
|
|
202
217
|
developmentMultiplier: 5, // More lenient rate limiting in dev
|
|
218
|
+
developmentPorts: [3000, 3001, 8080],
|
|
219
|
+
developmentExternalDomains: {
|
|
220
|
+
'script-src': ['https://cdn.example.com'],
|
|
221
|
+
'style-src': ['https://fonts.googleapis.com']
|
|
222
|
+
}
|
|
203
223
|
});
|
|
204
224
|
```
|
|
205
225
|
|
|
@@ -222,7 +242,9 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
222
242
|
globalRateLimit: 100, // requests per window
|
|
223
243
|
windowMs: 60000, // 1 minute
|
|
224
244
|
maxRequests: 30,
|
|
225
|
-
trustedProxy: '127.0.0.1'
|
|
245
|
+
trustedProxy: '127.0.0.1',
|
|
246
|
+
useXssProtection: true,
|
|
247
|
+
sanitizeOptions: {allowedTags: [], allowedAttributes: {}}
|
|
226
248
|
});
|
|
227
249
|
```
|
|
228
250
|
|
|
@@ -237,7 +259,6 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
237
259
|
- `enableServeHome(app, callback)` - Enables homepage serving
|
|
238
260
|
- `serveStatics(app, staticPath)` - Serves static files
|
|
239
261
|
- `serveStaticsPath(app, route, staticPath)` - Serves static files on specific route
|
|
240
|
-
- `validateInput(input, type)` - Validates input against predefined patterns
|
|
241
262
|
- `enableCSP(cspOptions)` - Enables Content Security Policy
|
|
242
263
|
- `listen(port)` - Starts server listening
|
|
243
264
|
- `close()` - Gracefully closes server
|
|
@@ -263,6 +284,13 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
263
284
|
- `generateSecureFilename(originalName)` - Generates cryptographically secure filename
|
|
264
285
|
- `quarantineFile(path, reason)` - Moves file to quarantine folder
|
|
265
286
|
- `createTempFile(prefix, extension)` - Creates a temporary file path
|
|
287
|
+
- `moveFile(from, to)` - Moves file to new location
|
|
288
|
+
- `getFileSize(path)` - Gets file size in bytes
|
|
289
|
+
- `compareFiles(file1, file2)` - Compares file contents
|
|
290
|
+
- `getRelativePath(from, to)` - Calculates relative path
|
|
291
|
+
- `walkDirectory(path, callback)` - Recursively processes directory tree
|
|
292
|
+
- `getDirectorySize(path)` - Calculates total directory size
|
|
293
|
+
- `emptyDirectory(path)` - Removes all contents from directory
|
|
266
294
|
|
|
267
295
|
### Encryptor Methods
|
|
268
296
|
|
|
@@ -284,6 +312,7 @@ let serverResult = appServerFactory.createAppServer({
|
|
|
284
312
|
- `validateFilenameSecurity(filename)` - Validates filename for security
|
|
285
313
|
- `validateFile(file, allowedType, callback)` - Validates a file during upload
|
|
286
314
|
- `validateFileContents(file, allowedType)` - Validates file content after upload
|
|
315
|
+
- `convertToRegex(key)` - Converts MIME type patterns to regex
|
|
287
316
|
|
|
288
317
|
## Security Features
|
|
289
318
|
|
|
@@ -17,7 +17,7 @@ class CorsConfigurer
|
|
|
17
17
|
this.corsMethods = ['GET','POST'];
|
|
18
18
|
this.corsHeaders = ['Content-Type','Authorization'];
|
|
19
19
|
this.developmentCorsOrigins = [];
|
|
20
|
-
this.developmentPorts = [
|
|
20
|
+
this.developmentPorts = [];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
setup(app, config)
|
|
@@ -40,12 +40,15 @@ class CorsConfigurer
|
|
|
40
40
|
allowedHeaders: this.corsHeaders,
|
|
41
41
|
credentials: true
|
|
42
42
|
};
|
|
43
|
+
if('*' === this.corsOrigin && true === corsOptions.credentials){
|
|
44
|
+
corsOptions.origin = true;
|
|
45
|
+
}
|
|
43
46
|
if(this.isDevelopmentMode && 0 < this.developmentCorsOrigins.length){
|
|
44
47
|
corsOptions.origin = (origin, callback) => {
|
|
45
48
|
if(!origin){
|
|
46
49
|
return callback(null, true);
|
|
47
50
|
}
|
|
48
|
-
if(-1 !== this.developmentCorsOrigins.indexOf(origin)){
|
|
51
|
+
if(-1 !== this.developmentCorsOrigins.indexOf(this.normalizeHost(origin))){
|
|
49
52
|
return callback(null, true);
|
|
50
53
|
}
|
|
51
54
|
if('*' === this.corsOrigin){
|
|
@@ -59,20 +62,32 @@ class CorsConfigurer
|
|
|
59
62
|
|
|
60
63
|
extractDevelopmentOrigins(domainMapping)
|
|
61
64
|
{
|
|
62
|
-
let
|
|
65
|
+
let originsSet = new Set();
|
|
63
66
|
let mappingKeys = Object.keys(domainMapping);
|
|
64
67
|
for(let domain of mappingKeys){
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
let normalizedDomain = this.normalizeHost(domain);
|
|
69
|
+
originsSet.add('http://'+normalizedDomain);
|
|
70
|
+
originsSet.add('https://'+normalizedDomain);
|
|
71
|
+
if(-1 !== normalizedDomain.indexOf(':')){
|
|
68
72
|
continue;
|
|
69
73
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
if(0 < this.developmentPorts.length){
|
|
75
|
+
for(let port of this.developmentPorts){
|
|
76
|
+
originsSet.add('http://'+normalizedDomain+':'+port);
|
|
77
|
+
originsSet.add('https://'+normalizedDomain+':'+port);
|
|
78
|
+
}
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
|
-
return
|
|
81
|
+
return Array.from(originsSet);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
normalizeHost(originOrHost)
|
|
85
|
+
{
|
|
86
|
+
let normalizedHost = (''+originOrHost).toLowerCase();
|
|
87
|
+
if('/' === normalizedHost.charAt(normalizedHost.length - 1)){
|
|
88
|
+
normalizedHost = normalizedHost.substring(0, normalizedHost.length - 1);
|
|
89
|
+
}
|
|
90
|
+
return normalizedHost;
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
}
|
|
@@ -26,6 +26,7 @@ class DevelopmentModeDetector
|
|
|
26
26
|
'staging.'
|
|
27
27
|
];
|
|
28
28
|
this.developmentEnvironments = ['development', 'dev', 'test'];
|
|
29
|
+
this.env = process?.env?.NODE_ENV || 'production';
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
detect(config = {})
|
|
@@ -36,8 +37,7 @@ class DevelopmentModeDetector
|
|
|
36
37
|
if(config.developmentEnvironments){
|
|
37
38
|
this.developmentEnvironments = config.developmentEnvironments;
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
-
if(this.developmentEnvironments.includes(env)){
|
|
40
|
+
if(this.developmentEnvironments.includes(this.env)){
|
|
41
41
|
return true;
|
|
42
42
|
}
|
|
43
43
|
if(config.developmentDomains && 0 < config.developmentDomains.length){
|
|
@@ -49,7 +49,7 @@ class DevelopmentModeDetector
|
|
|
49
49
|
}
|
|
50
50
|
if(config.domains && 0 < config.domains.length){
|
|
51
51
|
for(let domainConfig of config.domains){
|
|
52
|
-
if(!domainConfig
|
|
52
|
+
if(!domainConfig?.hostname){
|
|
53
53
|
continue;
|
|
54
54
|
}
|
|
55
55
|
if(this.matchesPattern(domainConfig.hostname)){
|
|
@@ -62,8 +62,34 @@ class DevelopmentModeDetector
|
|
|
62
62
|
|
|
63
63
|
matchesPattern(domain)
|
|
64
64
|
{
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
if(!domain){
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
let d = (''+domain).toLowerCase();
|
|
69
|
+
if('localhost' === d){
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if('127.0.0.1' === d){
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if('::1' === d){
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
for(let pattern of this.developmentPatterns || []){
|
|
79
|
+
if(!pattern){
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
let p = (''+pattern).toLowerCase();
|
|
83
|
+
if('.' === p.charAt(0) && d.endsWith(p)){
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
if('.' === p.charAt(p.length - 1) && 0 === d.indexOf(p)){
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if(d === p){
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
if(0 <= d.indexOf(p)){
|
|
67
93
|
return true;
|
|
68
94
|
}
|
|
69
95
|
}
|
|
@@ -20,8 +20,8 @@ class ProtocolEnforcer
|
|
|
20
20
|
this.useHttps = config.useHttps || false;
|
|
21
21
|
this.enforceProtocol = config.enforceProtocol !== false;
|
|
22
22
|
app.use((req, res, next) => {
|
|
23
|
-
let protocol = req.get('X-Forwarded-Proto') || req.protocol;
|
|
24
|
-
let host = req.get('host');
|
|
23
|
+
let protocol = (req.get('X-Forwarded-Proto') || req.protocol || '').toLowerCase();
|
|
24
|
+
let host = (req.get('host') || '').toLowerCase().trim();
|
|
25
25
|
if(this.isDevelopmentMode){
|
|
26
26
|
res.removeHeader('Origin-Agent-Cluster');
|
|
27
27
|
res.removeHeader('Strict-Transport-Security');
|
|
@@ -29,12 +29,10 @@ class ProtocolEnforcer
|
|
|
29
29
|
res.set('Origin-Agent-Cluster', '?0');
|
|
30
30
|
if(this.enforceProtocol && host){
|
|
31
31
|
if(!this.useHttps && 'https' === protocol){
|
|
32
|
-
|
|
33
|
-
return res.redirect(301, redirectUrl);
|
|
32
|
+
return res.redirect(301, 'http://'+host+req.url);
|
|
34
33
|
}
|
|
35
34
|
if(this.useHttps && 'http' === protocol){
|
|
36
|
-
|
|
37
|
-
return res.redirect(301, redirectUrl);
|
|
35
|
+
return res.redirect(301, 'https://'+host+req.url);
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
}
|
|
@@ -25,9 +25,9 @@ class RateLimitConfigurer
|
|
|
25
25
|
{
|
|
26
26
|
this.isDevelopmentMode = config.isDevelopmentMode || false;
|
|
27
27
|
this.globalRateLimit = config.globalRateLimit || 0;
|
|
28
|
-
this.windowMs = config.windowMs || this.windowMs;
|
|
29
|
-
this.maxRequests = config.maxRequests || this.maxRequests;
|
|
30
|
-
this.developmentMultiplier = config.developmentMultiplier || this.developmentMultiplier;
|
|
28
|
+
this.windowMs = Number(config.windowMs || this.windowMs);
|
|
29
|
+
this.maxRequests = Number(config.maxRequests || this.maxRequests);
|
|
30
|
+
this.developmentMultiplier = Number(config.developmentMultiplier || this.developmentMultiplier);
|
|
31
31
|
this.applyKeyGenerator = config.applyKeyGenerator || false;
|
|
32
32
|
this.tooManyRequestsMessage = config.tooManyRequestsMessage || this.tooManyRequestsMessage;
|
|
33
33
|
if(!this.globalRateLimit){
|
|
@@ -36,7 +36,7 @@ class RateLimitConfigurer
|
|
|
36
36
|
let limiterParams = {
|
|
37
37
|
windowMs: this.windowMs,
|
|
38
38
|
limit: this.maxRequests,
|
|
39
|
-
standardHeaders:
|
|
39
|
+
standardHeaders: 'draft-8',
|
|
40
40
|
legacyHeaders: false,
|
|
41
41
|
message: this.tooManyRequestsMessage
|
|
42
42
|
};
|
|
@@ -56,7 +56,7 @@ class RateLimitConfigurer
|
|
|
56
56
|
let limiterParams = {
|
|
57
57
|
windowMs: this.windowMs,
|
|
58
58
|
limit: this.maxRequests,
|
|
59
|
-
standardHeaders:
|
|
59
|
+
standardHeaders: 'draft-8',
|
|
60
60
|
legacyHeaders: false
|
|
61
61
|
};
|
|
62
62
|
if(this.isDevelopmentMode){
|
|
@@ -63,7 +63,10 @@ class SecurityConfigurer
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
if(config.developmentExternalDomains){
|
|
66
|
-
this.addExternalDomainsToCsp(
|
|
66
|
+
this.addExternalDomainsToCsp(
|
|
67
|
+
helmetOptions.contentSecurityPolicy.directives,
|
|
68
|
+
config.developmentExternalDomains
|
|
69
|
+
);
|
|
67
70
|
}
|
|
68
71
|
return helmetOptions;
|
|
69
72
|
}
|
|
@@ -99,7 +102,7 @@ class SecurityConfigurer
|
|
|
99
102
|
if(!req.body){
|
|
100
103
|
return next();
|
|
101
104
|
}
|
|
102
|
-
if('object' === typeof req.body){
|
|
105
|
+
if('object' === typeof req.body && null !== req.body){
|
|
103
106
|
this.sanitizeRequestBody(req.body);
|
|
104
107
|
}
|
|
105
108
|
next();
|
|
@@ -108,9 +111,24 @@ class SecurityConfigurer
|
|
|
108
111
|
|
|
109
112
|
sanitizeRequestBody(body)
|
|
110
113
|
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
if(Array.isArray(body)){
|
|
115
|
+
for(let i = 0; i < body.length; i++){
|
|
116
|
+
if('string' === typeof body[i]){
|
|
117
|
+
body[i] = sanitizeHtml(body[i], this.sanitizeOptions);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if('object' === typeof body[i] && null !== body[i]){
|
|
121
|
+
this.sanitizeRequestBody(body[i]);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if('object' !== typeof body || null === body){
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
let keys = Object.keys(body);
|
|
130
|
+
for(let i = 0; i < keys.length; i++){
|
|
131
|
+
let key = keys[i];
|
|
114
132
|
if('string' === typeof body[key]){
|
|
115
133
|
body[key] = sanitizeHtml(body[key], this.sanitizeOptions);
|
|
116
134
|
continue;
|
|
@@ -48,8 +48,8 @@ class AppServerFactory
|
|
|
48
48
|
this.useXssProtection = true;
|
|
49
49
|
this.globalRateLimit = 0;
|
|
50
50
|
this.corsOrigin = '*';
|
|
51
|
-
this.corsMethods = [
|
|
52
|
-
this.corsHeaders = [
|
|
51
|
+
this.corsMethods = [];
|
|
52
|
+
this.corsHeaders = [];
|
|
53
53
|
this.tooManyRequestsMessage = 'Too many requests, please try again later.';
|
|
54
54
|
this.error = {};
|
|
55
55
|
this.processErrorResponse = false;
|
|
@@ -74,16 +74,9 @@ class AppServerFactory
|
|
|
74
74
|
this.developmentDomains = [];
|
|
75
75
|
this.domainMapping = {};
|
|
76
76
|
this.enforceProtocol = true;
|
|
77
|
-
this.developmentPatterns = [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'.local',
|
|
81
|
-
'.test',
|
|
82
|
-
'.dev',
|
|
83
|
-
'.staging'
|
|
84
|
-
];
|
|
85
|
-
this.developmentEnvironments = ['development', 'dev', 'test'];
|
|
86
|
-
this.developmentPorts = [3000, 8080, 8081];
|
|
77
|
+
this.developmentPatterns = [];
|
|
78
|
+
this.developmentEnvironments = [];
|
|
79
|
+
this.developmentPorts = [];
|
|
87
80
|
this.developmentMultiplier = 10;
|
|
88
81
|
this.developmentExternalDomains = {};
|
|
89
82
|
this.developmentModeDetector = new DevelopmentModeDetector();
|
|
@@ -133,10 +126,10 @@ class AppServerFactory
|
|
|
133
126
|
|
|
134
127
|
extractDomainFromHttpUrl(url)
|
|
135
128
|
{
|
|
136
|
-
if(!url ||
|
|
129
|
+
if(!url || !url.startsWith('http://')){
|
|
137
130
|
return false;
|
|
138
131
|
}
|
|
139
|
-
return url.replace(/^
|
|
132
|
+
return url.replace(/^http:\/\//, '').split(':')[0];
|
|
140
133
|
}
|
|
141
134
|
|
|
142
135
|
addHttpDomainsAsDevelopment()
|
|
@@ -153,12 +146,17 @@ class AppServerFactory
|
|
|
153
146
|
|
|
154
147
|
detectDevelopmentMode()
|
|
155
148
|
{
|
|
156
|
-
|
|
157
|
-
developmentPatterns: this.developmentPatterns,
|
|
158
|
-
developmentEnvironments: this.developmentEnvironments,
|
|
149
|
+
let detectConfig = {
|
|
159
150
|
developmentDomains: this.developmentDomains,
|
|
160
151
|
domains: this.domains
|
|
161
|
-
}
|
|
152
|
+
};
|
|
153
|
+
if(0 < this.developmentPatterns.length){
|
|
154
|
+
detectConfig['developmentPatterns'] = this.developmentPatterns;
|
|
155
|
+
}
|
|
156
|
+
if(0 < this.developmentEnvironments.length){
|
|
157
|
+
detectConfig['developmentEnvironments'] = this.developmentEnvironments;
|
|
158
|
+
}
|
|
159
|
+
this.isDevelopmentMode = this.developmentModeDetector.detect(detectConfig);
|
|
162
160
|
}
|
|
163
161
|
|
|
164
162
|
setupDevelopmentConfiguration()
|
|
@@ -208,15 +206,28 @@ class AppServerFactory
|
|
|
208
206
|
|
|
209
207
|
setupCors()
|
|
210
208
|
{
|
|
211
|
-
|
|
209
|
+
let corsConfig = {
|
|
212
210
|
isDevelopmentMode: this.isDevelopmentMode,
|
|
213
211
|
useCors: this.useCors,
|
|
214
|
-
corsOrigin: this.corsOrigin
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
212
|
+
corsOrigin: this.corsOrigin
|
|
213
|
+
};
|
|
214
|
+
if(0 < this.corsMethods.length){
|
|
215
|
+
corsConfig['corsMethods'] = this.corsMethods;
|
|
216
|
+
}
|
|
217
|
+
if(0 < this.corsHeaders.length){
|
|
218
|
+
corsConfig['corsHeaders'] = this.corsHeaders;
|
|
219
|
+
}
|
|
220
|
+
if(0 < this.developmentPorts.length){
|
|
221
|
+
corsConfig['developmentPorts'] = this.developmentPorts;
|
|
222
|
+
}
|
|
223
|
+
if(
|
|
224
|
+
'object' === typeof this.domainMapping
|
|
225
|
+
&& null !== this.domainMapping
|
|
226
|
+
&& 0 < Object.keys(this.domainMapping)
|
|
227
|
+
){
|
|
228
|
+
corsConfig['domainMapping'] = this.domainMapping;
|
|
229
|
+
}
|
|
230
|
+
this.corsConfigurer.setup(this.app, corsConfig);
|
|
220
231
|
}
|
|
221
232
|
|
|
222
233
|
setupRateLimiting()
|
|
@@ -255,7 +266,7 @@ class AppServerFactory
|
|
|
255
266
|
setupTrustedProxy()
|
|
256
267
|
{
|
|
257
268
|
if('' !== this.trustedProxy){
|
|
258
|
-
this.app.
|
|
269
|
+
this.app.set('trust proxy', this.trustedProxy);
|
|
259
270
|
}
|
|
260
271
|
}
|
|
261
272
|
|
|
@@ -308,12 +319,13 @@ class AppServerFactory
|
|
|
308
319
|
return false;
|
|
309
320
|
}
|
|
310
321
|
let cleanHostname = hostname.toLowerCase().trim();
|
|
322
|
+
let hostWithoutPort = cleanHostname.split(':')[0];
|
|
311
323
|
for(let i = 0; i < this.domains.length; i++){
|
|
312
324
|
let domain = this.domains[i];
|
|
313
|
-
if(domain.hostname ===
|
|
325
|
+
if(domain.hostname === hostWithoutPort){
|
|
314
326
|
return domain;
|
|
315
327
|
}
|
|
316
|
-
if(domain.aliases && domain.aliases.includes(
|
|
328
|
+
if(domain.aliases && domain.aliases.includes(hostWithoutPort)){
|
|
317
329
|
return domain;
|
|
318
330
|
}
|
|
319
331
|
}
|
|
@@ -499,23 +511,6 @@ class AppServerFactory
|
|
|
499
511
|
return this.securityConfigurer.enableCSP(this.app, cspOptions);
|
|
500
512
|
}
|
|
501
513
|
|
|
502
|
-
validateInput(input, type)
|
|
503
|
-
{
|
|
504
|
-
if('string' !== typeof input){
|
|
505
|
-
return false;
|
|
506
|
-
}
|
|
507
|
-
let patterns = {
|
|
508
|
-
email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
|
509
|
-
username: /^[a-zA-Z0-9_-]{3,30}$/,
|
|
510
|
-
strongPassword: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
|
|
511
|
-
alphanumeric: /^[a-zA-Z0-9]+$/,
|
|
512
|
-
numeric: /^\d+$/,
|
|
513
|
-
hexColor: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
|
|
514
|
-
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
|
515
|
-
};
|
|
516
|
-
return patterns[type] ? patterns[type].test(input) : false;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
514
|
}
|
|
520
515
|
|
|
521
516
|
module.exports.AppServerFactory = AppServerFactory;
|
package/package.json
CHANGED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
--- a/lib/app-server-factory.js
|
|
2
|
-
+++ b/lib/app-server-factory.js
|
|
3
|
-
@@ -141,10 +141,14 @@ class AppServerFactory
|
|
4
|
-
|
|
5
|
-
addHttpDomainsAsDevelopment()
|
|
6
|
-
{
|
|
7
|
-
+ console.log('ENV VARS:', process.env.RELDENS_APP_HOST, process.env.RELDENS_PUBLIC_URL);
|
|
8
|
-
let hostDomain = this.extractDomainFromHttpUrl(process.env.RELDENS_APP_HOST);
|
|
9
|
-
let publicDomain = this.extractDomainFromHttpUrl(process.env.RELDENS_PUBLIC_URL);
|
|
10
|
-
+ console.log('EXTRACTED DOMAINS:', hostDomain, publicDomain);
|
|
11
|
-
if(hostDomain && !this.developmentDomains.includes(hostDomain)){
|
|
12
|
-
this.developmentDomains.push(hostDomain);
|
|
13
|
-
+ console.log('ADDED HOST DOMAIN:', hostDomain);
|
|
14
|
-
}
|
|
15
|
-
if(publicDomain && !this.developmentDomains.includes(publicDomain)){
|
|
16
|
-
this.developmentDomains.push(publicDomain);
|
|
17
|
-
+ console.log('ADDED PUBLIC DOMAIN:', publicDomain);
|
|
18
|
-
}
|
|
19
|
-
+ console.log('FINAL DEVELOPMENT DOMAINS:', this.developmentDomains);
|
|
20
|
-
}
|
|
21
|
-
@@ -154,6 +158,7 @@ class AppServerFactory
|
|
22
|
-
this.isDevelopmentMode = this.developmentModeDetector.detect({
|
|
23
|
-
developmentPatterns: this.developmentPatterns,
|
|
24
|
-
developmentEnvironments: this.developmentEnvironments,
|
|
25
|
-
developmentDomains: this.developmentDomains,
|
|
26
|
-
domains: this.domains
|
|
27
|
-
});
|
|
28
|
-
+ console.log('DEVELOPMENT MODE DETECTED:', this.isDevelopmentMode);
|
|
29
|
-
}
|