@lenne.tech/nest-server 10.2.13 → 10.2.15
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/dist/config.env.js +24 -3
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/decorators/restricted.decorator.d.ts +1 -0
- package/dist/core/common/decorators/restricted.decorator.js +5 -2
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/interceptors/check-response.interceptor.d.ts +11 -0
- package/dist/core/common/interceptors/check-response.interceptor.js +22 -2
- package/dist/core/common/interceptors/check-response.interceptor.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +8 -1
- package/dist/core/common/models/core-persistence.model.js +12 -0
- package/dist/core/common/models/core-persistence.model.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/src/config.env.ts +24 -3
- package/src/core/common/decorators/restricted.decorator.ts +8 -2
- package/src/core/common/interceptors/check-response.interceptor.ts +18 -1
- package/src/core/common/interfaces/server-options.interface.ts +40 -2
- package/src/core/common/models/core-persistence.model.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "10.2.
|
|
3
|
+
"version": "10.2.15",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -63,18 +63,18 @@
|
|
|
63
63
|
"node": ">= 20"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@apollo/gateway": "2.
|
|
66
|
+
"@apollo/gateway": "2.7.1",
|
|
67
67
|
"@getbrevo/brevo": "1.0.1",
|
|
68
68
|
"@lenne.tech/mongoose-gridfs": "1.4.2",
|
|
69
69
|
"@lenne.tech/multer-gridfs-storage": "5.0.6",
|
|
70
70
|
"@nestjs/apollo": "12.0.11",
|
|
71
|
-
"@nestjs/common": "10.3.
|
|
72
|
-
"@nestjs/core": "10.3.
|
|
71
|
+
"@nestjs/common": "10.3.1",
|
|
72
|
+
"@nestjs/core": "10.3.1",
|
|
73
73
|
"@nestjs/graphql": "12.0.11",
|
|
74
74
|
"@nestjs/jwt": "10.2.0",
|
|
75
75
|
"@nestjs/mongoose": "10.0.2",
|
|
76
76
|
"@nestjs/passport": "10.0.3",
|
|
77
|
-
"@nestjs/platform-express": "10.3.
|
|
77
|
+
"@nestjs/platform-express": "10.3.1",
|
|
78
78
|
"@nestjs/schedule": "4.0.0",
|
|
79
79
|
"@nestjs/terminus": "10.2.0",
|
|
80
80
|
"apollo-server-core": "3.13.0",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"graphql-query-complexity": "0.12.0",
|
|
90
90
|
"graphql-subscriptions": "2.0.0",
|
|
91
91
|
"graphql-upload": "15.0.2",
|
|
92
|
-
"js-sha256": "0.
|
|
92
|
+
"js-sha256": "0.11.0",
|
|
93
93
|
"json-to-graphql-query": "2.2.5",
|
|
94
94
|
"light-my-request": "5.11.0",
|
|
95
95
|
"lodash": "4.17.21",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"passport": "0.7.0",
|
|
103
103
|
"passport-jwt": "4.0.1",
|
|
104
104
|
"reflect-metadata": "0.1.14",
|
|
105
|
-
"rfdc": "1.3.
|
|
105
|
+
"rfdc": "1.3.1",
|
|
106
106
|
"rimraf": "5.0.5",
|
|
107
107
|
"rxjs": "7.8.1",
|
|
108
108
|
"yuml-diagram": "1.2.0"
|
|
@@ -113,10 +113,10 @@
|
|
|
113
113
|
"@lenne.tech/eslint-config-ts": "0.0.16",
|
|
114
114
|
"@nestjs/cli": "10.3.0",
|
|
115
115
|
"@nestjs/schematics": "10.1.0",
|
|
116
|
-
"@nestjs/testing": "10.3.
|
|
117
|
-
"@swc/cli": "0.1.
|
|
118
|
-
"@swc/core": "1.3.
|
|
119
|
-
"@swc/jest": "0.2.
|
|
116
|
+
"@nestjs/testing": "10.3.1",
|
|
117
|
+
"@swc/cli": "0.1.65",
|
|
118
|
+
"@swc/core": "1.3.106",
|
|
119
|
+
"@swc/jest": "0.2.31",
|
|
120
120
|
"@types/compression": "1.7.5",
|
|
121
121
|
"@types/cookie-parser": "1.4.6",
|
|
122
122
|
"@types/ejs": "3.1.5",
|
|
@@ -124,12 +124,12 @@
|
|
|
124
124
|
"@types/jest": "29.5.11",
|
|
125
125
|
"@types/lodash": "4.14.202",
|
|
126
126
|
"@types/multer": "1.4.11",
|
|
127
|
-
"@types/node": "20.11.
|
|
127
|
+
"@types/node": "20.11.6",
|
|
128
128
|
"@types/nodemailer": "6.4.14",
|
|
129
129
|
"@types/passport": "1.0.16",
|
|
130
130
|
"@types/supertest": "6.0.2",
|
|
131
|
-
"@typescript-eslint/eslint-plugin": "6.19.
|
|
132
|
-
"@typescript-eslint/parser": "6.19.
|
|
131
|
+
"@typescript-eslint/eslint-plugin": "6.19.1",
|
|
132
|
+
"@typescript-eslint/parser": "6.19.1",
|
|
133
133
|
"coffeescript": "2.7.0",
|
|
134
134
|
"eslint": "8.56.0",
|
|
135
135
|
"eslint-config-prettier": "9.1.0",
|
|
@@ -143,11 +143,11 @@
|
|
|
143
143
|
"husky": "8.0.3",
|
|
144
144
|
"jest": "29.7.0",
|
|
145
145
|
"npm-watch": "0.11.0",
|
|
146
|
-
"pm2": "5.3.
|
|
146
|
+
"pm2": "5.3.1",
|
|
147
147
|
"prettier": "3.2.4",
|
|
148
148
|
"pretty-quick": "4.0.0",
|
|
149
149
|
"supertest": "6.3.4",
|
|
150
|
-
"ts-jest": "29.1.
|
|
150
|
+
"ts-jest": "29.1.2",
|
|
151
151
|
"ts-loader": "9.5.1",
|
|
152
152
|
"ts-morph": "20.0.0",
|
|
153
153
|
"ts-node": "10.9.2",
|
package/src/config.env.ts
CHANGED
|
@@ -89,7 +89,14 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
89
89
|
},
|
|
90
90
|
port: 3000,
|
|
91
91
|
security: {
|
|
92
|
-
checkResponseInterceptor:
|
|
92
|
+
checkResponseInterceptor: {
|
|
93
|
+
checkObjectItself: false,
|
|
94
|
+
debug: false,
|
|
95
|
+
ignoreUndefined: true,
|
|
96
|
+
mergeRoles: true,
|
|
97
|
+
removeUndefinedFromResultArray: true,
|
|
98
|
+
throwError: false,
|
|
99
|
+
},
|
|
93
100
|
checkSecurityInterceptor: true,
|
|
94
101
|
mapAndValidatePipe: true,
|
|
95
102
|
},
|
|
@@ -196,7 +203,14 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
196
203
|
},
|
|
197
204
|
port: 3000,
|
|
198
205
|
security: {
|
|
199
|
-
checkResponseInterceptor:
|
|
206
|
+
checkResponseInterceptor: {
|
|
207
|
+
checkObjectItself: false,
|
|
208
|
+
debug: false,
|
|
209
|
+
ignoreUndefined: true,
|
|
210
|
+
mergeRoles: true,
|
|
211
|
+
removeUndefinedFromResultArray: true,
|
|
212
|
+
throwError: false,
|
|
213
|
+
},
|
|
200
214
|
checkSecurityInterceptor: true,
|
|
201
215
|
mapAndValidatePipe: true,
|
|
202
216
|
},
|
|
@@ -292,7 +306,14 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
292
306
|
},
|
|
293
307
|
port: 3000,
|
|
294
308
|
security: {
|
|
295
|
-
checkResponseInterceptor:
|
|
309
|
+
checkResponseInterceptor: {
|
|
310
|
+
checkObjectItself: false,
|
|
311
|
+
debug: false,
|
|
312
|
+
ignoreUndefined: true,
|
|
313
|
+
mergeRoles: true,
|
|
314
|
+
removeUndefinedFromResultArray: true,
|
|
315
|
+
throwError: false,
|
|
316
|
+
},
|
|
296
317
|
checkSecurityInterceptor: true,
|
|
297
318
|
mapAndValidatePipe: true,
|
|
298
319
|
},
|
|
@@ -67,15 +67,20 @@ export const checkRestricted = (
|
|
|
67
67
|
dbObject?: any;
|
|
68
68
|
debug?: boolean;
|
|
69
69
|
ignoreUndefined?: boolean;
|
|
70
|
+
mergeRoles?: boolean;
|
|
70
71
|
processType?: ProcessType;
|
|
71
72
|
removeUndefinedFromResultArray?: boolean;
|
|
72
73
|
throwError?: boolean;
|
|
73
74
|
} = {},
|
|
74
75
|
processedObjects: any[] = [],
|
|
75
76
|
) => {
|
|
77
|
+
// Act like Roles handling: checkObjectItself = false & mergeRoles = true
|
|
78
|
+
// For Input: throwError = true
|
|
79
|
+
// For Output: throwError = false
|
|
76
80
|
const config = {
|
|
77
|
-
checkObjectItself:
|
|
81
|
+
checkObjectItself: false,
|
|
78
82
|
ignoreUndefined: true,
|
|
83
|
+
mergeRoles: true,
|
|
79
84
|
removeUndefinedFromResultArray: true,
|
|
80
85
|
throwError: true,
|
|
81
86
|
...options,
|
|
@@ -220,7 +225,8 @@ export const checkRestricted = (
|
|
|
220
225
|
|
|
221
226
|
// Check restricted
|
|
222
227
|
const restricted = getRestricted(data, propertyKey) || [];
|
|
223
|
-
const
|
|
228
|
+
const concatenatedRestrictions = config.mergeRoles ? _.uniq(objectRestrictions.concat(restricted)) : restricted;
|
|
229
|
+
const valid = validateRestricted(concatenatedRestrictions);
|
|
224
230
|
|
|
225
231
|
// Check rights
|
|
226
232
|
if (valid) {
|
|
@@ -4,12 +4,29 @@ import { map } from 'rxjs/operators';
|
|
|
4
4
|
|
|
5
5
|
import { checkRestricted } from '../decorators/restricted.decorator';
|
|
6
6
|
import { getContextData } from '../helpers/context.helper';
|
|
7
|
+
import { ConfigService } from '../services/config.service';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Interceptor to check the response data for current user
|
|
10
11
|
*/
|
|
11
12
|
@Injectable()
|
|
12
13
|
export class CheckResponseInterceptor implements NestInterceptor {
|
|
14
|
+
config = {
|
|
15
|
+
checkObjectItself: false,
|
|
16
|
+
debug: false,
|
|
17
|
+
ignoreUndefined: true,
|
|
18
|
+
mergeRoles: true,
|
|
19
|
+
removeUndefinedFromResultArray: true,
|
|
20
|
+
throwError: false,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
constructor(private readonly configService: ConfigService) {
|
|
24
|
+
const configuration = this.configService.getFastButReadOnly('security.checkResponseInterceptor');
|
|
25
|
+
if (typeof configuration === 'object') {
|
|
26
|
+
this.config = { ...this.config, ...configuration };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
/**
|
|
14
31
|
* Interception
|
|
15
32
|
*/
|
|
@@ -21,7 +38,7 @@ export class CheckResponseInterceptor implements NestInterceptor {
|
|
|
21
38
|
return next.handle().pipe(
|
|
22
39
|
map((data) => {
|
|
23
40
|
// Prepare response data for current user
|
|
24
|
-
return checkRestricted(data, currentUser,
|
|
41
|
+
return checkRestricted(data, currentUser, this.config);
|
|
25
42
|
}),
|
|
26
43
|
);
|
|
27
44
|
}
|
|
@@ -410,9 +410,47 @@ export interface IServerOptions {
|
|
|
410
410
|
/**
|
|
411
411
|
* Check restrictions for output (models and output objects)
|
|
412
412
|
* See @lenne.tech/nest-server/src/core/common/interceptors/check-response.interceptor.ts
|
|
413
|
-
* default = true
|
|
414
413
|
*/
|
|
415
|
-
checkResponseInterceptor?:
|
|
414
|
+
checkResponseInterceptor?:
|
|
415
|
+
| {
|
|
416
|
+
/**
|
|
417
|
+
* Check the object itself for restrictions
|
|
418
|
+
* (the class restriction is not only default for properties but object itself)
|
|
419
|
+
* default = false (to act like Roles)
|
|
420
|
+
*/
|
|
421
|
+
checkObjectItself?: boolean;
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Whether to log if a restricted field is found
|
|
425
|
+
* default = false
|
|
426
|
+
*/
|
|
427
|
+
debug?: boolean;
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Whether to ignore fields with undefined values
|
|
431
|
+
* default = true
|
|
432
|
+
*/
|
|
433
|
+
ignoreUndefined?: boolean;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Merge roles of object and properties
|
|
437
|
+
* default = true (to act like Roles)
|
|
438
|
+
*/
|
|
439
|
+
mergeRoles?: boolean;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Remove undefined values from result array
|
|
443
|
+
* default = true
|
|
444
|
+
*/
|
|
445
|
+
removeUndefinedFromResultArray?: boolean;
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Whether to throw an error if a restricted field is found
|
|
449
|
+
* default = false (for output objects)
|
|
450
|
+
*/
|
|
451
|
+
throwError?: boolean;
|
|
452
|
+
}
|
|
453
|
+
| boolean;
|
|
416
454
|
|
|
417
455
|
/**
|
|
418
456
|
* Process securityCheck() methode of Object before response
|
|
@@ -2,6 +2,8 @@ import { Field, ID, ObjectType } from '@nestjs/graphql';
|
|
|
2
2
|
import { Prop, Schema } from '@nestjs/mongoose';
|
|
3
3
|
import { Types } from 'mongoose';
|
|
4
4
|
|
|
5
|
+
import { Restricted } from '../decorators/restricted.decorator';
|
|
6
|
+
import { RoleEnum } from '../enums/role.enum';
|
|
5
7
|
import { CoreModel } from './core-model.model';
|
|
6
8
|
|
|
7
9
|
/**
|
|
@@ -26,6 +28,7 @@ export abstract class CorePersistenceModel extends CoreModel {
|
|
|
26
28
|
// Getter
|
|
27
29
|
// ===========================================================================
|
|
28
30
|
|
|
31
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
29
32
|
get _id() {
|
|
30
33
|
return new Types.ObjectId(this.id);
|
|
31
34
|
}
|
|
@@ -37,6 +40,7 @@ export abstract class CorePersistenceModel extends CoreModel {
|
|
|
37
40
|
/**
|
|
38
41
|
* ID of the persistence object as string
|
|
39
42
|
*/
|
|
43
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
40
44
|
@Field(type => ID, {
|
|
41
45
|
description: 'ID of the persistence object',
|
|
42
46
|
nullable: true,
|
|
@@ -46,6 +50,7 @@ export abstract class CorePersistenceModel extends CoreModel {
|
|
|
46
50
|
/**
|
|
47
51
|
* Created date, is set automatically by mongoose
|
|
48
52
|
*/
|
|
53
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
49
54
|
@Field({ description: 'Created date', nullable: true })
|
|
50
55
|
@Prop({ onCreate: () => new Date() })
|
|
51
56
|
createdAt: Date = undefined;
|
|
@@ -53,6 +58,7 @@ export abstract class CorePersistenceModel extends CoreModel {
|
|
|
53
58
|
/**
|
|
54
59
|
* Labels of the object
|
|
55
60
|
*/
|
|
61
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
56
62
|
@Field(type => [String], {
|
|
57
63
|
description: 'Labels of the object',
|
|
58
64
|
nullable: true,
|
|
@@ -63,6 +69,7 @@ export abstract class CorePersistenceModel extends CoreModel {
|
|
|
63
69
|
/**
|
|
64
70
|
* Tags for the object
|
|
65
71
|
*/
|
|
72
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
66
73
|
@Field(type => [String], {
|
|
67
74
|
description: 'Tags for the object',
|
|
68
75
|
nullable: true,
|
|
@@ -73,6 +80,7 @@ export abstract class CorePersistenceModel extends CoreModel {
|
|
|
73
80
|
/**
|
|
74
81
|
* Updated date is set automatically by mongoose
|
|
75
82
|
*/
|
|
83
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
76
84
|
@Field({ description: 'Updated date', nullable: true })
|
|
77
85
|
@Prop({ onUpdate: () => new Date() })
|
|
78
86
|
updatedAt: Date = undefined;
|