@lenne.tech/nest-server 10.2.3 → 10.2.4
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 +3 -0
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +1 -0
- package/dist/core/common/services/config.service.js +2 -2
- package/dist/core/common/services/config.service.js.map +1 -1
- package/dist/core/modules/auth/interfaces/core-auth-user.interface.d.ts +5 -0
- package/dist/core/modules/auth/services/core-auth.service.js +20 -3
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/user/core-user.model.d.ts +5 -0
- package/dist/core/modules/user/core-user.model.js +6 -0
- package/dist/core/modules/user/core-user.model.js.map +1 -1
- package/dist/test/test.helper.d.ts +1 -0
- package/dist/test/test.helper.js +3 -0
- package/dist/test/test.helper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config.env.ts +3 -0
- package/src/core/common/interfaces/server-options.interface.ts +7 -0
- package/src/core/common/services/config.service.ts +2 -2
- package/src/core/modules/auth/interfaces/core-auth-user.interface.ts +6 -0
- package/src/core/modules/auth/services/core-auth.service.ts +26 -4
- package/src/core/modules/user/core-user.model.ts +8 -0
- package/src/test/test.helper.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.4",
|
|
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",
|
package/src/config.env.ts
CHANGED
|
@@ -86,6 +86,7 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
86
86
|
expiresIn: '7d',
|
|
87
87
|
},
|
|
88
88
|
},
|
|
89
|
+
sameTokenIdPeriod: 2000,
|
|
89
90
|
},
|
|
90
91
|
loadLocalConfig: true,
|
|
91
92
|
logExceptions: true,
|
|
@@ -176,6 +177,7 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
176
177
|
expiresIn: '7d',
|
|
177
178
|
},
|
|
178
179
|
},
|
|
180
|
+
sameTokenIdPeriod: 2000,
|
|
179
181
|
},
|
|
180
182
|
loadLocalConfig: false,
|
|
181
183
|
logExceptions: true,
|
|
@@ -266,6 +268,7 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
266
268
|
expiresIn: '7d',
|
|
267
269
|
},
|
|
268
270
|
},
|
|
271
|
+
sameTokenIdPeriod: 2000,
|
|
269
272
|
},
|
|
270
273
|
loadLocalConfig: false,
|
|
271
274
|
logExceptions: true,
|
|
@@ -315,6 +315,13 @@ export interface IServerOptions {
|
|
|
315
315
|
*/
|
|
316
316
|
renewal?: boolean;
|
|
317
317
|
} & IJwt;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Time period in milliseconds
|
|
321
|
+
* in which the same token ID is used so that all parallel token refresh requests of a device can be generated.
|
|
322
|
+
* default: 0 (every token includes a new token ID, all parallel token refresh requests must be prevented by the client or processed accordingly)
|
|
323
|
+
*/
|
|
324
|
+
sameTokenIdPeriod?: number;
|
|
318
325
|
} & IJwt &
|
|
319
326
|
JwtModuleOptions;
|
|
320
327
|
|
|
@@ -74,7 +74,7 @@ export class ConfigService {
|
|
|
74
74
|
// Init subject handling
|
|
75
75
|
if (!isInitialized) {
|
|
76
76
|
ConfigService._configSubject$.subscribe((config) => {
|
|
77
|
-
ConfigService._frozenConfigSubject$.next(deepFreeze(config));
|
|
77
|
+
ConfigService._frozenConfigSubject$.next(deepFreeze(cloneDeep(config)));
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -370,7 +370,7 @@ export class ConfigService {
|
|
|
370
370
|
* Set config property in ConfigService
|
|
371
371
|
*/
|
|
372
372
|
setProperty(key: string, value: any, options?: { warn?: boolean }) {
|
|
373
|
-
return ConfigService.setProperty(key, options);
|
|
373
|
+
return ConfigService.setProperty(key, value, options);
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
/**
|
|
@@ -23,4 +23,10 @@ export interface ICoreAuthUser {
|
|
|
23
23
|
* Refresh tokens for different devices
|
|
24
24
|
*/
|
|
25
25
|
refreshTokens?: Record<string, CoreTokenData>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Temporary tokens for parallel requests during the token refresh process
|
|
29
|
+
* See sameTokenIdPeriod in configuration
|
|
30
|
+
*/
|
|
31
|
+
tempTokens?: Record<string, { createdAt: number; deviceId: string; tokenId: string }>;
|
|
26
32
|
}
|
|
@@ -204,11 +204,26 @@ export class CoreAuthService {
|
|
|
204
204
|
* Get JWT and refresh token
|
|
205
205
|
*/
|
|
206
206
|
protected async createTokens(userId: string, data?: { [key: string]: any; deviceId?: string }) {
|
|
207
|
-
|
|
207
|
+
|
|
208
|
+
// Initializations
|
|
209
|
+
const sameTokenIdPeriod: number = this.configService.getFastButReadOnly('jwt.sameTokenIdPeriod', 0);
|
|
210
|
+
const deviceId = data?.deviceId || randomUUID();
|
|
211
|
+
|
|
212
|
+
// Use last token ID or a new one
|
|
213
|
+
let tokenId: string = randomUUID();
|
|
214
|
+
if (sameTokenIdPeriod) {
|
|
215
|
+
const user: ICoreAuthUser = await this.userService.get(userId, { force: true });
|
|
216
|
+
const tempToken = user?.tempTokens?.[deviceId];
|
|
217
|
+
if (tempToken && tempToken.tokenId && tempToken.createdAt >= new Date().getTime() - sameTokenIdPeriod) {
|
|
218
|
+
tokenId = tempToken.tokenId;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const payload: { [key: string]: any; id: string; deviceId: string; tokenId: string } = {
|
|
208
223
|
...data,
|
|
209
224
|
id: userId,
|
|
210
|
-
deviceId
|
|
211
|
-
tokenId
|
|
225
|
+
deviceId,
|
|
226
|
+
tokenId,
|
|
212
227
|
};
|
|
213
228
|
const [token, refreshToken] = await Promise.all([
|
|
214
229
|
this.jwtService.signAsync(payload, {
|
|
@@ -253,6 +268,9 @@ export class CoreAuthService {
|
|
|
253
268
|
if (!user.refreshTokens) {
|
|
254
269
|
user.refreshTokens = {};
|
|
255
270
|
}
|
|
271
|
+
if (!user.tempTokens) {
|
|
272
|
+
user.tempTokens = {};
|
|
273
|
+
}
|
|
256
274
|
if (deviceId) {
|
|
257
275
|
const oldData = user.refreshTokens[deviceId] || {};
|
|
258
276
|
data = Object.assign(oldData, data);
|
|
@@ -267,7 +285,11 @@ export class CoreAuthService {
|
|
|
267
285
|
deviceId = payload.deviceId;
|
|
268
286
|
}
|
|
269
287
|
user.refreshTokens[deviceId] = { ...data, deviceId, tokenId: payload.tokenId };
|
|
270
|
-
|
|
288
|
+
user.tempTokens[deviceId] = { createdAt: new Date().getTime(), deviceId, tokenId: payload.tokenId };
|
|
289
|
+
await this.userService.update(getStringIds(user), {
|
|
290
|
+
refreshTokens: user.refreshTokens,
|
|
291
|
+
tempTokens: user.tempTokens,
|
|
292
|
+
}, { force: true });
|
|
271
293
|
|
|
272
294
|
// Return new token
|
|
273
295
|
return newRefreshToken;
|
|
@@ -79,6 +79,14 @@ export abstract class CoreUserModel extends CorePersistenceModel {
|
|
|
79
79
|
@Prop(raw({}))
|
|
80
80
|
refreshTokens: Record<string, CoreTokenData> = undefined;
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Temporary token for parallel requests during the token refresh process
|
|
84
|
+
* See sameTokenIdPeriod in configuration
|
|
85
|
+
*/
|
|
86
|
+
@IsOptional()
|
|
87
|
+
@Prop(raw({}))
|
|
88
|
+
tempTokens: Record<string, { createdAt: number; deviceId: string; tokenId: string }> = undefined;
|
|
89
|
+
|
|
82
90
|
/**
|
|
83
91
|
* Verification token of the user
|
|
84
92
|
*/
|
package/src/test/test.helper.ts
CHANGED
|
@@ -606,4 +606,12 @@ export class TestHelper {
|
|
|
606
606
|
// Return subscribed messages
|
|
607
607
|
return messages;
|
|
608
608
|
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Convert JWT into to object
|
|
612
|
+
* @param token
|
|
613
|
+
*/
|
|
614
|
+
parseJwt(token) {
|
|
615
|
+
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
616
|
+
}
|
|
609
617
|
}
|