@aranzatech/aranza-auth 0.1.2 → 0.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.
package/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var common = require('@nestjs/common');
4
+ var core = require('@nestjs/core');
4
5
  var jwt = require('@nestjs/jwt');
5
6
  var passport = require('@nestjs/passport');
6
7
  var bcrypt2 = require('bcryptjs');
@@ -39,6 +40,29 @@ var __decorateClass = (decorators, target, key, kind) => {
39
40
  return result;
40
41
  };
41
42
  var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
43
+
44
+ // src/constants/rate-limit.presets.ts
45
+ var AUTH_RATE_LIMIT_PRESETS = {
46
+ /** General auth routes: 10 requests / minute / IP */
47
+ default: { name: "auth-default", ttl: 6e4, limit: 10 },
48
+ /** Login, register, refresh: 5 requests / minute / IP */
49
+ credentials: { name: "auth-credentials", ttl: 6e4, limit: 5 },
50
+ /** Forgot password: 3 requests / minute / IP */
51
+ passwordReset: { name: "auth-password-reset", ttl: 6e4, limit: 3 }
52
+ };
53
+
54
+ // src/constants/auth-errors.ts
55
+ var AuthErrorCode = {
56
+ INVALID_CREDENTIALS: "Invalid credentials",
57
+ INVALID_REFRESH_TOKEN: "Invalid refresh token",
58
+ REFRESH_TOKEN_REUSE: "REFRESH_TOKEN_REUSE",
59
+ ACCOUNT_DISABLED: "ACCOUNT_DISABLED",
60
+ EMAIL_NOT_VERIFIED: "EMAIL_NOT_VERIFIED",
61
+ TOKEN_INVALID_OR_EXPIRED: "TOKEN_INVALID_OR_EXPIRED",
62
+ ACCOUNT_LOCKED: "ACCOUNT_LOCKED",
63
+ INVALID_CURRENT_PASSWORD: "INVALID_CURRENT_PASSWORD",
64
+ PASSWORD_UNCHANGED: "PASSWORD_UNCHANGED"
65
+ };
42
66
  var CurrentUser = common.createParamDecorator(
43
67
  (_data, ctx) => {
44
68
  const request = ctx.switchToHttp().getRequest();
@@ -61,6 +85,9 @@ exports.JwtAuthGuard = __decorateClass([
61
85
  var AUTH_MODULE_OPTIONS = "AUTH_MODULE_OPTIONS";
62
86
  var AUTH_HOOKS = "AUTH_HOOKS";
63
87
  var AUTH_REPOSITORY = "AUTH_REPOSITORY";
88
+
89
+ // src/constants/password.constants.ts
90
+ var DUMMY_PASSWORD_HASH = "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy";
64
91
  exports.DefaultAuthHooks = class DefaultAuthHooks {
65
92
  async buildJwtPayload(account) {
66
93
  return {
@@ -75,7 +102,9 @@ exports.DefaultAuthHooks = class DefaultAuthHooks {
75
102
  email: account.email,
76
103
  username: account.username,
77
104
  emailVerified: account.emailVerified,
78
- disabled: account.disabled
105
+ disabled: account.disabled,
106
+ ...account.lastLoginAt != null ? { lastLoginAt: account.lastLoginAt } : {},
107
+ ...account.passwordChangedAt != null ? { passwordChangedAt: account.passwordChangedAt } : {}
79
108
  };
80
109
  }
81
110
  async onBeforeRegister(_input) {
@@ -96,15 +125,21 @@ exports.DefaultAuthHooks = __decorateClass([
96
125
  function isDuplicateKeyError(error) {
97
126
  return !!error && typeof error === "object" && "code" in error && error.code === 11e3;
98
127
  }
99
-
100
- // src/utils/identifier.util.ts
128
+ var COMPLEXITY_PATTERN = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/;
129
+ function assertPasswordComplexity(password) {
130
+ if (!COMPLEXITY_PATTERN.test(password)) {
131
+ throw new common.BadRequestException(
132
+ "Password must contain at least one uppercase letter, one lowercase letter, and one digit"
133
+ );
134
+ }
135
+ }
101
136
  function normalizeIdentifier(value) {
102
137
  return value.trim().toLowerCase();
103
138
  }
104
139
  function resolveRegisterIdentifier(input, field) {
105
140
  const value = field === "email" ? input.email : input.username;
106
141
  if (value == null || value.trim() === "") {
107
- throw new Error(`Register input requires ${field}`);
142
+ throw new common.BadRequestException(`Register input requires ${field}`);
108
143
  }
109
144
  return normalizeIdentifier(value);
110
145
  }
@@ -123,11 +158,15 @@ function expiresAtFromTtlMs(ttlMs) {
123
158
  }
124
159
  var DEFAULT_EMAIL_VERIFICATION_TTL_MS = 24 * 60 * 60 * 1e3;
125
160
  var DEFAULT_PASSWORD_RESET_TTL_MS = 15 * 60 * 1e3;
161
+ var JWT_ALGORITHM = "HS256";
126
162
  exports.TokenService = class TokenService {
127
163
  constructor(jwtService, options) {
128
164
  this.jwtService = jwtService;
129
165
  this.options = options;
130
166
  }
167
+ get bcryptRounds() {
168
+ return this.options.bcryptRounds ?? 10;
169
+ }
131
170
  async signTokens(payload) {
132
171
  const accessExpiresIn = this.options.expiresIn ?? "1h";
133
172
  const refreshExpiresIn = this.options.refreshExpiresIn ?? "7d";
@@ -136,14 +175,16 @@ exports.TokenService = class TokenService {
136
175
  payload,
137
176
  {
138
177
  secret: this.options.secret,
139
- expiresIn: accessExpiresIn
178
+ expiresIn: accessExpiresIn,
179
+ algorithm: JWT_ALGORITHM
140
180
  }
141
181
  ),
142
182
  this.jwtService.signAsync(
143
183
  payload,
144
184
  {
145
185
  secret: this.options.refreshSecret,
146
- expiresIn: refreshExpiresIn
186
+ expiresIn: refreshExpiresIn,
187
+ algorithm: JWT_ALGORITHM
147
188
  }
148
189
  )
149
190
  ]);
@@ -151,11 +192,12 @@ exports.TokenService = class TokenService {
151
192
  }
152
193
  async verifyRefreshToken(refreshToken) {
153
194
  return this.jwtService.verifyAsync(refreshToken, {
154
- secret: this.options.refreshSecret
195
+ secret: this.options.refreshSecret,
196
+ algorithms: [JWT_ALGORITHM]
155
197
  });
156
198
  }
157
199
  async hashRefreshToken(refreshToken) {
158
- return bcrypt2__namespace.hash(refreshToken, 10);
200
+ return bcrypt2__namespace.hash(refreshToken, this.bcryptRounds);
159
201
  }
160
202
  async compareRefreshToken(refreshToken, hash3) {
161
203
  return bcrypt2__namespace.compare(refreshToken, hash3);
@@ -187,6 +229,15 @@ exports.AuthService = class AuthService {
187
229
  get rotateRefreshToken() {
188
230
  return this.options.features?.refreshTokenRotation !== false;
189
231
  }
232
+ get bcryptRounds() {
233
+ return this.options.bcryptRounds ?? 10;
234
+ }
235
+ get accountLockoutEnabled() {
236
+ return this.options.features?.accountLockout === true;
237
+ }
238
+ get lockoutOptions() {
239
+ return this.options.lockout;
240
+ }
190
241
  resolveLoginIdentifier(dto) {
191
242
  const value = this.identifierField === "email" ? dto.email : dto.username;
192
243
  if (value == null || value.trim() === "") {
@@ -204,7 +255,8 @@ exports.AuthService = class AuthService {
204
255
  await this.hooks.onBeforeRegister?.(input);
205
256
  resolveRegisterIdentifier(input, this.identifierField);
206
257
  this.assertRegisterEmailWhenVerificationEnabled(input);
207
- const passwordHash = await bcrypt2__namespace.hash(dto.password, 10);
258
+ this.assertPasswordPolicy(dto.password);
259
+ const passwordHash = await bcrypt2__namespace.hash(dto.password, this.bcryptRounds);
208
260
  try {
209
261
  const account = await this.authRepository.create({
210
262
  ...input,
@@ -217,7 +269,7 @@ exports.AuthService = class AuthService {
217
269
  }
218
270
  } catch (error) {
219
271
  if (isDuplicateKeyError(error)) {
220
- throw new common.UnauthorizedException(`${this.identifierField} already exists`);
272
+ return { registered: true };
221
273
  }
222
274
  throw error;
223
275
  }
@@ -228,17 +280,22 @@ exports.AuthService = class AuthService {
228
280
  const account = await this.authRepository.findByIdentifierWithSecrets(
229
281
  identifier
230
282
  );
231
- if (account?.passwordHash == null) {
232
- throw new common.UnauthorizedException("Invalid credentials");
283
+ if (account != null) {
284
+ this.assertAccountNotLocked(account);
233
285
  }
234
- this.assertAccountActive(account);
235
- const passwordMatches = await bcrypt2__namespace.compare(
236
- dto.password,
237
- account.passwordHash
238
- );
239
- if (!passwordMatches) {
240
- throw new common.UnauthorizedException("Invalid credentials");
286
+ const passwordHash = account?.passwordHash ?? DUMMY_PASSWORD_HASH;
287
+ const passwordMatches = await bcrypt2__namespace.compare(dto.password, passwordHash);
288
+ if (account?.passwordHash == null || !passwordMatches) {
289
+ if (account != null && this.accountLockoutEnabled) {
290
+ await this.authRepository.recordLoginFailure(
291
+ account.id,
292
+ this.lockoutOptions
293
+ );
294
+ }
295
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_CREDENTIALS);
241
296
  }
297
+ this.assertAccountActive(account);
298
+ await this.authRepository.recordLoginSuccess(account.id);
242
299
  return this.issueTokens(account);
243
300
  }
244
301
  async refresh(refreshToken) {
@@ -246,19 +303,25 @@ exports.AuthService = class AuthService {
246
303
  try {
247
304
  payload = await this.tokenService.verifyRefreshToken(refreshToken);
248
305
  } catch {
249
- throw new common.UnauthorizedException("Invalid refresh token");
306
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
250
307
  }
251
308
  const account = await this.authRepository.findByIdWithSecrets(payload.sub);
252
- if (account?.refreshTokenHash == null) {
253
- throw new common.UnauthorizedException("Invalid refresh token");
309
+ if (account == null) {
310
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
254
311
  }
255
312
  this.assertAccountActive(account);
256
- const tokenMatches = await this.tokenService.compareRefreshToken(
257
- refreshToken,
258
- account.refreshTokenHash
259
- );
260
- if (!tokenMatches) {
261
- throw new common.UnauthorizedException("Invalid refresh token");
313
+ if (this.rotateRefreshToken) {
314
+ if (account.refreshTokenHash == null) {
315
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_REFRESH_TOKEN);
316
+ }
317
+ const tokenMatches = await this.tokenService.compareRefreshToken(
318
+ refreshToken,
319
+ account.refreshTokenHash
320
+ );
321
+ if (!tokenMatches) {
322
+ await this.authRepository.updateRefreshTokenHash(account.id, null);
323
+ throw new common.UnauthorizedException(AuthErrorCode.REFRESH_TOKEN_REUSE);
324
+ }
262
325
  }
263
326
  return this.issueTokens(account);
264
327
  }
@@ -281,7 +344,7 @@ exports.AuthService = class AuthService {
281
344
  const tokenHash = hashToken(token);
282
345
  const account = await this.authRepository.findByEmailVerificationTokenHash(tokenHash);
283
346
  if (account == null) {
284
- throw new common.BadRequestException("TOKEN_INVALID_OR_EXPIRED");
347
+ throw new common.BadRequestException(AuthErrorCode.TOKEN_INVALID_OR_EXPIRED);
285
348
  }
286
349
  await this.authRepository.markEmailVerified(account.id);
287
350
  return { verified: true };
@@ -307,20 +370,55 @@ exports.AuthService = class AuthService {
307
370
  const tokenHash = hashToken(token);
308
371
  const account = await this.authRepository.findByResetTokenHash(tokenHash);
309
372
  if (account == null) {
310
- throw new common.BadRequestException("TOKEN_INVALID_OR_EXPIRED");
373
+ throw new common.BadRequestException(AuthErrorCode.TOKEN_INVALID_OR_EXPIRED);
311
374
  }
312
- const passwordHash = await bcrypt2__namespace.hash(newPassword, 10);
375
+ this.assertPasswordPolicy(newPassword);
376
+ const passwordHash = await bcrypt2__namespace.hash(newPassword, this.bcryptRounds);
313
377
  await this.authRepository.updatePasswordHash(account.id, passwordHash);
314
378
  await this.authRepository.clearResetToken(account.id);
315
379
  await this.authRepository.updateRefreshTokenHash(account.id, null);
316
380
  return { reset: true };
317
381
  }
382
+ async changePassword(authId, currentPassword, newPassword) {
383
+ const account = await this.authRepository.findByIdWithSecrets(authId);
384
+ if (account?.passwordHash == null) {
385
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_CURRENT_PASSWORD);
386
+ }
387
+ const currentMatches = await bcrypt2__namespace.compare(
388
+ currentPassword,
389
+ account.passwordHash
390
+ );
391
+ if (!currentMatches) {
392
+ throw new common.UnauthorizedException(AuthErrorCode.INVALID_CURRENT_PASSWORD);
393
+ }
394
+ if (currentPassword === newPassword) {
395
+ throw new common.BadRequestException(AuthErrorCode.PASSWORD_UNCHANGED);
396
+ }
397
+ this.assertPasswordPolicy(newPassword);
398
+ const passwordHash = await bcrypt2__namespace.hash(newPassword, this.bcryptRounds);
399
+ await this.authRepository.updatePasswordHash(account.id, passwordHash);
400
+ await this.authRepository.updateRefreshTokenHash(account.id, null);
401
+ return { changed: true };
402
+ }
403
+ assertAccountNotLocked(account) {
404
+ if (!this.accountLockoutEnabled || account.lockedUntil == null) {
405
+ return;
406
+ }
407
+ if (account.lockedUntil > /* @__PURE__ */ new Date()) {
408
+ throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_LOCKED);
409
+ }
410
+ }
318
411
  assertAccountActive(account) {
319
412
  if (account.disabled) {
320
- throw new common.UnauthorizedException("ACCOUNT_DISABLED");
413
+ throw new common.UnauthorizedException(AuthErrorCode.ACCOUNT_DISABLED);
321
414
  }
322
415
  if (this.emailVerificationEnabled && !account.emailVerified) {
323
- throw new common.UnauthorizedException("EMAIL_NOT_VERIFIED");
416
+ throw new common.UnauthorizedException(AuthErrorCode.EMAIL_NOT_VERIFIED);
417
+ }
418
+ }
419
+ assertPasswordPolicy(password) {
420
+ if (this.options.passwordComplexity === true) {
421
+ assertPasswordComplexity(password);
324
422
  }
325
423
  }
326
424
  async issueTokens(account) {
@@ -436,6 +534,13 @@ var AuthController = class {
436
534
  resetPassword(dto) {
437
535
  return this.authService.resetPassword(dto.token, dto.newPassword);
438
536
  }
537
+ changePassword(user, dto) {
538
+ return this.authService.changePassword(
539
+ user.sub,
540
+ dto.currentPassword,
541
+ dto.newPassword
542
+ );
543
+ }
439
544
  };
440
545
  __decorateClass([
441
546
  common.Post("register"),
@@ -476,17 +581,39 @@ __decorateClass([
476
581
  common.HttpCode(common.HttpStatus.OK),
477
582
  __decorateParam(0, common.Body())
478
583
  ], AuthController.prototype, "resetPassword", 1);
584
+ __decorateClass([
585
+ common.Post("change-password"),
586
+ common.UseGuards(exports.JwtAuthGuard),
587
+ common.HttpCode(common.HttpStatus.OK),
588
+ __decorateParam(0, CurrentUser()),
589
+ __decorateParam(1, common.Body())
590
+ ], AuthController.prototype, "changePassword", 1);
479
591
  AuthController = __decorateClass([
480
592
  common.Controller("auth"),
481
593
  __decorateParam(0, common.Inject(exports.AuthService))
482
594
  ], AuthController);
595
+
596
+ // src/controllers/auth.controller.factory.ts
597
+ function createAuthController(routePrefix = "auth") {
598
+ let ConfiguredAuthController = class extends AuthController {
599
+ };
600
+ ConfiguredAuthController = __decorateClass([
601
+ common.Controller(routePrefix)
602
+ ], ConfiguredAuthController);
603
+ Object.defineProperty(ConfiguredAuthController, "name", {
604
+ value: `AuthController_${routePrefix.replace(/\W+/g, "_")}`
605
+ });
606
+ return ConfiguredAuthController;
607
+ }
483
608
  var JwtStrategy = class extends passport.PassportStrategy(passportJwt.Strategy) {
484
609
  constructor(options, authRepository) {
485
610
  super({
486
611
  jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
487
612
  ignoreExpiration: false,
488
- secretOrKey: options.secret
613
+ secretOrKey: options.secret,
614
+ algorithms: ["HS256"]
489
615
  });
616
+ this.options = options;
490
617
  this.authRepository = authRepository;
491
618
  }
492
619
  async validate(payload) {
@@ -494,6 +621,9 @@ var JwtStrategy = class extends passport.PassportStrategy(passportJwt.Strategy)
494
621
  if (account == null || account.disabled) {
495
622
  throw new common.UnauthorizedException("Account not found or inactive");
496
623
  }
624
+ if (this.options.features?.emailVerification === true && !account.emailVerified) {
625
+ throw new common.UnauthorizedException(AuthErrorCode.EMAIL_NOT_VERIFIED);
626
+ }
497
627
  return payload;
498
628
  }
499
629
  };
@@ -503,27 +633,82 @@ JwtStrategy = __decorateClass([
503
633
  __decorateParam(1, common.Inject(AUTH_REPOSITORY))
504
634
  ], JwtStrategy);
505
635
 
636
+ // src/utils/hooks-provider.util.ts
637
+ function createHooksProvider(options) {
638
+ if (options.hooksProvider != null) {
639
+ return options.hooksProvider;
640
+ }
641
+ const HooksClass = options.hooks ?? exports.DefaultAuthHooks;
642
+ return {
643
+ provide: AUTH_HOOKS,
644
+ useClass: HooksClass
645
+ };
646
+ }
647
+
648
+ // src/utils/validate-auth-config.util.ts
649
+ var MIN_SECRET_LENGTH = 32;
650
+ var MIN_BCRYPT_ROUNDS = 10;
651
+ var MAX_BCRYPT_ROUNDS = 14;
652
+ function validateAuthModuleOptions(options) {
653
+ if (options.secret.length < MIN_SECRET_LENGTH) {
654
+ throw new Error(
655
+ `AuthModule: secret must be at least ${MIN_SECRET_LENGTH} characters`
656
+ );
657
+ }
658
+ if (options.refreshSecret.length < MIN_SECRET_LENGTH) {
659
+ throw new Error(
660
+ `AuthModule: refreshSecret must be at least ${MIN_SECRET_LENGTH} characters`
661
+ );
662
+ }
663
+ if (options.secret === options.refreshSecret) {
664
+ throw new Error(
665
+ "AuthModule: secret and refreshSecret must be different"
666
+ );
667
+ }
668
+ const rounds = options.bcryptRounds ?? MIN_BCRYPT_ROUNDS;
669
+ if (rounds < MIN_BCRYPT_ROUNDS || rounds > MAX_BCRYPT_ROUNDS) {
670
+ throw new Error(
671
+ `AuthModule: bcryptRounds must be between ${MIN_BCRYPT_ROUNDS} and ${MAX_BCRYPT_ROUNDS}`
672
+ );
673
+ }
674
+ if (options.emailVerificationTokenTtlMs != null && options.emailVerificationTokenTtlMs < 6e4) {
675
+ throw new Error(
676
+ "AuthModule: emailVerificationTokenTtlMs must be at least 60000 (1 minute)"
677
+ );
678
+ }
679
+ if (options.passwordResetTokenTtlMs != null && options.passwordResetTokenTtlMs < 6e4) {
680
+ throw new Error(
681
+ "AuthModule: passwordResetTokenTtlMs must be at least 60000 (1 minute)"
682
+ );
683
+ }
684
+ }
685
+
506
686
  // src/auth.module.ts
507
- function createAuthProviders(options) {
687
+ function createCoreProviders(options) {
688
+ validateAuthModuleOptions(options);
508
689
  return [
509
690
  {
510
691
  provide: AUTH_MODULE_OPTIONS,
511
692
  useValue: options
512
693
  },
513
- {
514
- provide: AUTH_HOOKS,
515
- inject: [AUTH_MODULE_OPTIONS],
516
- useFactory: (opts) => {
517
- const HooksClass = opts.hooks ?? exports.DefaultAuthHooks;
518
- return new HooksClass();
519
- }
520
- },
694
+ createHooksProvider(options),
521
695
  exports.AuthService,
522
696
  exports.TokenService,
523
697
  JwtStrategy,
524
698
  exports.JwtAuthGuard
525
699
  ];
526
700
  }
701
+ function createAsyncHooksProvider(options) {
702
+ if (options.hooksProvider != null) {
703
+ return options.hooksProvider;
704
+ }
705
+ const HooksClass = options.hooks ?? exports.DefaultAuthHooks;
706
+ return {
707
+ provide: AUTH_HOOKS,
708
+ inject: [core.ModuleRef],
709
+ useFactory: (moduleRef) => moduleRef.create(HooksClass)
710
+ };
711
+ }
527
712
  function createAuthImports() {
528
713
  return [
529
714
  passport.PassportModule.register({ defaultStrategy: "jwt" }),
@@ -531,7 +716,10 @@ function createAuthImports() {
531
716
  inject: [AUTH_MODULE_OPTIONS],
532
717
  useFactory: (opts) => ({
533
718
  secret: opts.secret,
534
- signOptions: { expiresIn: opts.expiresIn ?? "1h" }
719
+ signOptions: {
720
+ expiresIn: opts.expiresIn ?? "1h",
721
+ algorithm: "HS256"
722
+ }
535
723
  })
536
724
  })
537
725
  ];
@@ -543,14 +731,33 @@ function mergeImports(userImports) {
543
731
  }
544
732
  return merged;
545
733
  }
734
+ function createAsyncProviders(options) {
735
+ return [
736
+ {
737
+ provide: AUTH_MODULE_OPTIONS,
738
+ inject: options.inject ?? [],
739
+ useFactory: async (...args) => {
740
+ const config = await options.useFactory(...args);
741
+ validateAuthModuleOptions(config);
742
+ return config;
743
+ }
744
+ },
745
+ createAsyncHooksProvider(options),
746
+ exports.AuthService,
747
+ exports.TokenService,
748
+ JwtStrategy,
749
+ exports.JwtAuthGuard
750
+ ];
751
+ }
546
752
  exports.AuthModule = class AuthModule {
547
753
  static forRoot(options) {
754
+ const routePrefix = options.routePrefix ?? "auth";
548
755
  return {
549
756
  module: exports.AuthModule,
550
757
  global: true,
551
758
  imports: createAuthImports(),
552
- controllers: [AuthController],
553
- providers: createAuthProviders(options),
759
+ controllers: [createAuthController(routePrefix)],
760
+ providers: createCoreProviders(options),
554
761
  exports: [
555
762
  AUTH_MODULE_OPTIONS,
556
763
  AUTH_HOOKS,
@@ -563,30 +770,13 @@ exports.AuthModule = class AuthModule {
563
770
  };
564
771
  }
565
772
  static forRootAsync(options) {
773
+ const routePrefix = options.routePrefix ?? "auth";
566
774
  return {
567
775
  module: exports.AuthModule,
568
776
  global: true,
569
777
  imports: mergeImports(options.imports),
570
- controllers: [AuthController],
571
- providers: [
572
- {
573
- provide: AUTH_MODULE_OPTIONS,
574
- inject: options.inject ?? [],
575
- useFactory: options.useFactory
576
- },
577
- {
578
- provide: AUTH_HOOKS,
579
- inject: [AUTH_MODULE_OPTIONS],
580
- useFactory: (opts) => {
581
- const HooksClass = opts.hooks ?? exports.DefaultAuthHooks;
582
- return new HooksClass();
583
- }
584
- },
585
- exports.AuthService,
586
- exports.TokenService,
587
- JwtStrategy,
588
- exports.JwtAuthGuard
589
- ],
778
+ controllers: [createAuthController(routePrefix)],
779
+ providers: createAsyncProviders(options),
590
780
  exports: [
591
781
  AUTH_MODULE_OPTIONS,
592
782
  AUTH_HOOKS,
@@ -606,6 +796,17 @@ exports.AuthModule = __decorateClass([
606
796
  // src/dto/auth-tokens.dto.ts
607
797
  var AuthTokensDto = class {
608
798
  };
799
+ var ChangePasswordDto = class {
800
+ };
801
+ __decorateClass([
802
+ classValidator.IsString(),
803
+ classValidator.IsNotEmpty()
804
+ ], ChangePasswordDto.prototype, "currentPassword", 2);
805
+ __decorateClass([
806
+ classValidator.IsString(),
807
+ classValidator.IsNotEmpty(),
808
+ classValidator.Length(8, 128)
809
+ ], ChangePasswordDto.prototype, "newPassword", 2);
609
810
  var ForgotPasswordDto = class {
610
811
  };
611
812
  __decorateClass([
@@ -615,7 +816,8 @@ var LoginDto = class {
615
816
  };
616
817
  __decorateClass([
617
818
  classValidator.IsOptional(),
618
- classValidator.IsString(),
819
+ classValidator.ValidateIf((dto) => dto.email != null && dto.email.trim() !== ""),
820
+ classValidator.IsEmail(),
619
821
  classValidator.Length(3, 255)
620
822
  ], LoginDto.prototype, "email", 2);
621
823
  __decorateClass([
@@ -642,7 +844,8 @@ var RegisterDto = class {
642
844
  };
643
845
  __decorateClass([
644
846
  classValidator.IsOptional(),
645
- classValidator.IsString(),
847
+ classValidator.ValidateIf((dto) => dto.email != null && dto.email.trim() !== ""),
848
+ classValidator.IsEmail(),
646
849
  classValidator.Length(3, 255)
647
850
  ], RegisterDto.prototype, "email", 2);
648
851
  __decorateClass([
@@ -676,8 +879,11 @@ __decorateClass([
676
879
 
677
880
  exports.AUTH_HOOKS = AUTH_HOOKS;
678
881
  exports.AUTH_MODULE_OPTIONS = AUTH_MODULE_OPTIONS;
882
+ exports.AUTH_RATE_LIMIT_PRESETS = AUTH_RATE_LIMIT_PRESETS;
679
883
  exports.AUTH_REPOSITORY = AUTH_REPOSITORY;
884
+ exports.AuthErrorCode = AuthErrorCode;
680
885
  exports.AuthTokensDto = AuthTokensDto;
886
+ exports.ChangePasswordDto = ChangePasswordDto;
681
887
  exports.CurrentUser = CurrentUser;
682
888
  exports.ForgotPasswordDto = ForgotPasswordDto;
683
889
  exports.LoginDto = LoginDto;