@reldens/server-utils 0.9.0 → 0.11.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/lib/app-server-factory.js +21 -7
- package/lib/uploader-factory.js +53 -23
- package/package.json +47 -47
|
@@ -47,7 +47,13 @@ class AppServerFactory
|
|
|
47
47
|
this.corsOrigin = String(process.env.RELDENS_CORS_ORIGIN || '*');
|
|
48
48
|
this.corsMethods = String(process.env.RELDENS_CORS_METHODS || 'GET,POST').split(',');
|
|
49
49
|
this.corsHeaders = String(process.env.RELDENS_CORS_HEADERS || 'Content-Type,Authorization').split(',');
|
|
50
|
-
this.
|
|
50
|
+
this.tooManyRequestsMessage = String(
|
|
51
|
+
process.env.RELDENS_TOO_MANY_REQUESTS_MESSAGE || 'Too many requests, please try again later.'
|
|
52
|
+
);
|
|
53
|
+
this.error = {};
|
|
54
|
+
this.processErrorResponse = function(status, message, req, res) {
|
|
55
|
+
return { status, message, handled: false };
|
|
56
|
+
};
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
createAppServer(appServerConfig)
|
|
@@ -72,7 +78,7 @@ class AppServerFactory
|
|
|
72
78
|
max: this.maxRequests,
|
|
73
79
|
standardHeaders: true,
|
|
74
80
|
legacyHeaders: false,
|
|
75
|
-
message:
|
|
81
|
+
message: this.tooManyRequestsMessage
|
|
76
82
|
};
|
|
77
83
|
if(this.applyKeyGenerator){
|
|
78
84
|
limiterParams.keyGenerator = function(req){
|
|
@@ -168,13 +174,21 @@ class AppServerFactory
|
|
|
168
174
|
app.get('/', async (req, res, next) => {
|
|
169
175
|
if('/' === req._parsedUrl.pathname){
|
|
170
176
|
if('function' !== typeof homePageLoadCallback){
|
|
171
|
-
|
|
177
|
+
let result = this.processErrorResponse(500, 'Homepage contents could not be loaded.', req, res);
|
|
178
|
+
if(result.handled){
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
return res.status(result.status).send(result.message);
|
|
172
182
|
}
|
|
173
183
|
try {
|
|
174
184
|
return res.send(await homePageLoadCallback(req));
|
|
175
185
|
} catch(error){
|
|
176
|
-
this.
|
|
177
|
-
|
|
186
|
+
this.error = {message: 'Error loading homepage.', error};
|
|
187
|
+
let result = this.processErrorResponse(500, 'Error loading homepage.', req, res);
|
|
188
|
+
if(result.handled){
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
return res.status(result.status).send(result.message);
|
|
178
192
|
}
|
|
179
193
|
}
|
|
180
194
|
next();
|
|
@@ -184,7 +198,7 @@ class AppServerFactory
|
|
|
184
198
|
async serveStatics(app, statics)
|
|
185
199
|
{
|
|
186
200
|
if(!FileHandler.isValidPath(statics)){
|
|
187
|
-
this.
|
|
201
|
+
this.error = {message: 'Invalid statics path.'};
|
|
188
202
|
return;
|
|
189
203
|
}
|
|
190
204
|
let staticOptions = {
|
|
@@ -202,7 +216,7 @@ class AppServerFactory
|
|
|
202
216
|
async serveStaticsPath(app, staticsPath, statics)
|
|
203
217
|
{
|
|
204
218
|
if(!FileHandler.isValidPath(staticsPath) || !FileHandler.isValidPath(statics)){
|
|
205
|
-
this.
|
|
219
|
+
this.error = {message: 'Invalid statics path to be served.'};
|
|
206
220
|
return;
|
|
207
221
|
}
|
|
208
222
|
let staticOptions = {
|
package/lib/uploader-factory.js
CHANGED
|
@@ -18,6 +18,9 @@ class UploaderFactory
|
|
|
18
18
|
this.fileLimit = props.fileLimit || 0;
|
|
19
19
|
this.allowedExtensions = props.allowedExtensions;
|
|
20
20
|
this.applySecureFileNames = props.applySecureFileNames;
|
|
21
|
+
this.processErrorResponse = props.processErrorResponse || function(status, message, req, res) {
|
|
22
|
+
return { status, message, handled: false };
|
|
23
|
+
};
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
createUploader(fields, buckets, allowedFileTypes)
|
|
@@ -35,16 +38,18 @@ class UploaderFactory
|
|
|
35
38
|
cb(null, dest);
|
|
36
39
|
}
|
|
37
40
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
41
|
+
diskStorageConfiguration['filename'] = (req, file, cb) => {
|
|
42
|
+
if(!this.applySecureFileNames) {
|
|
43
|
+
cb(null, file.originalname);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
let secureFilename = FileHandler.generateSecureFilename(file.originalname);
|
|
47
|
+
if(!req.fileNameMapping){
|
|
48
|
+
req.fileNameMapping = {};
|
|
49
|
+
}
|
|
50
|
+
req.fileNameMapping[secureFilename] = file.originalname;
|
|
51
|
+
cb(null, secureFilename);
|
|
52
|
+
};
|
|
48
53
|
let storage = multer.diskStorage(diskStorageConfiguration);
|
|
49
54
|
let limits = {
|
|
50
55
|
fileSize: this.maxFileSize
|
|
@@ -64,14 +69,30 @@ class UploaderFactory
|
|
|
64
69
|
if(err){
|
|
65
70
|
if(err instanceof multer.MulterError){
|
|
66
71
|
if(err.code === 'LIMIT_FILE_SIZE'){
|
|
67
|
-
|
|
72
|
+
let result = this.processErrorResponse(413, 'File too large.', req, res);
|
|
73
|
+
if(result.handled){
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
return res.status(result.status).send(result.message);
|
|
68
77
|
}
|
|
69
78
|
if(err.code === 'LIMIT_FILE_COUNT'){
|
|
70
|
-
|
|
79
|
+
let result = this.processErrorResponse(413, 'Too many files.', req, res);
|
|
80
|
+
if(result.handled){
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
return res.status(result.status).send(result.message);
|
|
84
|
+
}
|
|
85
|
+
let result = this.processErrorResponse(400, 'File upload error: ' + err.message, req, res);
|
|
86
|
+
if(result.handled){
|
|
87
|
+
return;
|
|
71
88
|
}
|
|
72
|
-
return res.status(
|
|
89
|
+
return res.status(result.status).send(result.message);
|
|
90
|
+
}
|
|
91
|
+
let result = this.processErrorResponse(500, 'Server error during file upload.', req, res);
|
|
92
|
+
if(result.handled){
|
|
93
|
+
return;
|
|
73
94
|
}
|
|
74
|
-
return res.status(
|
|
95
|
+
return res.status(result.status).send(result.message);
|
|
75
96
|
}
|
|
76
97
|
if(!req.files){
|
|
77
98
|
return next();
|
|
@@ -83,15 +104,23 @@ class UploaderFactory
|
|
|
83
104
|
if(FileHandler.exists(file.path)){
|
|
84
105
|
FileHandler.remove(file.path);
|
|
85
106
|
}
|
|
86
|
-
|
|
107
|
+
let result = this.processErrorResponse(415, 'File contents do not match declared type.', req, res);
|
|
108
|
+
if(result.handled){
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
return res.status(result.status).send(result.message);
|
|
87
112
|
}
|
|
88
113
|
}
|
|
89
114
|
}
|
|
90
115
|
next();
|
|
91
116
|
} catch(error){
|
|
92
|
-
|
|
117
|
+
this.error = {message: 'File validation error.', error};
|
|
93
118
|
this.cleanupFiles(req.files);
|
|
94
|
-
|
|
119
|
+
let result = this.processErrorResponse(500, 'Error processing uploaded files.', req, res);
|
|
120
|
+
if(result.handled){
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
return res.status(result.status).send(result.message);
|
|
95
124
|
}
|
|
96
125
|
});
|
|
97
126
|
};
|
|
@@ -116,11 +145,11 @@ class UploaderFactory
|
|
|
116
145
|
this.error = {message: 'Field name is invalid'};
|
|
117
146
|
return false;
|
|
118
147
|
}
|
|
119
|
-
if(!
|
|
148
|
+
if(!buckets[field.name]){
|
|
120
149
|
this.error = {message: `Missing bucket for field: ${field.name}`};
|
|
121
150
|
return false;
|
|
122
151
|
}
|
|
123
|
-
if(!
|
|
152
|
+
if(!allowedFileTypes[field.name]){
|
|
124
153
|
this.error = {message: `Missing allowedFileType for field: ${field.name}`};
|
|
125
154
|
return false;
|
|
126
155
|
}
|
|
@@ -156,11 +185,12 @@ class UploaderFactory
|
|
|
156
185
|
{
|
|
157
186
|
try {
|
|
158
187
|
if(!FileHandler.isFile(file.path)){
|
|
188
|
+
this.error = {message: 'File path must be provided.', file};
|
|
159
189
|
return false;
|
|
160
190
|
}
|
|
161
191
|
return FileHandler.validateFileType(file.path, allowedFileType, this.allowedExtensions, this.maxFileSize);
|
|
162
|
-
} catch(
|
|
163
|
-
|
|
192
|
+
} catch(error){
|
|
193
|
+
this.error = {message: 'Error validating file contents.', error};
|
|
164
194
|
return false;
|
|
165
195
|
}
|
|
166
196
|
}
|
|
@@ -187,8 +217,8 @@ class UploaderFactory
|
|
|
187
217
|
if(FileHandler.exists(file.path)){
|
|
188
218
|
FileHandler.remove(file.path);
|
|
189
219
|
}
|
|
190
|
-
} catch(
|
|
191
|
-
|
|
220
|
+
} catch(error){
|
|
221
|
+
this.error = {message: 'Error cleaning up file.', error};
|
|
192
222
|
}
|
|
193
223
|
}
|
|
194
224
|
}
|
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@reldens/server-utils",
|
|
3
|
-
"scope": "@reldens",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"description": "Reldens - Server Utils",
|
|
6
|
-
"author": "Damian A. Pastorini",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"homepage": "https://github.com/damian-pastorini/reldens-server-utils",
|
|
9
|
-
"source": true,
|
|
10
|
-
"main": "index.js",
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "https://github.com/damian-pastorini/reldens-server-utils.git"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"reldens",
|
|
17
|
-
"utils",
|
|
18
|
-
"shortcuts",
|
|
19
|
-
"system",
|
|
20
|
-
"game",
|
|
21
|
-
"mmorpg",
|
|
22
|
-
"rpg",
|
|
23
|
-
"dwd",
|
|
24
|
-
"colyseus",
|
|
25
|
-
"phaser",
|
|
26
|
-
"parcel",
|
|
27
|
-
"nodejs",
|
|
28
|
-
"mmo",
|
|
29
|
-
"multiplayer",
|
|
30
|
-
"rol",
|
|
31
|
-
"platform",
|
|
32
|
-
"framework"
|
|
33
|
-
],
|
|
34
|
-
"bugs": {
|
|
35
|
-
"url": "https://github.com/damian-pastorini/reldens-server-utils/issues"
|
|
36
|
-
},
|
|
37
|
-
"dependencies": {
|
|
38
|
-
"body-parser": "2.2.0",
|
|
39
|
-
"cors": "2.8.5",
|
|
40
|
-
"express": "4.21.2",
|
|
41
|
-
"express-rate-limit": "7.5.0",
|
|
42
|
-
"express-session": "1.18.1",
|
|
43
|
-
"helmet": "8.1.0",
|
|
44
|
-
"multer": "^1.4.5-lts.2",
|
|
45
|
-
"xss-clean": "
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@reldens/server-utils",
|
|
3
|
+
"scope": "@reldens",
|
|
4
|
+
"version": "0.11.0",
|
|
5
|
+
"description": "Reldens - Server Utils",
|
|
6
|
+
"author": "Damian A. Pastorini",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/damian-pastorini/reldens-server-utils",
|
|
9
|
+
"source": true,
|
|
10
|
+
"main": "index.js",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/damian-pastorini/reldens-server-utils.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"reldens",
|
|
17
|
+
"utils",
|
|
18
|
+
"shortcuts",
|
|
19
|
+
"system",
|
|
20
|
+
"game",
|
|
21
|
+
"mmorpg",
|
|
22
|
+
"rpg",
|
|
23
|
+
"dwd",
|
|
24
|
+
"colyseus",
|
|
25
|
+
"phaser",
|
|
26
|
+
"parcel",
|
|
27
|
+
"nodejs",
|
|
28
|
+
"mmo",
|
|
29
|
+
"multiplayer",
|
|
30
|
+
"rol",
|
|
31
|
+
"platform",
|
|
32
|
+
"framework"
|
|
33
|
+
],
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/damian-pastorini/reldens-server-utils/issues"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"body-parser": "2.2.0",
|
|
39
|
+
"cors": "2.8.5",
|
|
40
|
+
"express": "4.21.2",
|
|
41
|
+
"express-rate-limit": "7.5.0",
|
|
42
|
+
"express-session": "1.18.1",
|
|
43
|
+
"helmet": "8.1.0",
|
|
44
|
+
"multer": "^1.4.5-lts.2",
|
|
45
|
+
"xss-clean": "0.1.4"
|
|
46
|
+
}
|
|
47
|
+
}
|