@lenne.tech/nest-server 10.0.6 → 10.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "10.0.6",
3
+ "version": "10.0.8",
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",
@@ -75,13 +75,13 @@
75
75
  "@nestjs/terminus": "10.0.1",
76
76
  "apollo-server-core": "3.11.1",
77
77
  "apollo-server-express": "3.11.1",
78
- "bcrypt": "5.1.0",
78
+ "bcrypt": "5.1.1",
79
79
  "class-transformer": "0.5.1",
80
80
  "class-validator": "0.14.0",
81
81
  "compression": "1.7.4",
82
82
  "cookie-parser": "1.4.6",
83
83
  "ejs": "3.1.9",
84
- "graphql": "16.7.1",
84
+ "graphql": "16.8.0",
85
85
  "graphql-query-complexity": "0.12.0",
86
86
  "graphql-subscriptions": "2.0.0",
87
87
  "graphql-upload": "15.0.2",
@@ -89,7 +89,7 @@
89
89
  "json-to-graphql-query": "2.2.5",
90
90
  "light-my-request": "5.10.0",
91
91
  "lodash": "4.17.21",
92
- "mongodb": "4.16.0",
92
+ "mongodb": "4.17.0",
93
93
  "mongoose": "6.11.5",
94
94
  "mongoose-gridfs": "1.3.0",
95
95
  "multer": "1.4.5-lts.1",
@@ -109,12 +109,12 @@
109
109
  "@babel/plugin-proposal-private-methods": "7.18.6",
110
110
  "@compodoc/compodoc": "1.1.21",
111
111
  "@lenne.tech/eslint-config-ts": "0.0.9",
112
- "@nestjs/cli": "10.1.11",
112
+ "@nestjs/cli": "10.1.12",
113
113
  "@nestjs/schematics": "10.0.2",
114
114
  "@nestjs/testing": "10.1.3",
115
115
  "@swc/cli": "0.1.62",
116
- "@swc/core": "1.3.76",
117
- "@swc/jest": "0.2.28",
116
+ "@swc/core": "1.3.78",
117
+ "@swc/jest": "0.2.29",
118
118
  "@types/compression": "1.7.2",
119
119
  "@types/cookie-parser": "1.4.3",
120
120
  "@types/cron": "2.0.1",
@@ -123,14 +123,14 @@
123
123
  "@types/jest": "29.5.3",
124
124
  "@types/lodash": "4.14.197",
125
125
  "@types/multer": "1.4.7",
126
- "@types/node": "20.4.9",
126
+ "@types/node": "20.5.1",
127
127
  "@types/nodemailer": "6.4.9",
128
128
  "@types/passport": "1.0.12",
129
129
  "@types/supertest": "2.0.12",
130
- "@typescript-eslint/eslint-plugin": "6.3.0",
131
- "@typescript-eslint/parser": "6.3.0",
130
+ "@typescript-eslint/eslint-plugin": "6.4.0",
131
+ "@typescript-eslint/parser": "6.4.0",
132
132
  "coffeescript": "2.7.0",
133
- "eslint": "8.46.0",
133
+ "eslint": "8.47.0",
134
134
  "eslint-config-prettier": "9.0.0",
135
135
  "eslint-plugin-unused-imports": "3.0.0",
136
136
  "find-file-up": "2.0.1",
@@ -143,7 +143,7 @@
143
143
  "jest": "29.6.2",
144
144
  "npm-watch": "0.11.0",
145
145
  "pm2": "5.3.0",
146
- "prettier": "3.0.1",
146
+ "prettier": "3.0.2",
147
147
  "pretty-quick": "3.1.3",
148
148
  "supertest": "6.3.3",
149
149
  "ts-jest": "29.1.1",
package/src/config.env.ts CHANGED
@@ -18,6 +18,7 @@ const config: { [env: string]: IServerOptions } = {
18
18
  sayHello: {
19
19
  cronTime: CronExpression.EVERY_10_SECONDS,
20
20
  runOnInit: false,
21
+ disabled: false,
21
22
  runParallel: 1,
22
23
  timeZone: 'Europe/Berlin',
23
24
  throwException: false,
@@ -65,12 +66,20 @@ const config: { [env: string]: IServerOptions } = {
65
66
  },
66
67
  ignoreSelectionsForPopulate: true,
67
68
  jwt: {
69
+ // Each secret should be unique and not reused in other environments,
70
+ // also the JWT secret should be different from the Refresh secret!
71
+ // crypto.randomBytes(512).toString('base64') (see https://nodejs.org/api/crypto.html#crypto)
72
+ // tslint:disable-next-line:max-line-length
68
73
  secret: 'SECRET_OR_PRIVATE_KEY_LOCAL',
69
74
  signInOptions: {
70
75
  expiresIn: '15m',
71
76
  },
72
77
  refresh: {
73
78
  renewal: true,
79
+ // Each secret should be unique and not reused in other environments,
80
+ // also the JWT secret should be different from the Refresh secret!
81
+ // crypto.randomBytes(512).toString('base64') (see https://nodejs.org/api/crypto.html#crypto)
82
+ // tslint:disable-next-line:max-line-length
74
83
  secret: 'SECRET_OR_PRIVATE_KEY_LOCAL_REFRESH',
75
84
  signInOptions: {
76
85
  expiresIn: '7d',
@@ -147,12 +156,20 @@ const config: { [env: string]: IServerOptions } = {
147
156
  },
148
157
  ignoreSelectionsForPopulate: true,
149
158
  jwt: {
159
+ // Each secret should be unique and not reused in other environments,
160
+ // also the JWT secret should be different from the Refresh secret!
161
+ // crypto.randomBytes(512).toString('base64') (see https://nodejs.org/api/crypto.html#crypto)
162
+ // tslint:disable-next-line:max-line-length
150
163
  secret: 'SECRET_OR_PRIVATE_KEY_DEV',
151
164
  signInOptions: {
152
165
  expiresIn: '15m',
153
166
  },
154
167
  refresh: {
155
168
  renewal: true,
169
+ // Each secret should be unique and not reused in other environments,
170
+ // also the JWT secret should be different from the Refresh secret!
171
+ // crypto.randomBytes(512).toString('base64') (see https://nodejs.org/api/crypto.html#crypto)
172
+ // tslint:disable-next-line:max-line-length
156
173
  secret: 'SECRET_OR_PRIVATE_KEY_DEV_REFRESH',
157
174
  signInOptions: {
158
175
  expiresIn: '7d',
@@ -229,12 +246,20 @@ const config: { [env: string]: IServerOptions } = {
229
246
  },
230
247
  ignoreSelectionsForPopulate: true,
231
248
  jwt: {
249
+ // Each secret should be unique and not reused in other environments,
250
+ // also the JWT secret should be different from the Refresh secret!
251
+ // crypto.randomBytes(512).toString('base64') (see https://nodejs.org/api/crypto.html#crypto)
252
+ // tslint:disable-next-line:max-line-length
232
253
  secret: 'SECRET_OR_PRIVATE_KEY_PROD',
233
254
  signInOptions: {
234
255
  expiresIn: '15m',
235
256
  },
236
257
  refresh: {
237
258
  renewal: true,
259
+ // Each secret should be unique and not reused in other environments,
260
+ // also the JWT secret should be different from the Refresh secret!
261
+ // crypto.randomBytes(512).toString('base64') (see https://nodejs.org/api/crypto.html#crypto)
262
+ // tslint:disable-next-line:max-line-length
238
263
  secret: 'SECRET_OR_PRIVATE_KEY_PROD_REFRESH',
239
264
  signInOptions: {
240
265
  expiresIn: '7d',
@@ -18,13 +18,19 @@ export interface CronJobConfig {
18
18
  */
19
19
  cronTime: CronExpression | string | Date | Falsy;
20
20
 
21
+ /**
22
+ * Whether the cron job is disabled or not.
23
+ * This option is set to `false` by default
24
+ */
25
+ disabled?: boolean;
26
+
21
27
  /**
22
28
  * A function that will fire when the job is complete, when it is stopped.
23
29
  */
24
30
  onComplete?: CronCommand | null;
25
31
 
26
32
  /**
27
- * This will immediately fire your `onTickfunction` as soon as the requisit initialization has happened.
33
+ * This will immediately fire the `onTick` function as soon as the requisite initialization has happened.
28
34
  * This option is set to `true` by default.
29
35
  */
30
36
  runOnInit?: boolean;
@@ -58,8 +64,8 @@ export interface CronJobConfig {
58
64
  unrefTimeout?: boolean;
59
65
 
60
66
  /**
61
- * This allows you to specify the offset of your timezone rather than using the `timeZoneparam.
62
- * Probably don't use both ``timeZone` andutcOffset`` together or weird things may happen.
67
+ * This allows you to specify the offset of the timezone rather than using the `timeZone` parameter.
68
+ * Probably don't use both `timeZone` and `utcOffset` together or weird things may happen.
63
69
  */
64
70
  utcOffset?: string | number;
65
71
  }
@@ -30,6 +30,8 @@ export interface IJwt {
30
30
 
31
31
  /**
32
32
  * Secret to encrypt the JWT
33
+ * Each secret should be unique and not reused in other environments,
34
+ * also the JWT secret should be different from the Refresh secret!
33
35
  */
34
36
  secret?: string;
35
37
 
@@ -288,10 +290,15 @@ export interface IServerOptions {
288
290
 
289
291
  /**
290
292
  * Configuration of JavaScript Web Token (JWT) module
293
+ *
294
+ * Hint: The secrets of the different environments should be different, otherwise a JWT can be used in different
295
+ * environments, which can lead to security vulnerabilities.
291
296
  */
292
297
  jwt?: {
293
298
  /**
294
299
  * Configuration for refresh Token (JWT)
300
+ * Hint: The secret of the JWT and the Refresh Token should be different, otherwise a new RefreshToken can also be
301
+ * requested with the JWT, which can lead to a security vulnerability.
295
302
  */
296
303
  refresh?: {
297
304
  /**
@@ -62,15 +62,18 @@ export abstract class CoreCronJobs implements OnApplicationBootstrap {
62
62
  // Init cron jobs
63
63
  for (const [name, CronExpressionOrConfig] of Object.entries(this.cronJobs)) {
64
64
  // Check config
65
- if (!CronExpressionOrConfig) {
65
+ if (
66
+ !CronExpressionOrConfig
67
+ || (typeof CronExpressionOrConfig === 'object' && (CronExpressionOrConfig as CronJobConfig).disabled)
68
+ ) {
66
69
  continue;
67
70
  }
68
71
 
69
72
  // Prepare config
70
- let conf: CronExpression | string | Date | Falsy | CronJobConfig = CronExpressionOrConfig;
71
- if (typeof conf === 'string' || conf instanceof Date) {
73
+ let conf: CronJobConfig = (CronExpressionOrConfig as CronJobConfig);
74
+ if (typeof CronExpressionOrConfig === 'string' || CronExpressionOrConfig instanceof Date) {
72
75
  conf = {
73
- cronTime: conf,
76
+ cronTime: CronExpressionOrConfig as string | Date,
74
77
  };
75
78
  }
76
79
 
@@ -116,7 +116,7 @@ export class ModelDocService implements OnApplicationBootstrap {
116
116
  * @param yUmlText
117
117
  * @protected
118
118
  */
119
- protected yUmlToSvg(yUmlText: String) {
119
+ protected yUmlToSvg(yUmlText: string) {
120
120
 
121
121
  // Create diagrams
122
122
  // see https://github.com/jaime-olivares/yuml-diagram
@@ -125,6 +125,13 @@ export class ModelDocService implements OnApplicationBootstrap {
125
125
  const svgLightBg = yuml.processYumlDocument(yUmlText, false);
126
126
  const svgDarkBg = yuml.processYumlDocument(yUmlText, true);
127
127
 
128
+ // Save yuml document
129
+ fs.writeFile('model-doc.yuml', yUmlText, (err) => {
130
+ if (err) {
131
+ console.error(err);
132
+ }
133
+ });
134
+
128
135
  // Save diagrams
129
136
  fs.writeFile('model-doc-light.svg', svgLightBg, (err) => {
130
137
  if (err) {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Wrapper type used to circumvent ESM modules circular dependency issue
3
+ * caused by reflection metadata saving the type of the property.
4
+ *
5
+ * It is needed if swc is used and ReferenceError occurs:
6
+ * @Inject(forwardRef(() => CustomService)) private readonly customService: WrapperType<CustomService>,
7
+ *
8
+ * See https://docs.nestjs.com/recipes/swc#common-pitfalls
9
+ */
10
+ export type WrapperType<T> = T; // WrapperType === Relation
@@ -128,6 +128,12 @@ export class CoreModule implements NestModule {
128
128
  options,
129
129
  );
130
130
 
131
+ // Check secrets
132
+ const jwtConfig = config.jwt;
133
+ if (jwtConfig?.secret && jwtConfig.secret && jwtConfig.refresh && jwtConfig.refresh.secret === jwtConfig.secret) {
134
+ console.warn('JWT secret and refresh secret are equal, this can lead to security vulnerabilities!');
135
+ }
136
+
131
137
  // Set providers
132
138
  const providers: any[] = [
133
139
  // The ConfigService provides access to the current configuration of the module
package/src/index.ts CHANGED
@@ -80,6 +80,7 @@ export * from './core/common/types/remove-methods.type';
80
80
  export * from './core/common/types/require-only-one.type';
81
81
  export * from './core/common/types/required-at-least-one.type';
82
82
  export * from './core/common/types/string-or-object-id.type';
83
+ export * from './core/common/types/wrapper.type';
83
84
 
84
85
  // =====================================================================================================================
85
86
  // Core - Modules - Auth