dms-middleware-auth 1.0.9 → 1.1.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.
@@ -1,4 +1,4 @@
1
- import { NestMiddleware } from '@nestjs/common';
1
+ import { NestMiddleware, OnModuleInit } from '@nestjs/common';
2
2
  import { Response, NextFunction } from 'express';
3
3
  import { Cache } from 'cache-manager';
4
4
  interface AuthMiddlewareOptions {
@@ -10,13 +10,18 @@ interface AuthMiddlewareOptions {
10
10
  clientUuid: string;
11
11
  bypassURL: string;
12
12
  }
13
- export declare class AuthMiddleware implements NestMiddleware {
13
+ export declare class AuthMiddleware implements NestMiddleware, OnModuleInit {
14
14
  private cacheManager;
15
15
  private readonly options;
16
16
  private static licenceExpired;
17
17
  private static shutdownTimer;
18
+ private static licenceExpiryTimer;
19
+ private static licenceValidatedUntilMs;
20
+ private static licenceValidationPromise;
21
+ private static shutdownInitiated;
18
22
  private static readonly licenceExpiredMessage;
19
23
  constructor(cacheManager: Cache, options: AuthMiddlewareOptions);
24
+ onModuleInit(): Promise<void>;
20
25
  use(req: any, res: Response, next: NextFunction): Promise<void | Response<any, Record<string, any>>>;
21
26
  private clientLogin;
22
27
  private getUserDetails;
@@ -25,6 +30,8 @@ export declare class AuthMiddleware implements NestMiddleware {
25
30
  private getLicencingDetails;
26
31
  private validateLicence;
27
32
  private markLicenceExpired;
33
+ private scheduleLicenceShutdown;
34
+ private stopServer;
28
35
  private normalizeEpochMs;
29
36
  private verifyJwt;
30
37
  private decodeAccessToken;
@@ -57,18 +57,21 @@ let AuthMiddleware = AuthMiddleware_1 = class AuthMiddleware {
57
57
  this.cacheManager = cacheManager;
58
58
  this.options = options;
59
59
  }
60
+ async onModuleInit() {
61
+ const { publicKey, realm } = this.options;
62
+ const isValid = await this.checkLicenceAndValidate(realm, publicKey);
63
+ }
60
64
  async use(req, res, next) {
61
65
  const { publicKey, clientId, realm, bypassURL } = this.options;
62
66
  try {
63
67
  if (AuthMiddleware_1.licenceExpired) {
68
+ this.stopServer();
64
69
  return res.status(axios_1.HttpStatusCode.Forbidden).json({ message: AuthMiddleware_1.licenceExpiredMessage });
65
70
  }
66
- // fetching the licence and validating.
67
- const validate_lic = await this.checkLicenceAndValidate(realm, publicKey);
68
- if (!validate_lic) {
71
+ if (!AuthMiddleware_1.licenceValidatedUntilMs) {
69
72
  return res.status(axios_1.HttpStatusCode.Forbidden).json({ message: AuthMiddleware_1.licenceExpiredMessage });
70
73
  }
71
- else if (req.originalUrl == bypassURL && validate_lic) {
74
+ if (req.originalUrl == bypassURL) {
72
75
  return next();
73
76
  }
74
77
  const authHeader = req.headers['authorization'];
@@ -170,26 +173,30 @@ let AuthMiddleware = AuthMiddleware_1 = class AuthMiddleware {
170
173
  }
171
174
  async checkLicenceAndValidate(realm, publicKey) {
172
175
  try {
173
- // Reuse cached licence when possible; short-circuit if already marked expired.
174
176
  if (AuthMiddleware_1.licenceExpired) {
175
177
  return false;
176
178
  }
177
- const lic_token = await this.cacheManager.get('client_Licence_token');
178
- if (!lic_token) {
179
+ if (AuthMiddleware_1.licenceValidatedUntilMs && AuthMiddleware_1.licenceValidatedUntilMs > Date.now()) {
180
+ return true;
181
+ }
182
+ if (AuthMiddleware_1.licenceValidationPromise) {
183
+ return await AuthMiddleware_1.licenceValidationPromise;
184
+ }
185
+ AuthMiddleware_1.licenceValidationPromise = (async () => {
179
186
  const response = await this.getLicencingDetails(realm);
180
187
  if (response.code === axios_1.HttpStatusCode.InternalServerError) {
181
188
  return false;
182
189
  }
183
190
  else {
184
191
  const validate = await this.validateLicence(response.data, publicKey);
185
- if (validate.status && validate.ttl) {
186
- await this.cacheManager.set('client_Licence_token', response.data, validate.ttl);
187
- }
188
192
  return validate.status;
189
193
  }
194
+ })();
195
+ try {
196
+ return await AuthMiddleware_1.licenceValidationPromise;
190
197
  }
191
- else {
192
- return await this.validateLicence(lic_token, publicKey);
198
+ finally {
199
+ AuthMiddleware_1.licenceValidationPromise = null;
193
200
  }
194
201
  }
195
202
  catch (error) {
@@ -227,6 +234,7 @@ let AuthMiddleware = AuthMiddleware_1 = class AuthMiddleware {
227
234
  const licEndMs = this.normalizeEpochMs(token?.lic_end);
228
235
  // Reject when licence end (epoch) is missing or already in the past.
229
236
  if (!licEndMs) {
237
+ this.markLicenceExpired();
230
238
  return {
231
239
  status: false
232
240
  };
@@ -238,6 +246,8 @@ let AuthMiddleware = AuthMiddleware_1 = class AuthMiddleware {
238
246
  };
239
247
  }
240
248
  else {
249
+ AuthMiddleware_1.licenceValidatedUntilMs = licEndMs;
250
+ this.scheduleLicenceShutdown(licEndMs);
241
251
  return {
242
252
  status: true,
243
253
  ttl: (licEndMs - Date.now()) > 0 ? (licEndMs - Date.now()) : null
@@ -246,18 +256,51 @@ let AuthMiddleware = AuthMiddleware_1 = class AuthMiddleware {
246
256
  }
247
257
  catch (error) {
248
258
  this.markLicenceExpired();
249
- return false;
259
+ return {
260
+ status: false
261
+ };
250
262
  }
251
263
  }
252
264
  markLicenceExpired() {
253
265
  if (!AuthMiddleware_1.licenceExpired) {
254
266
  AuthMiddleware_1.licenceExpired = true;
255
267
  }
256
- if (!AuthMiddleware_1.shutdownTimer) {
257
- AuthMiddleware_1.shutdownTimer = setTimeout(() => {
258
- process.exit(1);
259
- }, 2 * 60 * 1000); // waiting two minutes after shutdowning server.
268
+ // this.stopServer();
269
+ }
270
+ scheduleLicenceShutdown(licEndMs) {
271
+ if (!licEndMs) {
272
+ return;
260
273
  }
274
+ const delay = licEndMs - Date.now();
275
+ if (delay <= 0) {
276
+ this.markLicenceExpired();
277
+ return;
278
+ }
279
+ if (AuthMiddleware_1.licenceExpiryTimer) {
280
+ return;
281
+ }
282
+ AuthMiddleware_1.licenceExpiryTimer = setTimeout(() => {
283
+ this.markLicenceExpired();
284
+ }, delay);
285
+ }
286
+ stopServer() {
287
+ if (AuthMiddleware_1.shutdownInitiated) {
288
+ return;
289
+ }
290
+ AuthMiddleware_1.shutdownInitiated = true;
291
+ setTimeout(() => {
292
+ try {
293
+ process.kill(process.pid, 'SIGTERM');
294
+ }
295
+ catch {
296
+ process.exit(1);
297
+ }
298
+ if (!AuthMiddleware_1.shutdownTimer) {
299
+ AuthMiddleware_1.shutdownTimer = setTimeout(() => {
300
+ process.exit(1);
301
+ }, 5000);
302
+ }
303
+ }, 0);
261
304
  }
262
305
  normalizeEpochMs(epoch) {
263
306
  if (!epoch || Number.isNaN(epoch)) {
@@ -284,6 +327,10 @@ let AuthMiddleware = AuthMiddleware_1 = class AuthMiddleware {
284
327
  exports.AuthMiddleware = AuthMiddleware;
285
328
  AuthMiddleware.licenceExpired = false;
286
329
  AuthMiddleware.shutdownTimer = null;
330
+ AuthMiddleware.licenceExpiryTimer = null;
331
+ AuthMiddleware.licenceValidatedUntilMs = null;
332
+ AuthMiddleware.licenceValidationPromise = null;
333
+ AuthMiddleware.shutdownInitiated = false;
287
334
  AuthMiddleware.licenceExpiredMessage = "server Licence is expired!. please renew";
288
335
  exports.AuthMiddleware = AuthMiddleware = AuthMiddleware_1 = __decorate([
289
336
  (0, common_1.Injectable)(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dms-middleware-auth",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
4
4
  "description": "Reusable middleware for authentication and authorization in NestJS applications.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,4 +1,4 @@
1
- import { Inject, Injectable, NestMiddleware } from '@nestjs/common';
1
+ import { Inject, Injectable, NestMiddleware, OnModuleInit } from '@nestjs/common';
2
2
  import { Response, NextFunction } from 'express';
3
3
  import * as jwt from 'jsonwebtoken';
4
4
  import axios, { HttpStatusCode } from 'axios';
@@ -16,9 +16,13 @@ interface AuthMiddlewareOptions {
16
16
  }
17
17
 
18
18
  @Injectable()
19
- export class AuthMiddleware implements NestMiddleware {
19
+ export class AuthMiddleware implements NestMiddleware, OnModuleInit {
20
20
  private static licenceExpired = false;
21
21
  private static shutdownTimer: NodeJS.Timeout | null = null;
22
+ private static licenceExpiryTimer: NodeJS.Timeout | null = null;
23
+ private static licenceValidatedUntilMs: number | null = null;
24
+ private static licenceValidationPromise: Promise<boolean> | null = null;
25
+ private static shutdownInitiated = false;
22
26
  private static readonly licenceExpiredMessage = "server Licence is expired!. please renew";
23
27
 
24
28
  constructor(
@@ -26,6 +30,12 @@ export class AuthMiddleware implements NestMiddleware {
26
30
  @Inject('AUTH_MIDDLEWARE_OPTIONS') private readonly options: AuthMiddlewareOptions
27
31
  ) {}
28
32
 
33
+ async onModuleInit() {
34
+ const { publicKey, realm } = this.options;
35
+ const isValid = await this.checkLicenceAndValidate(realm, publicKey);
36
+
37
+ }
38
+
29
39
  async use(req: any, res: Response, next: NextFunction) {
30
40
 
31
41
 
@@ -33,16 +43,17 @@ export class AuthMiddleware implements NestMiddleware {
33
43
 
34
44
  try {
35
45
  if (AuthMiddleware.licenceExpired) {
46
+
47
+ this.stopServer();
48
+
36
49
  return res.status(HttpStatusCode.Forbidden).json({ message: AuthMiddleware.licenceExpiredMessage });
37
50
  }
38
51
 
39
- // fetching the licence and validating.
40
- const validate_lic = await this.checkLicenceAndValidate(realm, publicKey);
41
- if (!validate_lic) {
42
- return res.status(HttpStatusCode.Forbidden).json({message: AuthMiddleware.licenceExpiredMessage});
52
+ if (!AuthMiddleware.licenceValidatedUntilMs) {
53
+ return res.status(HttpStatusCode.Forbidden).json({ message: AuthMiddleware.licenceExpiredMessage });
43
54
  }
44
- else if (req.originalUrl == bypassURL && validate_lic ) {
45
- return next();
55
+ if (req.originalUrl == bypassURL) {
56
+ return next();
46
57
  }
47
58
  const authHeader = req.headers['authorization'];
48
59
 
@@ -165,27 +176,29 @@ export class AuthMiddleware implements NestMiddleware {
165
176
 
166
177
  private async checkLicenceAndValidate(realm: string, publicKey:string) {
167
178
  try {
168
- // Reuse cached licence when possible; short-circuit if already marked expired.
169
179
  if (AuthMiddleware.licenceExpired) {
170
180
  return false;
171
181
  }
172
- const lic_token = await this.cacheManager.get( 'client_Licence_token' );
173
- if (!lic_token) {
182
+ if (AuthMiddleware.licenceValidatedUntilMs && AuthMiddleware.licenceValidatedUntilMs > Date.now()) {
183
+ return true;
184
+ }
185
+ if (AuthMiddleware.licenceValidationPromise) {
186
+ return await AuthMiddleware.licenceValidationPromise;
187
+ }
188
+ AuthMiddleware.licenceValidationPromise = (async () => {
174
189
  const response:any = await this.getLicencingDetails(realm);
175
190
  if (response.code === HttpStatusCode.InternalServerError) {
176
191
  return false
177
192
  }
178
193
  else{
179
- const validate:any = await this.validateLicence(response.data, publicKey);
180
- if (validate.status && validate.ttl) {
181
- await this.cacheManager.set('client_Licence_token', response.data, validate.ttl);
182
- }
183
-
194
+ const validate = await this.validateLicence(response.data, publicKey);
184
195
  return validate.status;
185
196
  }
186
- }
187
- else {
188
- return await this.validateLicence(lic_token, publicKey);
197
+ })();
198
+ try {
199
+ return await AuthMiddleware.licenceValidationPromise;
200
+ } finally {
201
+ AuthMiddleware.licenceValidationPromise = null;
189
202
  }
190
203
  }
191
204
  catch(error:any){
@@ -228,6 +241,7 @@ export class AuthMiddleware implements NestMiddleware {
228
241
  const licEndMs = this.normalizeEpochMs(token?.lic_end);
229
242
  // Reject when licence end (epoch) is missing or already in the past.
230
243
  if (!licEndMs) {
244
+ this.markLicenceExpired();
231
245
  return{
232
246
  status: false
233
247
  }
@@ -238,7 +252,8 @@ export class AuthMiddleware implements NestMiddleware {
238
252
  status: false
239
253
  }
240
254
  } else {
241
-
255
+ AuthMiddleware.licenceValidatedUntilMs = licEndMs;
256
+ this.scheduleLicenceShutdown(licEndMs);
242
257
  return {
243
258
  status: true,
244
259
  ttl: (licEndMs - Date.now()) > 0 ? (licEndMs - Date.now()) : null
@@ -247,7 +262,9 @@ export class AuthMiddleware implements NestMiddleware {
247
262
  }
248
263
  catch(error:any){
249
264
  this.markLicenceExpired();
250
- return false;
265
+ return {
266
+ status: false
267
+ };
251
268
  }
252
269
  }
253
270
 
@@ -255,11 +272,43 @@ export class AuthMiddleware implements NestMiddleware {
255
272
  if (!AuthMiddleware.licenceExpired) {
256
273
  AuthMiddleware.licenceExpired = true;
257
274
  }
258
- if (!AuthMiddleware.shutdownTimer) {
259
- AuthMiddleware.shutdownTimer = setTimeout(() => {
260
- process.exit(1);
261
- }, 2 * 60 * 1000); // waiting two minutes after shutdowning server.
275
+ // this.stopServer();
276
+ }
277
+
278
+ private scheduleLicenceShutdown(licEndMs: number) {
279
+ if (!licEndMs) {
280
+ return;
262
281
  }
282
+ const delay = licEndMs - Date.now();
283
+ if (delay <= 0) {
284
+ this.markLicenceExpired();
285
+ return;
286
+ }
287
+ if (AuthMiddleware.licenceExpiryTimer) {
288
+ return;
289
+ }
290
+ AuthMiddleware.licenceExpiryTimer = setTimeout(() => {
291
+ this.markLicenceExpired();
292
+ }, delay);
293
+ }
294
+
295
+ private stopServer() {
296
+ if (AuthMiddleware.shutdownInitiated) {
297
+ return;
298
+ }
299
+ AuthMiddleware.shutdownInitiated = true;
300
+ setTimeout(() => {
301
+ try {
302
+ process.kill(process.pid, 'SIGTERM');
303
+ } catch {
304
+ process.exit(1);
305
+ }
306
+ if (!AuthMiddleware.shutdownTimer) {
307
+ AuthMiddleware.shutdownTimer = setTimeout(() => {
308
+ process.exit(1);
309
+ }, 5000);
310
+ }
311
+ }, 0);
263
312
  }
264
313
 
265
314
  private normalizeEpochMs(epoch: number): number | null {