@reldens/server-utils 0.33.0 → 0.34.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 +40 -0
- package/lib/app-server-factory.js +60 -9
- package/package.json +13 -11
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ A Node.js server toolkit providing secure application server creation, file hand
|
|
|
9
9
|
### AppServerFactory
|
|
10
10
|
- Complete Express.js server configuration with modular security
|
|
11
11
|
- HTTPS/HTTP server creation with SSL certificate management
|
|
12
|
+
- HTTP/2 support via spdy with automatic HTTP/1.1 fallback
|
|
13
|
+
- Optimized static asset caching for CSS, JS, fonts, and images
|
|
12
14
|
- SNI (Server Name Indication) support for multi-domain hosting
|
|
13
15
|
- Virtual host management with domain mapping
|
|
14
16
|
- Development mode detection with appropriate configurations
|
|
@@ -99,6 +101,40 @@ if(serverResult){
|
|
|
99
101
|
}
|
|
100
102
|
```
|
|
101
103
|
|
|
104
|
+
### HTTP/2 Server with Optimized Caching
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
let appServerFactory = new AppServerFactory();
|
|
108
|
+
let serverResult = appServerFactory.createAppServer({
|
|
109
|
+
port: 443,
|
|
110
|
+
useHttps: true,
|
|
111
|
+
useHttp2: true,
|
|
112
|
+
keyPath: '/ssl/server.key',
|
|
113
|
+
certPath: '/ssl/server.crt',
|
|
114
|
+
autoListen: true
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Cache configuration is automatic with defaults:
|
|
119
|
+
- CSS/JS: 1 year
|
|
120
|
+
- Fonts: 1 year
|
|
121
|
+
- Images: 30 days
|
|
122
|
+
|
|
123
|
+
Override cache settings if needed:
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
let appServerFactory = new AppServerFactory();
|
|
127
|
+
appServerFactory.cacheConfig = {
|
|
128
|
+
'.css': 86400,
|
|
129
|
+
'.js': 86400,
|
|
130
|
+
'.png': 604800
|
|
131
|
+
};
|
|
132
|
+
let serverResult = appServerFactory.createAppServer({
|
|
133
|
+
useHttps: true,
|
|
134
|
+
useHttp2: true
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
102
138
|
### File Operations
|
|
103
139
|
|
|
104
140
|
```javascript
|
|
@@ -193,6 +229,7 @@ appServerFactory.addDomain({
|
|
|
193
229
|
|
|
194
230
|
let serverResult = appServerFactory.createAppServer({
|
|
195
231
|
useHttps: true,
|
|
232
|
+
useHttp2: true,
|
|
196
233
|
useVirtualHosts: true,
|
|
197
234
|
keyPath: '/ssl/default.key',
|
|
198
235
|
certPath: '/ssl/default.crt',
|
|
@@ -328,6 +365,9 @@ Configurable rate limiting with development mode detection for appropriate thres
|
|
|
328
365
|
### HTTPS Support
|
|
329
366
|
Full SSL/TLS support with SNI for multi-domain hosting and automatic certificate management.
|
|
330
367
|
|
|
368
|
+
### HTTP/2 Support
|
|
369
|
+
HTTP/2 support via spdy with multiplexing for improved performance and automatic HTTP/1.1 fallback for older clients.
|
|
370
|
+
|
|
331
371
|
### Input Validation
|
|
332
372
|
Built-in validators for common input types including email, username, strong passwords, alphanumeric strings, and IP addresses.
|
|
333
373
|
|
|
@@ -12,6 +12,7 @@ const { CorsConfigurer } = require('./app-server-factory/cors-configurer');
|
|
|
12
12
|
const { RateLimitConfigurer } = require('./app-server-factory/rate-limit-configurer');
|
|
13
13
|
const http = require('http');
|
|
14
14
|
const https = require('https');
|
|
15
|
+
const spdy = require('spdy');
|
|
15
16
|
const express = require('express');
|
|
16
17
|
const bodyParser = require('body-parser');
|
|
17
18
|
const session = require('express-session');
|
|
@@ -34,6 +35,7 @@ class AppServerFactory
|
|
|
34
35
|
this.useUrlencoded = true;
|
|
35
36
|
this.encoding = 'utf-8';
|
|
36
37
|
this.useHttps = false;
|
|
38
|
+
this.useHttp2 = false;
|
|
37
39
|
this.passphrase = '';
|
|
38
40
|
this.httpsChain = '';
|
|
39
41
|
this.keyPath = '';
|
|
@@ -61,15 +63,28 @@ class AppServerFactory
|
|
|
61
63
|
this.defaultDomain = '';
|
|
62
64
|
this.maxRequestSize = '10mb';
|
|
63
65
|
this.sanitizeOptions = {allowedTags: [], allowedAttributes: {}};
|
|
66
|
+
this.cacheConfig = {
|
|
67
|
+
'.css': 31536000,
|
|
68
|
+
'.js': 31536000,
|
|
69
|
+
'.woff': 31536000,
|
|
70
|
+
'.woff2': 31536000,
|
|
71
|
+
'.ttf': 31536000,
|
|
72
|
+
'.eot': 31536000,
|
|
73
|
+
'.jpg': 2592000,
|
|
74
|
+
'.jpeg': 2592000,
|
|
75
|
+
'.png': 2592000,
|
|
76
|
+
'.gif': 2592000,
|
|
77
|
+
'.webp': 2592000,
|
|
78
|
+
'.svg': 2592000,
|
|
79
|
+
'.ico': 2592000
|
|
80
|
+
};
|
|
64
81
|
this.staticOptions = {
|
|
65
82
|
maxAge: '1d',
|
|
83
|
+
immutable: false,
|
|
66
84
|
etag: true,
|
|
67
85
|
lastModified: true,
|
|
68
86
|
index: false,
|
|
69
|
-
setHeaders:
|
|
70
|
-
res.set('X-Content-Type-Options', 'nosniff');
|
|
71
|
-
res.set('X-Frame-Options', 'DENY');
|
|
72
|
-
}
|
|
87
|
+
setHeaders: this.buildStaticHeaders.bind(this)
|
|
73
88
|
};
|
|
74
89
|
this.isDevelopmentMode = false;
|
|
75
90
|
this.developmentDomains = [];
|
|
@@ -98,6 +113,28 @@ class AppServerFactory
|
|
|
98
113
|
};
|
|
99
114
|
}
|
|
100
115
|
|
|
116
|
+
buildStaticHeaders(res, path)
|
|
117
|
+
{
|
|
118
|
+
res.set('X-Content-Type-Options', 'nosniff');
|
|
119
|
+
res.set('X-Frame-Options', 'DENY');
|
|
120
|
+
res.set('Vary', 'Accept-Encoding');
|
|
121
|
+
let cacheMaxAge = this.getCacheConfigForPath(path);
|
|
122
|
+
if(cacheMaxAge){
|
|
123
|
+
res.set('Cache-Control', 'public, max-age='+cacheMaxAge+', immutable');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getCacheConfigForPath(path)
|
|
128
|
+
{
|
|
129
|
+
let cacheKeys = Object.keys(this.cacheConfig);
|
|
130
|
+
for(let ext of cacheKeys){
|
|
131
|
+
if(path.endsWith(ext)){
|
|
132
|
+
return this.cacheConfig[ext];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
101
138
|
createAppServer(appServerConfig)
|
|
102
139
|
{
|
|
103
140
|
if(appServerConfig){
|
|
@@ -117,7 +154,7 @@ class AppServerFactory
|
|
|
117
154
|
try {
|
|
118
155
|
this.appServer = this.createServer();
|
|
119
156
|
} catch (error) {
|
|
120
|
-
this.error = {message: 'Server creation exception: '
|
|
157
|
+
this.error = {message: 'Server creation exception: '+error.message};
|
|
121
158
|
return false;
|
|
122
159
|
}
|
|
123
160
|
if(!this.appServer){
|
|
@@ -172,12 +209,14 @@ class AppServerFactory
|
|
|
172
209
|
if(!this.isDevelopmentMode){
|
|
173
210
|
return;
|
|
174
211
|
}
|
|
175
|
-
this.staticOptions.
|
|
212
|
+
this.staticOptions.immutable = false;
|
|
213
|
+
this.staticOptions.setHeaders = (res, path) => {
|
|
176
214
|
res.set('X-Content-Type-Options', 'nosniff');
|
|
177
215
|
res.set('X-Frame-Options', 'SAMEORIGIN');
|
|
178
216
|
res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
179
217
|
res.set('Pragma', 'no-cache');
|
|
180
218
|
res.set('Expires', '0');
|
|
219
|
+
res.set('Vary', 'Accept-Encoding');
|
|
181
220
|
};
|
|
182
221
|
}
|
|
183
222
|
|
|
@@ -313,7 +352,7 @@ class AppServerFactory
|
|
|
313
352
|
req.domain = this.defaultDomain;
|
|
314
353
|
return next();
|
|
315
354
|
}
|
|
316
|
-
this.error = {message: 'Unknown domain: '
|
|
355
|
+
this.error = {message: 'Unknown domain: '+hostname};
|
|
317
356
|
return res.status(404).send('Domain not found');
|
|
318
357
|
}
|
|
319
358
|
req.domain = domain;
|
|
@@ -343,6 +382,10 @@ class AppServerFactory
|
|
|
343
382
|
createServer()
|
|
344
383
|
{
|
|
345
384
|
if(!this.useHttps){
|
|
385
|
+
if(this.useHttp2){
|
|
386
|
+
this.error = {message: 'HTTP/2 requires HTTPS to be enabled'};
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
346
389
|
return http.createServer(this.app);
|
|
347
390
|
}
|
|
348
391
|
if(this.useVirtualHosts && 0 < this.domains.length){
|
|
@@ -355,12 +398,12 @@ class AppServerFactory
|
|
|
355
398
|
{
|
|
356
399
|
let key = FileHandler.readFile(this.keyPath, 'Key');
|
|
357
400
|
if(!key){
|
|
358
|
-
this.error = {message: 'Could not read SSL key file: '
|
|
401
|
+
this.error = {message: 'Could not read SSL key file: '+this.keyPath};
|
|
359
402
|
return false;
|
|
360
403
|
}
|
|
361
404
|
let cert = FileHandler.readFile(this.certPath, 'Cert');
|
|
362
405
|
if(!cert){
|
|
363
|
-
this.error = {message: 'Could not read SSL certificate file: '
|
|
406
|
+
this.error = {message: 'Could not read SSL certificate file: '+this.certPath};
|
|
364
407
|
return false;
|
|
365
408
|
}
|
|
366
409
|
let credentials = {key, cert, passphrase: this.passphrase};
|
|
@@ -370,6 +413,10 @@ class AppServerFactory
|
|
|
370
413
|
credentials.ca = ca;
|
|
371
414
|
}
|
|
372
415
|
}
|
|
416
|
+
if(this.useHttp2){
|
|
417
|
+
credentials.spdy = {protocols: ['h2', 'http/1.1']};
|
|
418
|
+
return spdy.createServer(credentials, this.app);
|
|
419
|
+
}
|
|
373
420
|
return https.createServer(credentials, this.app);
|
|
374
421
|
}
|
|
375
422
|
|
|
@@ -398,6 +445,10 @@ class AppServerFactory
|
|
|
398
445
|
let ctx = tls.createSecureContext({key, cert});
|
|
399
446
|
callback(null, ctx);
|
|
400
447
|
};
|
|
448
|
+
if(this.useHttp2){
|
|
449
|
+
httpsOptions.spdy = {protocols: ['h2', 'http/1.1']};
|
|
450
|
+
return spdy.createServer(httpsOptions, this.app);
|
|
451
|
+
}
|
|
401
452
|
return https.createServer(httpsOptions, this.app);
|
|
402
453
|
}
|
|
403
454
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reldens/server-utils",
|
|
3
3
|
"scope": "@reldens",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.34.0",
|
|
5
5
|
"description": "Reldens - Server Utils",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -17,17 +17,18 @@
|
|
|
17
17
|
"utils",
|
|
18
18
|
"shortcuts",
|
|
19
19
|
"system",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
20
|
+
"server",
|
|
21
|
+
"http",
|
|
22
|
+
"https",
|
|
23
23
|
"dwd",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
24
|
+
"http2",
|
|
25
|
+
"file",
|
|
26
|
+
"encrypt",
|
|
27
|
+
"uploader",
|
|
28
|
+
"upload",
|
|
29
|
+
"cors",
|
|
27
30
|
"nodejs",
|
|
28
|
-
"
|
|
29
|
-
"multiplayer",
|
|
30
|
-
"rol",
|
|
31
|
+
"protocol",
|
|
31
32
|
"platform",
|
|
32
33
|
"framework"
|
|
33
34
|
],
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"express-session": "1.18.2",
|
|
44
45
|
"helmet": "8.1.0",
|
|
45
46
|
"multer": "2.0.2",
|
|
46
|
-
"sanitize-html": "2.17.0"
|
|
47
|
+
"sanitize-html": "2.17.0",
|
|
48
|
+
"spdy": "^4.0.2"
|
|
47
49
|
}
|
|
48
50
|
}
|