lesgo 0.7.7 → 1.0.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 +1 -1
- package/bin/lesgo-scripts.sh +52 -7
- package/package.json +2 -2
- package/src/middlewares/__tests__/basicAuthMiddleware.spec.js +264 -0
- package/src/middlewares/__tests__/clientAuthMiddleware.spec.js +235 -0
- package/src/middlewares/__tests__/errorHttpResponseMiddleware.spec.js +43 -0
- package/src/middlewares/__tests__/gzipHttpResponse.spec.js +1 -1
- package/src/middlewares/__tests__/httpNoOutputMiddleware.spec.js +201 -0
- package/src/middlewares/__tests__/normalizeSQSMessageMiddleware.spec.js +18 -0
- package/src/middlewares/__tests__/successHttpResponseMiddleware.spec.js +13 -0
- package/src/middlewares/__tests__/verifyJwtMiddleware.spec.js +187 -64
- package/src/middlewares/basicAuthMiddleware.js +125 -0
- package/src/middlewares/clientAuthMiddleware.js +103 -0
- package/src/middlewares/errorHttpResponseMiddleware.js +3 -1
- package/src/middlewares/httpNoOutputMiddleware.js +91 -0
- package/src/middlewares/index.js +4 -0
- package/src/middlewares/normalizeSQSMessageMiddleware.js +5 -3
- package/src/middlewares/successHttpResponseMiddleware.js +7 -5
- package/src/middlewares/verifyJwtMiddleware.js +23 -7
- package/src/services/LoggerService.js +10 -3
- package/src/services/__tests__/LoggerService.spec.js +17 -2
- package/src/utils/__tests__/validateFields.spec.js +223 -32
- package/src/utils/validateFields.js +85 -44
- package/CHANGELOG.md +0 -9
|
@@ -12,6 +12,13 @@ const params = {
|
|
|
12
12
|
status: 'active',
|
|
13
13
|
decimalCheck: 1.99,
|
|
14
14
|
totalRecord: 99,
|
|
15
|
+
functionCheck: () => {},
|
|
16
|
+
jsonCheck: JSON.stringify({
|
|
17
|
+
test: 'json value',
|
|
18
|
+
testArray: ['withvalues', 'here'],
|
|
19
|
+
testNum: 1,
|
|
20
|
+
}),
|
|
21
|
+
statusCollection: ['active', 'inactive', 'active'],
|
|
15
22
|
};
|
|
16
23
|
|
|
17
24
|
const validFields = [
|
|
@@ -26,8 +33,29 @@ const validFields = [
|
|
|
26
33
|
enumValues: ['active', 'inactive'],
|
|
27
34
|
required: true,
|
|
28
35
|
},
|
|
29
|
-
{
|
|
36
|
+
{
|
|
37
|
+
key: 'decimalCheck',
|
|
38
|
+
type: 'decimal',
|
|
39
|
+
required: true,
|
|
40
|
+
},
|
|
30
41
|
{ key: 'totalRecord', type: 'number', required: true },
|
|
42
|
+
{
|
|
43
|
+
key: 'functionCheck',
|
|
44
|
+
type: 'function',
|
|
45
|
+
required: true,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: 'jsonCheck',
|
|
49
|
+
type: 'json',
|
|
50
|
+
required: true,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: 'statusCollection',
|
|
54
|
+
type: 'enum',
|
|
55
|
+
enumValues: ['active', 'inactive'],
|
|
56
|
+
required: true,
|
|
57
|
+
isCollection: true,
|
|
58
|
+
},
|
|
31
59
|
];
|
|
32
60
|
|
|
33
61
|
describe('test Utils/validateFields', () => {
|
|
@@ -39,56 +67,92 @@ describe('test Utils/validateFields', () => {
|
|
|
39
67
|
const newParams = { ...params };
|
|
40
68
|
delete newParams.email;
|
|
41
69
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
70
|
+
try {
|
|
71
|
+
const validated = validateFields(newParams, validFields);
|
|
72
|
+
|
|
73
|
+
expect(validated).toThrow();
|
|
74
|
+
} catch (e) {
|
|
75
|
+
expect(e.name).toEqual('LesgoException');
|
|
76
|
+
expect(e.message).toEqual("Missing required 'email'");
|
|
77
|
+
expect(e.code).toEqual(`${FILE}::MISSING_REQUIRED_EMAIL`);
|
|
78
|
+
expect(e.extra).toStrictEqual({
|
|
79
|
+
field: validFields[2],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
48
82
|
});
|
|
49
83
|
|
|
50
84
|
it('should throw invalid type when non-string value check', () => {
|
|
51
85
|
const newParams = { ...params, name: 123 };
|
|
52
86
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
try {
|
|
88
|
+
const validated = validateFields(newParams, validFields);
|
|
89
|
+
|
|
90
|
+
expect(validated).toThrow();
|
|
91
|
+
} catch (e) {
|
|
92
|
+
expect(e.name).toEqual('LesgoException');
|
|
93
|
+
expect(e.message).toEqual(`Invalid type for 'name', expecting 'string'`);
|
|
94
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_NAME`);
|
|
95
|
+
expect(e.extra).toStrictEqual({
|
|
96
|
+
field: validFields[1],
|
|
97
|
+
value: 123,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
59
100
|
});
|
|
60
101
|
|
|
61
102
|
it('should throw invalid type when non-object value check', () => {
|
|
62
103
|
const newParams = { ...params, roles: 1597929335 };
|
|
63
104
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
105
|
+
try {
|
|
106
|
+
const validated = validateFields(newParams, validFields);
|
|
107
|
+
|
|
108
|
+
expect(validated).toThrow();
|
|
109
|
+
} catch (e) {
|
|
110
|
+
expect(e.name).toEqual('LesgoException');
|
|
111
|
+
expect(e.message).toEqual(`Invalid type for 'roles', expecting 'object'`);
|
|
112
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_ROLES`);
|
|
113
|
+
expect(e.extra).toStrictEqual({
|
|
114
|
+
field: validFields[3],
|
|
115
|
+
value: 1597929335,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
70
118
|
});
|
|
71
119
|
|
|
72
120
|
it('should throw invalid type when non-number value check', () => {
|
|
73
121
|
const newParams = { ...params, Id: '123' };
|
|
74
122
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
123
|
+
try {
|
|
124
|
+
const validated = validateFields(newParams, validFields);
|
|
125
|
+
|
|
126
|
+
expect(validated).toThrow();
|
|
127
|
+
} catch (e) {
|
|
128
|
+
expect(e.name).toEqual('LesgoException');
|
|
129
|
+
expect(e.message).toEqual(`Invalid type for 'Id', expecting 'number'`);
|
|
130
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_ID`);
|
|
131
|
+
expect(e.extra).toStrictEqual({
|
|
132
|
+
field: validFields[0],
|
|
133
|
+
value: '123',
|
|
134
|
+
});
|
|
135
|
+
}
|
|
81
136
|
});
|
|
82
137
|
|
|
83
138
|
it('should throw invalid type when non-array value check', () => {
|
|
84
139
|
const newParams = { ...params, listItem: { created_at: 1597929335 } };
|
|
85
140
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
141
|
+
try {
|
|
142
|
+
const validated = validateFields(newParams, validFields);
|
|
143
|
+
|
|
144
|
+
expect(validated).toThrow();
|
|
145
|
+
} catch (e) {
|
|
146
|
+
expect(e.name).toEqual('LesgoException');
|
|
147
|
+
expect(e.message).toEqual(
|
|
148
|
+
`Invalid type for 'listItem', expecting 'array'`
|
|
149
|
+
);
|
|
150
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_LISTITEM`);
|
|
151
|
+
expect(e.extra).toStrictEqual({
|
|
152
|
+
field: validFields[4],
|
|
153
|
+
value: { created_at: 1597929335 },
|
|
154
|
+
});
|
|
155
|
+
}
|
|
92
156
|
});
|
|
93
157
|
|
|
94
158
|
it('should throw required when array value is empty but required', () => {
|
|
@@ -119,9 +183,136 @@ describe('test Utils/validateFields', () => {
|
|
|
119
183
|
expect(() => validateFields(newParams, validFields)).toThrow(
|
|
120
184
|
new LesgoException(
|
|
121
185
|
`Invalid type for 'status', expecting 'enum'`,
|
|
122
|
-
|
|
186
|
+
`Invalid type for 'status', expecting 'enum'`
|
|
123
187
|
)
|
|
124
188
|
);
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
const validated = validateFields(newParams, validFields);
|
|
192
|
+
|
|
193
|
+
expect(validated).toThrow();
|
|
194
|
+
} catch (e) {
|
|
195
|
+
expect(e.name).toEqual('LesgoException');
|
|
196
|
+
expect(e.message).toEqual(`Invalid type for 'status', expecting 'enum'`);
|
|
197
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_STATUS`);
|
|
198
|
+
expect(e.extra).toStrictEqual({
|
|
199
|
+
field: validFields[5],
|
|
200
|
+
value: 'private',
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should throw invalid type when non-function value check', async () => {
|
|
206
|
+
const newParams = {
|
|
207
|
+
...params,
|
|
208
|
+
functionCheck: { not: 'function' },
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
const validated = validateFields(newParams, validFields);
|
|
213
|
+
|
|
214
|
+
expect(validated).toThrow();
|
|
215
|
+
} catch (e) {
|
|
216
|
+
expect(e.name).toEqual('LesgoException');
|
|
217
|
+
expect(e.message).toEqual(
|
|
218
|
+
`Invalid type for 'functionCheck', expecting 'function'`
|
|
219
|
+
);
|
|
220
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_FUNCTIONCHECK`);
|
|
221
|
+
expect(e.extra).toStrictEqual({
|
|
222
|
+
field: validFields[8],
|
|
223
|
+
value: { not: 'function' },
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it.each`
|
|
229
|
+
value
|
|
230
|
+
${'not a json'}
|
|
231
|
+
${3}
|
|
232
|
+
${'"invalid'}
|
|
233
|
+
${{ not: 'json' }}
|
|
234
|
+
${'{"missing":"bracket"}}'}
|
|
235
|
+
`(
|
|
236
|
+
'should throw invalid type when non-json $value check',
|
|
237
|
+
async ({ value }) => {
|
|
238
|
+
const newParams = {
|
|
239
|
+
...params,
|
|
240
|
+
jsonCheck: value,
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const validated = validateFields(newParams, validFields);
|
|
245
|
+
|
|
246
|
+
expect(validated).toThrow();
|
|
247
|
+
} catch (e) {
|
|
248
|
+
expect(e.name).toEqual('LesgoException');
|
|
249
|
+
expect(e.message).toEqual(
|
|
250
|
+
`Invalid type for 'jsonCheck', expecting 'json'`
|
|
251
|
+
);
|
|
252
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_JSONCHECK`);
|
|
253
|
+
expect(e.extra).toStrictEqual({
|
|
254
|
+
field: validFields[9],
|
|
255
|
+
value,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
it('should throw invalid type when non-collection value check', async () => {
|
|
262
|
+
const newParams = {
|
|
263
|
+
...params,
|
|
264
|
+
statusCollection: 'active',
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
const validated = validateFields(newParams, validFields);
|
|
269
|
+
|
|
270
|
+
expect(validated).toThrow();
|
|
271
|
+
} catch (e) {
|
|
272
|
+
expect(e.name).toEqual('LesgoException');
|
|
273
|
+
expect(e.message).toEqual(
|
|
274
|
+
`Invalid type for 'statusCollection', expecting collection of 'enum'`
|
|
275
|
+
);
|
|
276
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_STATUSCOLLECTION`);
|
|
277
|
+
expect(e.extra).toStrictEqual({
|
|
278
|
+
field: validFields[10],
|
|
279
|
+
value: 'active',
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should ignore type when collection value check is non-required', async () => {
|
|
285
|
+
const newParams = { ...params };
|
|
286
|
+
const newValidFields = [...validFields];
|
|
287
|
+
delete newParams.statusCollection;
|
|
288
|
+
newValidFields[10].required = false;
|
|
289
|
+
|
|
290
|
+
const validated = validateFields(newParams, newValidFields);
|
|
291
|
+
|
|
292
|
+
expect(validated).toStrictEqual(newParams);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should throw invalid type when non-enum collection value check', async () => {
|
|
296
|
+
const newParams = {
|
|
297
|
+
...params,
|
|
298
|
+
statusCollection: ['archive'],
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
const validated = validateFields(newParams, validFields);
|
|
303
|
+
|
|
304
|
+
expect(validated).toThrow();
|
|
305
|
+
} catch (e) {
|
|
306
|
+
expect(e.name).toEqual('LesgoException');
|
|
307
|
+
expect(e.message).toEqual(
|
|
308
|
+
`Invalid type for 'statusCollection', expecting collection of 'enum'`
|
|
309
|
+
);
|
|
310
|
+
expect(e.code).toEqual(`${FILE}::INVALID_TYPE_STATUSCOLLECTION`);
|
|
311
|
+
expect(e.extra).toStrictEqual({
|
|
312
|
+
field: validFields[10],
|
|
313
|
+
value: 'archive',
|
|
314
|
+
});
|
|
315
|
+
}
|
|
125
316
|
});
|
|
126
317
|
|
|
127
318
|
it('should return only valid and allowed fields when other fields are received', () => {
|
|
@@ -4,30 +4,44 @@ import isDecimal from './isDecimal';
|
|
|
4
4
|
|
|
5
5
|
const FILE = 'Utils/validateFields';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
const isValidJSON = json => {
|
|
8
|
+
if (typeof json !== 'string') {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Cannot find a regex solution to this
|
|
13
|
+
try {
|
|
14
|
+
JSON.parse(json);
|
|
15
|
+
|
|
16
|
+
return true;
|
|
17
|
+
} catch (_) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const validateFields = (params, validFields) => {
|
|
8
23
|
const validated = {};
|
|
9
24
|
|
|
10
25
|
validFields.forEach(field => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
) {
|
|
26
|
+
const { required, type, key, isCollection, enumValues = [] } = field;
|
|
27
|
+
|
|
28
|
+
if (required) {
|
|
29
|
+
if (typeof params[key] === 'object') {
|
|
30
|
+
if (Array.isArray(params[key]) && params[key].length === 0) {
|
|
17
31
|
throw new LesgoException(
|
|
18
|
-
`Missing required '${
|
|
19
|
-
`${FILE}::MISSING_REQUIRED_${
|
|
32
|
+
`Missing required '${key}'`,
|
|
33
|
+
`${FILE}::MISSING_REQUIRED_${key.toUpperCase()}`,
|
|
20
34
|
500,
|
|
21
35
|
{ field }
|
|
22
36
|
);
|
|
23
37
|
}
|
|
24
38
|
}
|
|
25
39
|
|
|
26
|
-
if (!params[
|
|
27
|
-
if (typeof params[
|
|
40
|
+
if (!params[key]) {
|
|
41
|
+
if (typeof params[key] !== 'number') {
|
|
28
42
|
throw new LesgoException(
|
|
29
|
-
`Missing required '${
|
|
30
|
-
`${FILE}::MISSING_REQUIRED_${
|
|
43
|
+
`Missing required '${key}'`,
|
|
44
|
+
`${FILE}::MISSING_REQUIRED_${key.toUpperCase()}`,
|
|
31
45
|
500,
|
|
32
46
|
{ field }
|
|
33
47
|
);
|
|
@@ -35,41 +49,68 @@ export default (params, validFields) => {
|
|
|
35
49
|
}
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
(field.type === 'email' &&
|
|
52
|
-
typeof params[field.key] !== 'undefined' &&
|
|
53
|
-
!isEmail(params[field.key])) ||
|
|
54
|
-
(field.type === 'array' &&
|
|
55
|
-
typeof params[field.key] !== 'undefined' &&
|
|
56
|
-
!Array.isArray(params[field.key])) ||
|
|
57
|
-
(field.type === 'enum' &&
|
|
58
|
-
typeof params[field.key] !== 'undefined' &&
|
|
59
|
-
!field.enumValues.includes(params[field.key]))
|
|
60
|
-
) {
|
|
61
|
-
throw new LesgoException(
|
|
62
|
-
`Invalid type for '${field.key}', expecting '${field.type}'`,
|
|
63
|
-
`${FILE}::INVALID_TYPE_${field.key.toUpperCase()}`,
|
|
64
|
-
500,
|
|
65
|
-
{ field, value: params[field.key] }
|
|
66
|
-
);
|
|
52
|
+
if (isCollection) {
|
|
53
|
+
try {
|
|
54
|
+
validateFields({ [key]: params[key] }, [
|
|
55
|
+
{ key, required, type: 'array' },
|
|
56
|
+
]);
|
|
57
|
+
} catch (_) {
|
|
58
|
+
throw new LesgoException(
|
|
59
|
+
`Invalid type for '${key}', expecting collection of '${type}'`,
|
|
60
|
+
`${FILE}::INVALID_TYPE_${key.toUpperCase()}`,
|
|
61
|
+
500,
|
|
62
|
+
{ field, value: params[key] }
|
|
63
|
+
);
|
|
64
|
+
}
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
(isCollection ? params[key] || [] : [params[key]]).forEach(paramsItem => {
|
|
68
|
+
if (
|
|
69
|
+
(type === 'string' &&
|
|
70
|
+
typeof paramsItem !== 'undefined' &&
|
|
71
|
+
typeof paramsItem !== 'string') ||
|
|
72
|
+
(type === 'object' &&
|
|
73
|
+
typeof paramsItem !== 'undefined' &&
|
|
74
|
+
typeof paramsItem !== 'object') ||
|
|
75
|
+
(type === 'number' &&
|
|
76
|
+
typeof paramsItem !== 'undefined' &&
|
|
77
|
+
typeof paramsItem !== 'number') ||
|
|
78
|
+
(type === 'decimal' &&
|
|
79
|
+
typeof paramsItem !== 'undefined' &&
|
|
80
|
+
!isDecimal(paramsItem)) ||
|
|
81
|
+
(type === 'email' &&
|
|
82
|
+
typeof paramsItem !== 'undefined' &&
|
|
83
|
+
!isEmail(paramsItem)) ||
|
|
84
|
+
(type === 'array' &&
|
|
85
|
+
typeof paramsItem !== 'undefined' &&
|
|
86
|
+
!Array.isArray(paramsItem)) ||
|
|
87
|
+
(type === 'enum' &&
|
|
88
|
+
typeof paramsItem !== 'undefined' &&
|
|
89
|
+
!enumValues.includes(paramsItem)) ||
|
|
90
|
+
(type === 'function' &&
|
|
91
|
+
typeof paramsItem !== 'undefined' &&
|
|
92
|
+
{}.toString.call(paramsItem) !== '[object Function]') ||
|
|
93
|
+
(type === 'json' &&
|
|
94
|
+
typeof paramsItem !== 'undefined' &&
|
|
95
|
+
!isValidJSON(paramsItem))
|
|
96
|
+
) {
|
|
97
|
+
throw new LesgoException(
|
|
98
|
+
`Invalid type for '${key}', expecting ${
|
|
99
|
+
isCollection ? 'collection of ' : ''
|
|
100
|
+
}'${type}'`,
|
|
101
|
+
`${FILE}::INVALID_TYPE_${key.toUpperCase()}`,
|
|
102
|
+
500,
|
|
103
|
+
{ field, value: paramsItem }
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (typeof params[key] !== 'undefined') {
|
|
109
|
+
validated[key] = params[key];
|
|
71
110
|
}
|
|
72
111
|
});
|
|
73
112
|
|
|
74
113
|
return validated;
|
|
75
114
|
};
|
|
115
|
+
|
|
116
|
+
export default validateFields;
|
package/CHANGELOG.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Changes as of November 11, 2019:
|
|
2
|
-
- Added DatabaseService
|
|
3
|
-
- where you could connect thru your own sql server (mysql, posgres and etc.)
|
|
4
|
-
- Added ElasticSearchService
|
|
5
|
-
- this service provides a connection that can connect thru local or AWS' ElasticSearch as of the moment.
|
|
6
|
-
- Added JwtService
|
|
7
|
-
- to validate jwt access token, and custom claims.
|
|
8
|
-
- Added ElastiCacheService
|
|
9
|
-
- a service that can use memcached/redis for in-memory key-value search.
|