@lenne.tech/nest-server 9.1.0 → 9.2.1

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.
Files changed (121) hide show
  1. package/dist/config.env.js +41 -2
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/filters/http-exception-log.filter.d.ts +4 -0
  4. package/dist/core/common/filters/http-exception-log.filter.js +30 -0
  5. package/dist/core/common/filters/http-exception-log.filter.js.map +1 -0
  6. package/dist/core/common/interceptors/check-security.interceptor.d.ts +5 -0
  7. package/dist/core/common/interceptors/check-security.interceptor.js +46 -0
  8. package/dist/core/common/interceptors/check-security.interceptor.js.map +1 -0
  9. package/dist/core/common/interfaces/server-options.interface.d.ts +16 -6
  10. package/dist/core/common/models/core-model.model.d.ts +1 -0
  11. package/dist/core/common/models/core-model.model.js +3 -0
  12. package/dist/core/common/models/core-model.model.js.map +1 -1
  13. package/dist/core/common/plugins/complexity.plugin.d.ts +9 -0
  14. package/dist/core/common/plugins/complexity.plugin.js +47 -0
  15. package/dist/core/common/plugins/complexity.plugin.js.map +1 -0
  16. package/dist/core/common/plugins/mongoose-id.plugin.d.ts +1 -2
  17. package/dist/core/common/plugins/mongoose-id.plugin.js +7 -2
  18. package/dist/core/common/plugins/mongoose-id.plugin.js.map +1 -1
  19. package/dist/core/common/services/config.service.d.ts +4 -4
  20. package/dist/core/common/services/config.service.js.map +1 -1
  21. package/dist/core/common/services/module.service.js +2 -2
  22. package/dist/core/common/services/module.service.js.map +1 -1
  23. package/dist/core/modules/auth/core-auth.model.d.ts +4 -1
  24. package/dist/core/modules/auth/core-auth.model.js +12 -1
  25. package/dist/core/modules/auth/core-auth.model.js.map +1 -1
  26. package/dist/core/modules/auth/core-auth.module.d.ts +3 -1
  27. package/dist/core/modules/auth/core-auth.module.js +7 -2
  28. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  29. package/dist/core/modules/auth/core-auth.resolver.d.ts +22 -2
  30. package/dist/core/modules/auth/core-auth.resolver.js +77 -9
  31. package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
  32. package/dist/core/modules/auth/guards/auth.guard.d.ts +1 -1
  33. package/dist/core/modules/auth/guards/auth.guard.js +9 -4
  34. package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
  35. package/dist/core/modules/auth/guards/refresh-token.guard.d.ts +4 -0
  36. package/dist/core/modules/auth/guards/refresh-token.guard.js +18 -0
  37. package/dist/core/modules/auth/guards/refresh-token.guard.js.map +1 -0
  38. package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
  39. package/dist/core/modules/auth/inputs/core-auth-sign-in.input.d.ts +1 -0
  40. package/dist/core/modules/auth/inputs/core-auth-sign-in.input.js +5 -0
  41. package/dist/core/modules/auth/inputs/core-auth-sign-in.input.js.map +1 -1
  42. package/dist/core/modules/auth/inputs/core-auth-sign-up.input.d.ts +1 -0
  43. package/dist/core/modules/auth/inputs/core-auth-sign-up.input.js +5 -0
  44. package/dist/core/modules/auth/inputs/core-auth-sign-up.input.js.map +1 -1
  45. package/dist/core/modules/auth/interfaces/core-auth-user.interface.d.ts +3 -0
  46. package/dist/core/modules/auth/interfaces/jwt-payload.interface.d.ts +1 -1
  47. package/dist/core/modules/auth/services/core-auth-user.service.d.ts +3 -0
  48. package/dist/core/modules/auth/services/core-auth-user.service.js.map +1 -1
  49. package/dist/core/modules/auth/services/core-auth.service.d.ts +23 -5
  50. package/dist/core/modules/auth/services/core-auth.service.js +121 -13
  51. package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
  52. package/dist/core/modules/auth/strategies/jwt-refresh.strategy.d.ts +12 -0
  53. package/dist/core/modules/auth/strategies/jwt-refresh.strategy.js +61 -0
  54. package/dist/core/modules/auth/strategies/jwt-refresh.strategy.js.map +1 -0
  55. package/dist/core/modules/auth/{jwt.strategy.d.ts → strategies/jwt.strategy.d.ts} +4 -3
  56. package/dist/core/modules/auth/{jwt.strategy.js → strategies/jwt.strategy.js} +12 -5
  57. package/dist/core/modules/auth/strategies/jwt.strategy.js.map +1 -0
  58. package/dist/core/modules/file/core-file.controller.d.ts +2 -2
  59. package/dist/core/modules/file/core-file.controller.js +2 -2
  60. package/dist/core/modules/file/core-file.controller.js.map +1 -1
  61. package/dist/core/modules/user/core-user.model.d.ts +2 -0
  62. package/dist/core/modules/user/core-user.model.js +12 -0
  63. package/dist/core/modules/user/core-user.model.js.map +1 -1
  64. package/dist/core.module.js +12 -2
  65. package/dist/core.module.js.map +1 -1
  66. package/dist/index.d.ts +6 -1
  67. package/dist/index.js +6 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/main.js +23 -0
  70. package/dist/main.js.map +1 -1
  71. package/dist/server/modules/auth/auth.model.js.map +1 -1
  72. package/dist/server/modules/auth/auth.resolver.d.ts +13 -5
  73. package/dist/server/modules/auth/auth.resolver.js +21 -12
  74. package/dist/server/modules/auth/auth.resolver.js.map +1 -1
  75. package/dist/server/modules/auth/auth.service.d.ts +2 -1
  76. package/dist/server/modules/auth/auth.service.js +7 -48
  77. package/dist/server/modules/auth/auth.service.js.map +1 -1
  78. package/dist/server/modules/file/file.module.js +3 -3
  79. package/dist/server/modules/file/file.module.js.map +1 -1
  80. package/dist/server/modules/user/user.model.d.ts +1 -0
  81. package/dist/server/modules/user/user.model.js +19 -0
  82. package/dist/server/modules/user/user.model.js.map +1 -1
  83. package/dist/server/server.module.js +12 -1
  84. package/dist/server/server.module.js.map +1 -1
  85. package/dist/tsconfig.build.tsbuildinfo +1 -1
  86. package/package.json +32 -27
  87. package/src/config.env.ts +41 -2
  88. package/src/core/common/filters/http-exception-log.filter.ts +27 -0
  89. package/src/core/common/interceptors/check-security.interceptor.ts +52 -0
  90. package/src/core/common/interfaces/server-options.interface.ts +67 -30
  91. package/src/core/common/models/core-model.model.ts +7 -0
  92. package/src/core/common/plugins/complexity.plugin.ts +31 -0
  93. package/src/core/common/plugins/mongoose-id.plugin.js +4 -2
  94. package/src/core/common/services/config.service.ts +4 -4
  95. package/src/core/common/services/module.service.ts +2 -2
  96. package/src/core/modules/auth/core-auth.model.ts +15 -2
  97. package/src/core/modules/auth/core-auth.module.ts +8 -2
  98. package/src/core/modules/auth/core-auth.resolver.ts +93 -10
  99. package/src/core/modules/auth/guards/auth.guard.ts +12 -5
  100. package/src/core/modules/auth/guards/refresh-token.guard.ts +5 -0
  101. package/src/core/modules/auth/guards/roles.guard.ts +1 -1
  102. package/src/core/modules/auth/inputs/core-auth-sign-in.input.ts +3 -0
  103. package/src/core/modules/auth/inputs/core-auth-sign-up.input.ts +3 -0
  104. package/src/core/modules/auth/interfaces/core-auth-user.interface.ts +15 -0
  105. package/src/core/modules/auth/interfaces/jwt-payload.interface.ts +1 -1
  106. package/src/core/modules/auth/services/core-auth-user.service.ts +15 -0
  107. package/src/core/modules/auth/services/core-auth.service.ts +216 -18
  108. package/src/core/modules/auth/strategies/jwt-refresh.strategy.ts +56 -0
  109. package/src/core/modules/auth/{jwt.strategy.ts → strategies/jwt.strategy.ts} +16 -5
  110. package/src/core/modules/file/core-file.controller.ts +2 -2
  111. package/src/core/modules/user/core-user.model.ts +17 -2
  112. package/src/core.module.ts +14 -2
  113. package/src/index.ts +6 -1
  114. package/src/main.ts +29 -0
  115. package/src/server/modules/auth/auth.model.ts +1 -1
  116. package/src/server/modules/auth/auth.resolver.ts +26 -8
  117. package/src/server/modules/auth/auth.service.ts +20 -61
  118. package/src/server/modules/file/file.module.ts +3 -3
  119. package/src/server/modules/user/user.model.ts +29 -0
  120. package/src/server/server.module.ts +12 -1
  121. package/dist/core/modules/auth/jwt.strategy.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "9.1.0",
3
+ "version": "9.2.1",
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",
@@ -60,78 +60,83 @@
60
60
  "node": ">= 16.13.0"
61
61
  },
62
62
  "dependencies": {
63
- "@apollo/gateway": "2.2.3",
64
- "@nestjs/apollo": "10.1.7",
65
- "@nestjs/common": "9.2.1",
66
- "@nestjs/core": "9.2.1",
67
- "@nestjs/graphql": "10.1.7",
68
- "@nestjs/jwt": "10.0.1",
63
+ "@apollo/gateway": "2.3.2",
64
+ "@nestjs/apollo": "10.2.0",
65
+ "@nestjs/common": "9.3.9",
66
+ "@nestjs/core": "9.3.9",
67
+ "@nestjs/graphql": "10.2.0",
68
+ "@nestjs/jwt": "10.0.2",
69
69
  "@nestjs/mongoose": "9.2.1",
70
- "@nestjs/passport": "9.0.0",
71
- "@nestjs/platform-express": "9.2.1",
72
- "@nestjs/schedule": "2.1.0",
70
+ "@nestjs/passport": "9.0.3",
71
+ "@nestjs/platform-express": "9.3.9",
72
+ "@nestjs/schedule": "2.2.0",
73
73
  "apollo-server-core": "3.11.1",
74
74
  "apollo-server-express": "3.11.1",
75
75
  "bcrypt": "5.1.0",
76
76
  "class-transformer": "0.5.1",
77
77
  "class-validator": "0.14.0",
78
+ "compression": "1.7.4",
79
+ "cookie-parser": "1.4.6",
78
80
  "ejs": "3.1.8",
79
81
  "graphql": "16.6.0",
82
+ "graphql-query-complexity": "0.12.0",
80
83
  "graphql-subscriptions": "2.0.0",
81
84
  "graphql-upload": "15.0.2",
82
85
  "js-sha256": "0.9.0",
83
- "json-to-graphql-query": "2.2.4",
86
+ "json-to-graphql-query": "2.2.5",
84
87
  "light-my-request": "5.8.0",
85
88
  "lodash": "4.17.21",
86
- "mongodb": "4.13.0",
87
- "mongoose": "6.8.4",
89
+ "mongodb": "4.14.0",
90
+ "mongoose": "6.9.1",
88
91
  "mongoose-gridfs": "1.3.0",
89
- "multer-gridfs-storage": "5.0.2",
90
92
  "multer": "1.4.5-lts.1",
91
- "node-mailjet": "6.0.1",
92
- "nodemailer": "6.9.0",
93
+ "multer-gridfs-storage": "5.0.2",
94
+ "node-mailjet": "6.0.2",
95
+ "nodemailer": "6.9.1",
93
96
  "nodemon": "2.0.20",
94
97
  "passport": "0.6.0",
95
98
  "passport-jwt": "4.0.1",
96
99
  "reflect-metadata": "0.1.13",
97
100
  "rfdc": "1.3.0",
98
- "rimraf": "4.1.1",
101
+ "rimraf": "4.1.2",
99
102
  "rxjs": "7.8.0"
100
103
  },
101
104
  "devDependencies": {
102
- "@nestjs/testing": "9.2.1",
105
+ "@nestjs/testing": "9.3.9",
106
+ "@types/compression": "1.7.2",
107
+ "@types/cookie-parser": "1.4.3",
103
108
  "@types/cron": "2.0.0",
104
109
  "@types/ejs": "3.1.1",
105
- "@types/jest": "29.2.6",
110
+ "@types/jest": "29.4.0",
106
111
  "@types/lodash": "4.14.191",
107
112
  "@types/multer": "1.4.7",
108
- "@types/node": "18.11.18",
113
+ "@types/node": "18.13.0",
109
114
  "@types/nodemailer": "6.4.7",
110
115
  "@types/passport": "1.0.11",
111
116
  "@types/supertest": "2.0.12",
112
- "@typescript-eslint/eslint-plugin": "5.48.2",
113
- "@typescript-eslint/parser": "5.48.2",
117
+ "@typescript-eslint/eslint-plugin": "5.52.0",
118
+ "@typescript-eslint/parser": "5.52.0",
114
119
  "coffeescript": "2.7.0",
115
- "eslint": "8.32.0",
120
+ "eslint": "8.34.0",
116
121
  "eslint-config-prettier": "8.6.0",
117
122
  "find-file-up": "2.0.1",
118
- "grunt": "1.5.3",
123
+ "grunt": "1.6.1",
119
124
  "grunt-bg-shell": "2.3.3",
120
125
  "grunt-contrib-clean": "2.0.1",
121
126
  "grunt-contrib-watch": "1.1.0",
122
127
  "grunt-sync": "0.8.2",
123
128
  "husky": "8.0.3",
124
- "jest": "29.3.1",
129
+ "jest": "29.4.2",
125
130
  "npm-watch": "0.11.0",
126
131
  "pm2": "5.2.2",
127
- "prettier": "2.8.3",
132
+ "prettier": "2.8.4",
128
133
  "pretty-quick": "3.1.3",
129
134
  "supertest": "6.3.3",
130
135
  "ts-jest": "29.0.5",
131
136
  "ts-morph": "17.0.1",
132
137
  "ts-node": "10.9.1",
133
138
  "tsconfig-paths": "4.1.2",
134
- "typescript": "4.9.4",
139
+ "typescript": "4.9.5",
135
140
  "yalc": "1.0.0-pre.53"
136
141
  },
137
142
  "overrides": {
package/src/config.env.ts CHANGED
@@ -12,6 +12,8 @@ const config: { [env: string]: IServerOptions } = {
12
12
  // ===========================================================================
13
13
  local: {
14
14
  automaticObjectIdFiltering: true,
15
+ compression: true,
16
+ cookies: false,
15
17
  cronJobs: {
16
18
  sayHello: {
17
19
  cronTime: CronExpression.EVERY_10_SECONDS,
@@ -52,16 +54,27 @@ const config: { [env: string]: IServerOptions } = {
52
54
  debug: true,
53
55
  introspection: true,
54
56
  },
57
+ maxComplexity: 20,
55
58
  },
56
59
  jwt: {
57
- secret: 'SECRET_OR_PRIVATE_KEY_DEV',
60
+ secret: 'SECRET_OR_PRIVATE_KEY_LOCAL',
61
+ signInOptions: {
62
+ expiresIn: '15m',
63
+ },
64
+ refresh: {
65
+ secret: 'SECRET_OR_PRIVATE_KEY_LOCAL_REFRESH',
66
+ signInOptions: {
67
+ expiresIn: '7d',
68
+ },
69
+ },
58
70
  },
59
71
  loadLocalConfig: false,
72
+ logExceptions: true,
60
73
  mongoose: {
61
74
  collation: {
62
75
  locale: 'de',
63
76
  },
64
- uri: 'mongodb://127.0.0.1/nest-server-dev',
77
+ uri: 'mongodb://127.0.0.1/nest-server-local',
65
78
  },
66
79
  port: 3000,
67
80
  sha256: true,
@@ -80,6 +93,8 @@ const config: { [env: string]: IServerOptions } = {
80
93
  // ===========================================================================
81
94
  development: {
82
95
  automaticObjectIdFiltering: true,
96
+ compression: true,
97
+ cookies: false,
83
98
  email: {
84
99
  smtp: {
85
100
  auth: {
@@ -111,11 +126,22 @@ const config: { [env: string]: IServerOptions } = {
111
126
  debug: true,
112
127
  introspection: true,
113
128
  },
129
+ maxComplexity: 20,
114
130
  },
115
131
  jwt: {
116
132
  secret: 'SECRET_OR_PRIVATE_KEY_DEV',
133
+ signInOptions: {
134
+ expiresIn: '15m',
135
+ },
136
+ refresh: {
137
+ secret: 'SECRET_OR_PRIVATE_KEY_DEV_REFRESH',
138
+ signInOptions: {
139
+ expiresIn: '7d',
140
+ },
141
+ },
117
142
  },
118
143
  loadLocalConfig: false,
144
+ logExceptions: true,
119
145
  mongoose: {
120
146
  collation: {
121
147
  locale: 'de',
@@ -139,6 +165,8 @@ const config: { [env: string]: IServerOptions } = {
139
165
  // ===========================================================================
140
166
  production: {
141
167
  automaticObjectIdFiltering: true,
168
+ compression: true,
169
+ cookies: false,
142
170
  email: {
143
171
  smtp: {
144
172
  auth: {
@@ -170,11 +198,22 @@ const config: { [env: string]: IServerOptions } = {
170
198
  debug: false,
171
199
  introspection: true,
172
200
  },
201
+ maxComplexity: 20,
173
202
  },
174
203
  jwt: {
175
204
  secret: 'SECRET_OR_PRIVATE_KEY_PROD',
205
+ signInOptions: {
206
+ expiresIn: '15m',
207
+ },
208
+ refresh: {
209
+ secret: 'SECRET_OR_PRIVATE_KEY_PROD_REFRESH',
210
+ signInOptions: {
211
+ expiresIn: '7d',
212
+ },
213
+ },
176
214
  },
177
215
  loadLocalConfig: false,
216
+ logExceptions: true,
178
217
  mongoose: {
179
218
  collation: {
180
219
  locale: 'de',
@@ -0,0 +1,27 @@
1
+ import { ArgumentsHost, Catch, ContextType, ExceptionFilter, HttpException } from '@nestjs/common';
2
+ import { Response } from 'express';
3
+
4
+ @Catch(HttpException)
5
+ export class HttpExceptionLogFilter implements ExceptionFilter {
6
+ /**
7
+ * Log exception
8
+ */
9
+ catch(exception: HttpException, host: ArgumentsHost) {
10
+ // Log
11
+ console.debug(exception.stack);
12
+
13
+ // GraphQL
14
+ const type = host.getType() as ContextType | 'graphql';
15
+ if (type === 'graphql') {
16
+ return exception;
17
+ }
18
+
19
+ // REST
20
+ const ctx = host.switchToHttp();
21
+ const res = ctx.getResponse<Response>();
22
+ const status = exception.getStatus();
23
+ res.status(status).json({
24
+ ...exception,
25
+ });
26
+ }
27
+ }
@@ -0,0 +1,52 @@
1
+ import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
2
+ import { Observable } from 'rxjs';
3
+ import { map } from 'rxjs/operators';
4
+ import { getContextData } from '../helpers/context.helper';
5
+ import { processDeep } from '../helpers/input.helper';
6
+
7
+ /**
8
+ * Verification of all outgoing data via securityCheck
9
+ */
10
+ @Injectable()
11
+ export class CheckSecurityInterceptor implements NestInterceptor {
12
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
13
+ // Get current user
14
+ const user = getContextData(context)?.currentUser;
15
+
16
+ // Set force mode for sign in and sign up
17
+ let force = false;
18
+ if (!user) {
19
+ // Here the name is used and not the class itself, because the concrete class is located in the respective project.
20
+ // In case of an override it is better to use the concrete class directly (context.getClass() instead of context.getClasss()?.name).
21
+ if (context.getClass()?.name === 'AuthResolver') {
22
+ force = true;
23
+ }
24
+ }
25
+
26
+ // Check response
27
+ return next.handle().pipe(
28
+ map((data) => {
29
+ // Check data
30
+ if (data && typeof data === 'object' && typeof data.securityCheck === 'function') {
31
+ return data.securityCheck(user, force);
32
+ }
33
+
34
+ // Check if data is writeable (e.g. objects from direct access to json files via http are not writable)
35
+ if (data && typeof data === 'object') {
36
+ const writeable = !Object.keys(data).find((key) => !Object.getOwnPropertyDescriptor(data, key).writable);
37
+ if (!writeable) {
38
+ return data;
39
+ }
40
+ }
41
+
42
+ // Check deep
43
+ return processDeep(data, (item) => {
44
+ if (!item || typeof item !== 'object' || typeof item.securityCheck !== 'function') {
45
+ return item;
46
+ }
47
+ return item.securityCheck(user, force);
48
+ });
49
+ })
50
+ );
51
+ }
52
+ }
@@ -1,15 +1,57 @@
1
1
  import { ApolloDriverConfig } from '@nestjs/apollo';
2
2
  import { GqlModuleAsyncOptions } from '@nestjs/graphql';
3
3
  import { JwtModuleOptions } from '@nestjs/jwt';
4
+ import { JwtSignOptions } from '@nestjs/jwt/dist/interfaces';
4
5
  import { MongooseModuleOptions } from '@nestjs/mongoose';
5
6
  import { ServeStaticOptions } from '@nestjs/platform-express/interfaces/serve-static-options.interface';
6
7
  import { CronExpression } from '@nestjs/schedule';
8
+ import compression from 'compression';
7
9
  import { CollationOptions } from 'mongodb';
8
10
  import * as SMTPTransport from 'nodemailer/lib/smtp-transport';
9
11
  import { Falsy } from '../types/falsy.type';
10
12
  import { CronJobConfig } from './cron-job-config.interface';
11
13
  import { MailjetOptions } from './mailjet-options.interface';
12
14
 
15
+ /**
16
+ * Interface for JWT configuration (main and refresh)
17
+ */
18
+ export interface IJwt {
19
+ /**
20
+ * Private key
21
+ */
22
+ privateKey?: string;
23
+
24
+ /**
25
+ * Public key
26
+ */
27
+ publicKey?: string;
28
+
29
+ /**
30
+ * Secret to encrypt the JWT
31
+ */
32
+ secret?: string;
33
+
34
+ /**
35
+ * JWT Provider
36
+ * See https://github.com/mikenicholson/passport-jwt/blob/master/README.md#configure-strategy
37
+ */
38
+ secretOrKeyProvider?: (
39
+ request: Record<string, any>,
40
+ rawJwtToken: string,
41
+ done: (err: any, secret: string) => any
42
+ ) => any;
43
+
44
+ /**
45
+ * Alias of secret (for backwards compatibility)
46
+ */
47
+ secretOrPrivateKey?: string;
48
+
49
+ /**
50
+ * SignIn Options like expiresIn
51
+ */
52
+ signInOptions?: JwtSignOptions;
53
+ }
54
+
13
55
  /**
14
56
  * Options for the server
15
57
  */
@@ -21,6 +63,18 @@ export interface IServerOptions {
21
63
  */
22
64
  automaticObjectIdFiltering?: boolean;
23
65
 
66
+ /**
67
+ * Whether to use the compression middleware package to enable gzip compression.
68
+ * See: https://docs.nestjs.com/techniques/compression
69
+ */
70
+ compression?: boolean | compression.CompressionOptions;
71
+
72
+ /**
73
+ * Whether to use cookies for authentication handling
74
+ * See: https://docs.nestjs.com/techniques/cookies
75
+ */
76
+ cookies?: boolean;
77
+
24
78
  /**
25
79
  * Cron jobs configuration object with the name of the cron job function as key
26
80
  * and the cron expression or config as value
@@ -105,6 +159,11 @@ export interface IServerOptions {
105
159
  */
106
160
  enableSubscriptionAuth?: boolean;
107
161
 
162
+ /**
163
+ * Maximum complexity of GraphQL requests
164
+ */
165
+ maxComplexity?: number;
166
+
108
167
  /**
109
168
  * Module options (forRootAsync)
110
169
  */
@@ -123,36 +182,9 @@ export interface IServerOptions {
123
182
  * Configuration of JavaScript Web Token (JWT) module
124
183
  */
125
184
  jwt?: {
126
- /**
127
- * Private key
128
- */
129
- privateKey?: string;
130
-
131
- /**
132
- * Public key
133
- */
134
- publicKey?: string;
135
-
136
- /**
137
- * Secret to encrypt the JWT
138
- */
139
- secret?: string;
140
-
141
- /**
142
- * JWT Provider
143
- * See https://github.com/mikenicholson/passport-jwt/blob/master/README.md#configure-strategy
144
- */
145
- secretOrKeyProvider?: (
146
- request: Record<string, any>,
147
- rawJwtToken: string,
148
- done: (err: any, secret: string) => any
149
- ) => any;
150
-
151
- /**
152
- * Alias of secret (for backwards compatibility)
153
- */
154
- secretOrPrivateKey?: string;
155
- } & JwtModuleOptions;
185
+ refresh?: IJwt;
186
+ } & IJwt &
187
+ JwtModuleOptions;
156
188
 
157
189
  /**
158
190
  * Load local configuration
@@ -162,6 +194,11 @@ export interface IServerOptions {
162
194
  */
163
195
  loadLocalConfig?: boolean | string;
164
196
 
197
+ /**
198
+ * Log exceptions (for better debugging)
199
+ */
200
+ logExceptions?: boolean;
201
+
165
202
  /**
166
203
  * Configuration for Mongoose
167
204
  */
@@ -125,4 +125,11 @@ export abstract class CoreModel {
125
125
  };
126
126
  return this.map(data, config);
127
127
  }
128
+
129
+ /**
130
+ * Verification of the user's rights to access the properties of this object
131
+ */
132
+ securityCheck(user: any, force?: boolean): this {
133
+ return this;
134
+ }
128
135
  }
@@ -0,0 +1,31 @@
1
+ import { GraphQLSchemaHost } from '@nestjs/graphql';
2
+ import { Plugin } from '@nestjs/apollo';
3
+ import { ApolloServerPlugin, GraphQLRequestListener } from 'apollo-server-plugin-base';
4
+ import { GraphQLError } from 'graphql';
5
+ import { fieldExtensionsEstimator, getComplexity, simpleEstimator } from 'graphql-query-complexity';
6
+ import { ConfigService } from '../services/config.service';
7
+
8
+ @Plugin()
9
+ export class ComplexityPlugin implements ApolloServerPlugin {
10
+ constructor(private gqlSchemaHost: GraphQLSchemaHost, private configService: ConfigService) {}
11
+
12
+ async requestDidStart(): Promise<GraphQLRequestListener> {
13
+ const maxComplexity: number = this.configService.getFastButReadOnly('graphQl.maxComplexity');
14
+ const { schema } = this.gqlSchemaHost;
15
+
16
+ return {
17
+ async didResolveOperation({ request, document }) {
18
+ const complexity = getComplexity({
19
+ schema,
20
+ operationName: request.operationName,
21
+ query: document,
22
+ variables: request.variables,
23
+ estimators: [fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 })],
24
+ });
25
+ if (maxComplexity !== undefined && complexity > maxComplexity) {
26
+ throw new GraphQLError(`Query is too complex: ${complexity}. Maximum allowed complexity: ${maxComplexity}`);
27
+ }
28
+ },
29
+ };
30
+ }
31
+ }
@@ -1,4 +1,4 @@
1
- module.exports = function mongooseIdPlugin(schema, options) {
1
+ export function mongooseIdPlugin(schema, options) {
2
2
  schema.post(['find', 'findOne', 'save', 'deleteOne'], function (docs) {
3
3
  if (!Array.isArray(docs)) {
4
4
  docs = [docs];
@@ -10,4 +10,6 @@ module.exports = function mongooseIdPlugin(schema, options) {
10
10
  }
11
11
  }
12
12
  });
13
- };
13
+ }
14
+
15
+ module.exports = mongooseIdPlugin;
@@ -129,28 +129,28 @@ export class ConfigService {
129
129
  /**
130
130
  * Get readable and writable deep-cloned property from configuration
131
131
  */
132
- get(key: string, defaultValue: any = undefined) {
132
+ get<T = any>(key: string, defaultValue: any = undefined): T {
133
133
  return ConfigService.get(key, defaultValue);
134
134
  }
135
135
 
136
136
  /**
137
137
  * Get readable and writable deep-cloned property from configuration
138
138
  */
139
- static get(key: string, defaultValue: any = undefined) {
139
+ static get<T = any>(key: string, defaultValue: any = undefined): T {
140
140
  return clone(_.get(ConfigService._configSubject$.getValue(), key, defaultValue), { circles: false });
141
141
  }
142
142
 
143
143
  /**
144
144
  * Get faster but read-ony deep-frozen property from configuration
145
145
  */
146
- getFastButReadOnly(key: string, defaultValue: any = undefined) {
146
+ getFastButReadOnly<T = any>(key: string, defaultValue: any = undefined): T {
147
147
  return ConfigService.getFastButReadOnly(key, defaultValue);
148
148
  }
149
149
 
150
150
  /**
151
151
  * Get faster but read-ony deep-frozen property from configuration
152
152
  */
153
- static getFastButReadOnly(key: string, defaultValue: any = undefined) {
153
+ static getFastButReadOnly<T = any>(key: string, defaultValue: any = undefined): T {
154
154
  return _.get(ConfigService._frozenConfigSubject$.getValue(), key, defaultValue);
155
155
  }
156
156
 
@@ -109,10 +109,10 @@ export abstract class ModuleService<T extends CoreModel = any> {
109
109
  // Note force configuration
110
110
  if (config.force) {
111
111
  config.checkRights = false;
112
- if (typeof config.prepareInput === 'object') {
112
+ if (config.prepareInput && typeof config.prepareInput === 'object') {
113
113
  config.prepareInput.checkRoles = false;
114
114
  }
115
- if (typeof config.prepareOutput === 'object') {
115
+ if (config.prepareOutput && typeof config.prepareOutput === 'object') {
116
116
  config.prepareOutput.removeSecrets = false;
117
117
  }
118
118
  }
@@ -1,5 +1,6 @@
1
1
  import { Field, ObjectType } from '@nestjs/graphql';
2
2
  import { CoreModel } from '../../common/models/core-model.model';
3
+ import { CoreUserModel } from '../user/core-user.model';
3
4
 
4
5
  /**
5
6
  * CoreAuth model for the response after the sign in
@@ -13,8 +14,20 @@ export class CoreAuthModel extends CoreModel {
13
14
  /**
14
15
  * JavaScript Web Token (JWT)
15
16
  */
16
- @Field({ description: 'JavaScript Web Token (JWT)' })
17
- token: string = undefined;
17
+ @Field({ description: 'JavaScript Web Token (JWT)', nullable: true })
18
+ token?: string = undefined;
19
+
20
+ /**
21
+ * Refresh token
22
+ */
23
+ @Field({ description: 'Refresh token', nullable: true })
24
+ refreshToken?: string = undefined;
25
+
26
+ /**
27
+ * Current user
28
+ */
29
+ @Field({ description: 'Current user' })
30
+ user: CoreUserModel = undefined;
18
31
 
19
32
  // ===================================================================================================================
20
33
  // Methods
@@ -3,7 +3,8 @@ import { APP_GUARD } from '@nestjs/core';
3
3
  import { JwtModule, JwtModuleOptions } from '@nestjs/jwt';
4
4
  import { PassportModule } from '@nestjs/passport';
5
5
  import { RolesGuard } from './guards/roles.guard';
6
- import { JwtStrategy } from './jwt.strategy';
6
+ import { JwtRefreshStrategy } from './strategies/jwt-refresh.strategy';
7
+ import { JwtStrategy } from './strategies/jwt.strategy';
7
8
  import { CoreAuthUserService } from './services/core-auth-user.service';
8
9
  import { CoreAuthService } from './services/core-auth.service';
9
10
  import { PubSub } from 'graphql-subscriptions';
@@ -23,6 +24,7 @@ export class CoreAuthModule {
23
24
  options: JwtModuleOptions & {
24
25
  authService?: Type<CoreAuthService>;
25
26
  jwtStrategy?: Type<JwtStrategy>;
27
+ jwtRefreshStrategy?: Type<JwtRefreshStrategy>;
26
28
  imports?: Array<Type<any> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
27
29
  providers?: Provider[];
28
30
  }
@@ -56,6 +58,10 @@ export class CoreAuthModule {
56
58
  provide: JwtStrategy,
57
59
  useClass: options.jwtStrategy || JwtStrategy,
58
60
  },
61
+ {
62
+ provide: JwtRefreshStrategy,
63
+ useClass: options.jwtRefreshStrategy || JwtRefreshStrategy,
64
+ },
59
65
  ];
60
66
  if (Array.isArray(options?.providers)) {
61
67
  providers = imports.concat(options.providers);
@@ -66,7 +72,7 @@ export class CoreAuthModule {
66
72
  module: CoreAuthModule,
67
73
  imports: imports,
68
74
  providers: providers,
69
- exports: [CoreAuthService, JwtModule, JwtStrategy, PassportModule, UserModule],
75
+ exports: [CoreAuthService, JwtModule, JwtStrategy, JwtRefreshStrategy, PassportModule, UserModule],
70
76
  };
71
77
  }
72
78
  }