cca-auth-module 0.2.0 → 0.2.2

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.
@@ -4,5 +4,5 @@ export declare class LogoutUseCase implements IBaseService {
4
4
  private readonly repository;
5
5
  constructor(repository: AuthRepository);
6
6
  initialize(): Promise<void>;
7
- execute(authId: string): Promise<void>;
7
+ execute(userId: string | undefined): Promise<void>;
8
8
  }
@@ -1,8 +1,8 @@
1
1
  import { AdminEntity, UserEntity, UserRole } from "cca-entities";
2
2
  import { IDecodedToken } from "./IDecodedToken";
3
3
  export interface IAuthService {
4
- generateAccessToken(user: UserEntity | AdminEntity, role: UserRole): string;
4
+ generateAccessToken(user: UserEntity | AdminEntity, role: UserRole, twoFactorAuthenticated?: boolean): string;
5
5
  generateRefreshToken(user: UserEntity | AdminEntity): string;
6
6
  verifyAccessToken(token: string): Promise<IDecodedToken>;
7
- verifyRefreshToken(token: string): IDecodedToken;
7
+ verifyRefreshToken(token: string): Promise<IDecodedToken>;
8
8
  }
@@ -3,4 +3,5 @@ export interface IDecodedToken extends JwtPayload {
3
3
  userId?: string;
4
4
  email?: string;
5
5
  role?: string;
6
+ twoFactorAuthenticated?: boolean;
6
7
  }
@@ -1,9 +1,9 @@
1
- import { AuthEntity, UserEntity, UserRole } from "cca-entities";
1
+ import { AdminEntity, AuthEntity, UserEntity, UserRole } from "cca-entities";
2
2
  import { IDecodedToken } from "./IDecodedToken";
3
3
  export interface IJwtAuth {
4
4
  validateUser(email: string, password: string): Promise<AuthEntity | null>;
5
- generateAccessToken(user: UserEntity, role: UserRole): string;
6
- generateRefreshToken(user: UserEntity): string;
5
+ generateAccessToken(user: UserEntity | AdminEntity, role: UserRole, twoFactorAuthenticated?: boolean): string;
6
+ generateRefreshToken(user: UserEntity | AdminEntity): string;
7
7
  verifyAccessToken(token: string): Promise<IDecodedToken>;
8
- verifyRefreshToken(token: string): IDecodedToken;
8
+ verifyRefreshToken(token: string): Promise<IDecodedToken>;
9
9
  }
@@ -4,4 +4,5 @@ export interface IJwtPayload {
4
4
  role: string;
5
5
  iat: number;
6
6
  exp: number;
7
+ twoFactorAuthenticated?: boolean;
7
8
  }
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BaseRepository, IExtendedBaseRepository, IBaseService, BaseDatabase, BaseContainer } from 'cca-core';
2
2
  import { Request, Response, NextFunction } from 'express';
3
- import { AuthEntity, UserRole, UserEntity, AdminEntity } from 'cca-entities';
3
+ import { AuthEntity, UserEntity, AdminEntity, UserRole } from 'cca-entities';
4
4
  import { Repository } from 'typeorm';
5
5
  import * as jwt from 'jsonwebtoken';
6
6
  import { JwtPayload } from 'jsonwebtoken';
@@ -32,6 +32,7 @@ declare class AuthRepository extends BaseRepository<AuthEntity> implements IExte
32
32
  disableTwoFactor(auth: AuthEntity): Promise<void>;
33
33
  isTwoFactorEnabled(userId: string): Promise<boolean>;
34
34
  getTwoFactorSecret(userId: string): Promise<string | null>;
35
+ saveAccount(account: UserEntity | AdminEntity): Promise<void>;
35
36
  }
36
37
 
37
38
  declare class RegisterUseCase implements IBaseService {
@@ -64,24 +65,24 @@ interface IDecodedToken extends JwtPayload {
64
65
  userId?: string;
65
66
  email?: string;
66
67
  role?: string;
68
+ twoFactorAuthenticated?: boolean;
67
69
  }
68
70
 
69
71
  interface IAuthService {
70
- generateAccessToken(user: UserEntity | AdminEntity, role: UserRole): string;
72
+ generateAccessToken(user: UserEntity | AdminEntity, role: UserRole, twoFactorAuthenticated?: boolean): string;
71
73
  generateRefreshToken(user: UserEntity | AdminEntity): string;
72
74
  verifyAccessToken(token: string): Promise<IDecodedToken>;
73
- verifyRefreshToken(token: string): IDecodedToken;
75
+ verifyRefreshToken(token: string): Promise<IDecodedToken>;
74
76
  }
75
77
 
76
78
  declare class JwtAuthService implements IBaseService, IAuthService {
77
79
  private readonly repository;
78
80
  private jwtConfig;
79
81
  constructor(repository: AuthRepository, config?: IJwtConfig);
80
- private loadConfig;
81
82
  initialize(): Promise<void>;
82
83
  private validateConfiguration;
83
84
  private verifyJwtConfig;
84
- generateAccessToken(user: UserEntity | AdminEntity, role: UserRole): string;
85
+ generateAccessToken(user: UserEntity | AdminEntity, role: UserRole, twoFactorAuthenticated?: boolean): string;
85
86
  generateRefreshToken(user: UserEntity | AdminEntity): string;
86
87
  verifyToken(token: string, secret: string): Promise<IDecodedToken>;
87
88
  verifyAccessToken(token: string): Promise<IDecodedToken>;
@@ -105,7 +106,7 @@ declare class LogoutUseCase implements IBaseService {
105
106
  private readonly repository;
106
107
  constructor(repository: AuthRepository);
107
108
  initialize(): Promise<void>;
108
- execute(authId: string): Promise<void>;
109
+ execute(userId: string | undefined): Promise<void>;
109
110
  }
110
111
 
111
112
  interface ITokenPair {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BaseRepository, IExtendedBaseRepository, IBaseService, BaseDatabase, BaseContainer } from 'cca-core';
2
2
  import { Request, Response, NextFunction } from 'express';
3
- import { AuthEntity, UserRole, UserEntity, AdminEntity } from 'cca-entities';
3
+ import { AuthEntity, UserEntity, AdminEntity, UserRole } from 'cca-entities';
4
4
  import { Repository } from 'typeorm';
5
5
  import * as jwt from 'jsonwebtoken';
6
6
  import { JwtPayload } from 'jsonwebtoken';
@@ -32,6 +32,7 @@ declare class AuthRepository extends BaseRepository<AuthEntity> implements IExte
32
32
  disableTwoFactor(auth: AuthEntity): Promise<void>;
33
33
  isTwoFactorEnabled(userId: string): Promise<boolean>;
34
34
  getTwoFactorSecret(userId: string): Promise<string | null>;
35
+ saveAccount(account: UserEntity | AdminEntity): Promise<void>;
35
36
  }
36
37
 
37
38
  declare class RegisterUseCase implements IBaseService {
@@ -64,24 +65,24 @@ interface IDecodedToken extends JwtPayload {
64
65
  userId?: string;
65
66
  email?: string;
66
67
  role?: string;
68
+ twoFactorAuthenticated?: boolean;
67
69
  }
68
70
 
69
71
  interface IAuthService {
70
- generateAccessToken(user: UserEntity | AdminEntity, role: UserRole): string;
72
+ generateAccessToken(user: UserEntity | AdminEntity, role: UserRole, twoFactorAuthenticated?: boolean): string;
71
73
  generateRefreshToken(user: UserEntity | AdminEntity): string;
72
74
  verifyAccessToken(token: string): Promise<IDecodedToken>;
73
- verifyRefreshToken(token: string): IDecodedToken;
75
+ verifyRefreshToken(token: string): Promise<IDecodedToken>;
74
76
  }
75
77
 
76
78
  declare class JwtAuthService implements IBaseService, IAuthService {
77
79
  private readonly repository;
78
80
  private jwtConfig;
79
81
  constructor(repository: AuthRepository, config?: IJwtConfig);
80
- private loadConfig;
81
82
  initialize(): Promise<void>;
82
83
  private validateConfiguration;
83
84
  private verifyJwtConfig;
84
- generateAccessToken(user: UserEntity | AdminEntity, role: UserRole): string;
85
+ generateAccessToken(user: UserEntity | AdminEntity, role: UserRole, twoFactorAuthenticated?: boolean): string;
85
86
  generateRefreshToken(user: UserEntity | AdminEntity): string;
86
87
  verifyToken(token: string, secret: string): Promise<IDecodedToken>;
87
88
  verifyAccessToken(token: string): Promise<IDecodedToken>;
@@ -105,7 +106,7 @@ declare class LogoutUseCase implements IBaseService {
105
106
  private readonly repository;
106
107
  constructor(repository: AuthRepository);
107
108
  initialize(): Promise<void>;
108
- execute(authId: string): Promise<void>;
109
+ execute(userId: string | undefined): Promise<void>;
109
110
  }
110
111
 
111
112
  interface ITokenPair {
package/dist/index.js CHANGED
@@ -174,6 +174,7 @@ var import_jwt_decode = require("jwt-decode");
174
174
  var yup = __toESM(require("yup"));
175
175
  var import_cca_entities = require("cca-entities");
176
176
  var import_bcrypt = __toESM(require("bcrypt"));
177
+ var import_crypto = __toESM(require("crypto"));
177
178
  var schemas = {
178
179
  id: yup.string().uuid("Invalid user ID format"),
179
180
  email: yup.string().email("Invalid email format").max(255, "Email cannot exceed 255 characters"),
@@ -186,8 +187,9 @@ var schemas = {
186
187
  };
187
188
  var validateEmail = /* @__PURE__ */ __name(async (email, repository) => {
188
189
  try {
189
- await schemas.email.validate(email?.trim().toLowerCase());
190
- const user = await repository.findByEmail(email);
190
+ const normalizedEmail = email?.trim().toLowerCase();
191
+ await schemas.email.validate(normalizedEmail);
192
+ const user = await repository.findByEmail(normalizedEmail);
191
193
  if (!user) {
192
194
  throw new NotFoundError(
193
195
  "The email address or password is incorrect. Please retry"
@@ -209,8 +211,9 @@ var validatePassword = /* @__PURE__ */ __name(async (password) => {
209
211
  }, "validatePassword");
210
212
  var validateEmailUniqueness = /* @__PURE__ */ __name(async (repository, email, excludeUserId) => {
211
213
  try {
212
- await schemas.email.validate(email?.trim().toLowerCase());
213
- const existingUser = await repository.findByEmail(email);
214
+ const normalizedEmail = email?.trim().toLowerCase();
215
+ await schemas.email.validate(normalizedEmail);
216
+ const existingUser = await repository.findByEmail(normalizedEmail);
214
217
  if (!existingUser) return;
215
218
  if (existingUser.id === excludeUserId) return;
216
219
  throw new ValidationError(`Email ${email} is already in use.`);
@@ -255,7 +258,14 @@ var validateAdminSecret = /* @__PURE__ */ __name(async (secretPassword) => {
255
258
  if (!config.adminSecretPassword) {
256
259
  throw new ValidationError("ADMIN_SECRET_PASSWORD not found in config");
257
260
  }
258
- if (parseInt(secretPassword) !== parseInt(config.adminSecretPassword)) {
261
+ const provided = secretPassword.trim();
262
+ const expected = config.adminSecretPassword.trim();
263
+ if (provided.length !== expected.length) {
264
+ throw new ValidationError("Invalid admin password");
265
+ }
266
+ const providedBuf = Buffer.from(provided);
267
+ const expectedBuf = Buffer.from(expected);
268
+ if (!import_crypto.default.timingSafeEqual(providedBuf, expectedBuf)) {
259
269
  throw new ValidationError("Invalid admin password");
260
270
  }
261
271
  } catch (error) {
@@ -285,8 +295,9 @@ var _LoginUseCase = class _LoginUseCase {
285
295
  if (!account) {
286
296
  throw new NotFoundError(`${isAdmin ? "Admin" : "User"} account not found or inactive`);
287
297
  }
288
- const accessToken = this.jwtService.generateAccessToken(account, auth.role);
289
- const expiresAt = (0, import_jwt_decode.jwtDecode)(accessToken).exp;
298
+ const accessToken = this.jwtService.generateAccessToken(account, auth.role, false);
299
+ const decoded = (0, import_jwt_decode.jwtDecode)(accessToken);
300
+ const expiresAt = decoded.exp ?? 0;
290
301
  return { id: account.id, accessToken, expiresAt, enabled: auth.twoFactorEnabled };
291
302
  }
292
303
  };
@@ -302,11 +313,17 @@ var _LogoutUseCase = class _LogoutUseCase {
302
313
  async initialize() {
303
314
  await (0, import_cca_core2.validateRepository)(this.repository, (repo) => repo.getAll());
304
315
  }
305
- async execute(authId) {
316
+ async execute(userId) {
306
317
  try {
307
- await this.repository.logout(authId);
318
+ if (!userId) {
319
+ throw new NotFoundError("User ID is required");
320
+ }
321
+ await this.repository.logout(userId);
308
322
  } catch (error) {
309
- new NotFoundError("Auth not found");
323
+ if (error instanceof NotFoundError) {
324
+ throw error;
325
+ }
326
+ throw new NotFoundError("Auth not found");
310
327
  }
311
328
  }
312
329
  };
@@ -478,7 +495,11 @@ var _RegisterUseCase = class _RegisterUseCase {
478
495
  const authEntity = mapper.map(dto, RegisterDTO, import_cca_entities3.AuthEntity);
479
496
  const userOrAdminEntity = isAdmin ? mapper.map(dto, RegisterDTO, import_cca_entities3.AdminEntity) : mapper.map(dto, RegisterDTO, import_cca_entities3.UserEntity);
480
497
  userOrAdminEntity.updatedAt = void 0;
481
- authEntity.user = userOrAdminEntity;
498
+ if (isAdmin) {
499
+ authEntity.admin = userOrAdminEntity;
500
+ } else {
501
+ authEntity.user = userOrAdminEntity;
502
+ }
482
503
  authEntity.password = hashedPassword;
483
504
  authEntity.refreshToken = "";
484
505
  return authEntity;
@@ -499,18 +520,23 @@ var _RefreshTokenUseCase = class _RefreshTokenUseCase {
499
520
  }
500
521
  async execute(refreshToken) {
501
522
  try {
523
+ if (!refreshToken) return null;
502
524
  const decoded = await this.service.verifyRefreshToken(refreshToken);
503
525
  if (!decoded.userId) return null;
504
- const authEntity = await this.repository.findByUseAdminId(decoded.userId);
526
+ const authEntity = await this.repository.findByUserOrAdminId(decoded.userId);
505
527
  if (!authEntity) return null;
528
+ if (!authEntity.refreshToken || authEntity.refreshToken !== refreshToken) return null;
506
529
  const account = authEntity.user ?? authEntity.admin;
507
530
  if (!account) return null;
508
- const accessToken = this.service.generateAccessToken(account, authEntity.role);
531
+ const accessToken = this.service.generateAccessToken(
532
+ account,
533
+ authEntity.role,
534
+ !!authEntity.twoFactorEnabled
535
+ );
509
536
  const newRefreshToken = this.service.generateRefreshToken(account);
510
537
  await this.repository.update(authEntity.id, { refreshToken: newRefreshToken });
511
538
  return { accessToken, refreshToken: newRefreshToken };
512
539
  } catch (error) {
513
- console.error("Refresh token failed:", error);
514
540
  return null;
515
541
  }
516
542
  }
@@ -576,6 +602,9 @@ var _TwoFactorEnableUseCase = class _TwoFactorEnableUseCase {
576
602
  if (!token) {
577
603
  throw new TwoFactorError("Token is required");
578
604
  }
605
+ if (!userId) {
606
+ throw new TwoFactorError("User ID is required");
607
+ }
579
608
  const auth = await this.authRepository.findByUserOrAdminId(userId);
580
609
  if (!auth || !auth.twoFactorSecret) {
581
610
  throw new TwoFactorError("Please set up two-factor authentication first");
@@ -658,7 +687,7 @@ var _TwoFactorVerifyUseCase = class _TwoFactorVerifyUseCase {
658
687
  if (!account) throw new NotFoundError("User or Admin account not found for AuthEntity");
659
688
  account.lastLoginAt = /* @__PURE__ */ new Date();
660
689
  account.isActive = true;
661
- await this.authRepository.update(auth.id, auth);
690
+ await this.authRepository.saveAccount(account);
662
691
  }
663
692
  async updateUserRefreshToken(auth, refreshToken) {
664
693
  auth.refreshToken = refreshToken;
@@ -668,7 +697,7 @@ var _TwoFactorVerifyUseCase = class _TwoFactorVerifyUseCase {
668
697
  const account = auth.user ?? auth.admin;
669
698
  if (!account) throw new NotFoundError("User or Admin account not found for AuthEntity");
670
699
  return {
671
- accessToken: this.jwtService.generateAccessToken(account, auth.role),
700
+ accessToken: this.jwtService.generateAccessToken(account, auth.role, true),
672
701
  refreshToken: this.jwtService.generateRefreshToken(account)
673
702
  };
674
703
  }
@@ -690,7 +719,6 @@ var _TwoFactorDisableUseCase = class _TwoFactorDisableUseCase {
690
719
  this.twoFactorService.initialize(),
691
720
  (0, import_cca_core7.validateRepository)(this.authRepository, (repo) => repo.getAll())
692
721
  ]);
693
- 4;
694
722
  this.isInitialized = true;
695
723
  }
696
724
  async execute(userId, dto) {
@@ -698,6 +726,12 @@ var _TwoFactorDisableUseCase = class _TwoFactorDisableUseCase {
698
726
  await this.initialize();
699
727
  }
700
728
  const { token } = dto;
729
+ if (!token) {
730
+ throw new TwoFactorError("Token is required");
731
+ }
732
+ if (!userId) {
733
+ throw new TwoFactorError("User ID is required");
734
+ }
701
735
  const user = await this.authRepository.findByUserOrAdminId(userId);
702
736
  if (!user || !user.twoFactorSecret || !user.twoFactorEnabled) {
703
737
  throw new TwoFactorError("Two-factor authentication is not enabled");
@@ -773,11 +807,13 @@ var _AuthController = class _AuthController {
773
807
  }
774
808
  const result = await this.loginUseCase.execute(loginDTO, adminPassword);
775
809
  const adminLoginData = {
776
- message: result,
810
+ accessToken: result.accessToken,
811
+ userId: result.id,
812
+ expiresAt: result.expiresAt,
777
813
  auth: this.createAuthData(
778
814
  true,
779
- false,
780
- AUTH_STATUS.BASIC_AUTH,
815
+ result.enabled ?? false,
816
+ result.enabled ?? false ? AUTH_STATUS.PENDING_VERIFICATION : AUTH_STATUS.BASIC_AUTH,
781
817
  false
782
818
  )
783
819
  };
@@ -788,7 +824,8 @@ var _AuthController = class _AuthController {
788
824
  }, "adminLogin");
789
825
  this.logout = /* @__PURE__ */ __name(async (req, res, next) => {
790
826
  try {
791
- await this.logoutUseCase.execute(req.body.id);
827
+ const userId = req.auth?.userId ?? req.body.id;
828
+ await this.logoutUseCase.execute(userId);
792
829
  const logoutData = {
793
830
  auth: this.createAuthData(
794
831
  false,
@@ -849,10 +886,10 @@ var _AuthController = class _AuthController {
849
886
  }, "refreshToken");
850
887
  this.setup2FA = /* @__PURE__ */ __name(async (req, res, next) => {
851
888
  try {
852
- if (!req.auth?.id) {
889
+ if (!req.auth?.userId) {
853
890
  throw new ForbiddenError("User authentication required");
854
891
  }
855
- const result = await this.twoFactorSetupUseCase.execute(req.auth.id);
892
+ const result = await this.twoFactorSetupUseCase.execute(req.auth.userId);
856
893
  const setupData = {
857
894
  qrCode: result.qrCodeUrl,
858
895
  auth: this.createAuthData(true, false, AUTH_STATUS.NEEDS_SETUP)
@@ -868,7 +905,10 @@ var _AuthController = class _AuthController {
868
905
  }, "setup2FA");
869
906
  this.enable2FA = /* @__PURE__ */ __name(async (req, res, next) => {
870
907
  try {
871
- const dto = { ...req.body, userId: req.auth?.id };
908
+ if (!req.auth?.userId) {
909
+ throw new ForbiddenError("User authentication required");
910
+ }
911
+ const dto = { ...req.body, userId: req.auth?.userId };
872
912
  await this.twoFactorEnableUseCase.execute(dto);
873
913
  const enableData = {
874
914
  enabledAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -885,16 +925,22 @@ var _AuthController = class _AuthController {
885
925
  }, "enable2FA");
886
926
  this.verify2FA = /* @__PURE__ */ __name(async (req, res, next) => {
887
927
  try {
888
- const dto = req.body;
928
+ if (!req.auth?.userId) {
929
+ throw new ForbiddenError("User authentication required");
930
+ }
931
+ const dto = { ...req.body, userId: req.auth.userId };
889
932
  const result = await this.twoFactorVerifyUseCase.execute(dto);
933
+ if (!result) {
934
+ throw new Error("Two-factor verification failed");
935
+ }
890
936
  const verifyData = {
891
- token: result?.token,
892
- refreshToken: result?.refreshToken,
937
+ token: result.token,
938
+ refreshToken: result.refreshToken,
893
939
  user: {
894
- id: result?.data?.id,
895
- email: result?.data?.email,
896
- name: result?.data?.name,
897
- role: result?.data?.role
940
+ id: result.data?.id,
941
+ email: result.data?.email,
942
+ name: result.data?.name,
943
+ role: result.data?.role
898
944
  },
899
945
  auth: this.createAuthData(true, true, AUTH_STATUS.FULL_AUTH, true)
900
946
  };
@@ -909,7 +955,10 @@ var _AuthController = class _AuthController {
909
955
  }, "verify2FA");
910
956
  this.disable2FA = /* @__PURE__ */ __name(async (req, res, next) => {
911
957
  try {
912
- const userId = req.auth.id;
958
+ const userId = req.auth?.userId;
959
+ if (!userId) {
960
+ throw new ForbiddenError("User authentication required");
961
+ }
913
962
  const dto = req.body;
914
963
  await this.twoFactorDisableUseCase.execute(userId, dto);
915
964
  const disableData = {
@@ -973,11 +1022,14 @@ var _RequireComplete2FA = class _RequireComplete2FA {
973
1022
  return res.status(401).json({ message: "Authentication required" });
974
1023
  }
975
1024
  const decoded = await this.jwtService.verifyAccessToken(token);
1025
+ if (!decoded.userId) {
1026
+ return res.status(401).json({ message: "Invalid token payload" });
1027
+ }
976
1028
  if (!decoded.twoFactorAuthenticated) {
977
1029
  return res.status(403).json({
978
1030
  message: "Two-factor authentication required",
979
1031
  code: "REQUIRE_2FA",
980
- userId: decoded.id
1032
+ userId: decoded.userId
981
1033
  });
982
1034
  }
983
1035
  req.auth = { ...decoded, twoFactorAuthenticated: true };
@@ -1001,7 +1053,14 @@ var _AuthRepository = class _AuthRepository extends import_cca_core8.BaseReposit
1001
1053
  return result;
1002
1054
  }
1003
1055
  async create(entity) {
1004
- return super.create(entity);
1056
+ const now = /* @__PURE__ */ new Date();
1057
+ const auth = this.repository.create({
1058
+ ...entity,
1059
+ createdAt: now,
1060
+ updatedAt: now,
1061
+ isDeleted: false
1062
+ });
1063
+ return this.repository.save(auth);
1005
1064
  }
1006
1065
  async findByUserOrAdminId(id) {
1007
1066
  return await this.repository.createQueryBuilder("auth").leftJoinAndSelect("auth.user", "user").leftJoinAndSelect("auth.admin", "admin").addSelect("auth.twoFactorSecret").where("user.id = :id", { id }).orWhere("admin.id = :id", { id }).getOne();
@@ -1024,6 +1083,7 @@ var _AuthRepository = class _AuthRepository extends import_cca_core8.BaseReposit
1024
1083
  if (account) {
1025
1084
  auth.refreshToken = "";
1026
1085
  account.isActive = false;
1086
+ await this.saveAccount(account);
1027
1087
  }
1028
1088
  await this.update(auth.id, auth);
1029
1089
  }
@@ -1058,6 +1118,9 @@ var _AuthRepository = class _AuthRepository extends import_cca_core8.BaseReposit
1058
1118
  }
1059
1119
  return auth.twoFactorSecret;
1060
1120
  }
1121
+ async saveAccount(account) {
1122
+ await this.repository.manager.save(account);
1123
+ }
1061
1124
  };
1062
1125
  __name(_AuthRepository, "AuthRepository");
1063
1126
  var AuthRepository = _AuthRepository;
@@ -1068,34 +1131,40 @@ var import_cca_core9 = require("cca-core");
1068
1131
  var _JwtAuthService = class _JwtAuthService {
1069
1132
  constructor(repository, config) {
1070
1133
  this.repository = repository;
1071
- this.loadConfig(config);
1072
- }
1073
- async loadConfig(config) {
1074
- const configData = await createConfigInstance();
1075
- this.jwtConfig = {
1076
- accessTokenSecret: configData.accessTokenSecret,
1077
- refreshTokenSecret: configData.refreshTokenSecret,
1078
- accessTokenExpiry: parseInt(configData.accessTokenExpiry, 10),
1079
- refreshTokenExpiry: parseInt(configData.refreshTokenExpiry, 10),
1080
- ...config
1081
- };
1134
+ if (config) {
1135
+ this.jwtConfig = {
1136
+ accessTokenSecret: config.accessTokenSecret,
1137
+ refreshTokenSecret: config.refreshTokenSecret,
1138
+ accessTokenExpiry: config.accessTokenExpiry,
1139
+ refreshTokenExpiry: config.refreshTokenExpiry
1140
+ };
1141
+ }
1082
1142
  this.validateConfiguration();
1083
1143
  }
1084
1144
  async initialize() {
1085
1145
  await (0, import_cca_core9.validateRepository)(this.repository, (repo) => repo.getAll());
1146
+ this.validateConfiguration();
1086
1147
  }
1087
1148
  validateConfiguration() {
1088
1149
  if (!this.jwtConfig?.accessTokenSecret || !this.jwtConfig?.refreshTokenSecret) {
1089
1150
  throw new JwtError("JWT secrets required in config");
1090
1151
  }
1152
+ if (this.jwtConfig.accessTokenExpiry == null || this.jwtConfig.refreshTokenExpiry == null) {
1153
+ throw new JwtError("JWT expirations required in config");
1154
+ }
1091
1155
  }
1092
1156
  verifyJwtConfig() {
1093
1157
  if (!this.jwtConfig) throw new JwtError("JWT config not loaded");
1094
1158
  }
1095
- generateAccessToken(user, role) {
1159
+ generateAccessToken(user, role, twoFactorAuthenticated = false) {
1096
1160
  this.verifyJwtConfig();
1097
1161
  return jwt.sign(
1098
- { userId: user.id, email: user.email, role },
1162
+ {
1163
+ userId: user.id,
1164
+ email: user.email,
1165
+ role,
1166
+ twoFactorAuthenticated
1167
+ },
1099
1168
  this.jwtConfig.accessTokenSecret,
1100
1169
  { expiresIn: this.jwtConfig.accessTokenExpiry }
1101
1170
  );
@@ -1110,11 +1179,8 @@ var _JwtAuthService = class _JwtAuthService {
1110
1179
  }
1111
1180
  async verifyToken(token, secret) {
1112
1181
  try {
1113
- console.log("Verifying token:", token);
1114
- console.log("Using secret:", secret);
1115
1182
  return jwt.verify(token, secret);
1116
1183
  } catch (error) {
1117
- console.error("Error verifying token:", error);
1118
1184
  throw new UnauthorizedError();
1119
1185
  }
1120
1186
  }
@@ -1137,9 +1203,11 @@ var _TwoFactorService = class _TwoFactorService {
1137
1203
  constructor(config) {
1138
1204
  this.initialized = false;
1139
1205
  this.config = config;
1206
+ const parsedTokenWindow = Number.parseInt(config.tokenWindow, 10);
1207
+ const parsedSecretLength = Number.parseInt(config.secretLength, 10);
1140
1208
  this.twoFactorConfig = {
1141
- tokenWindow: parseInt(config.tokenWindow) ?? 1,
1142
- secretLength: parseInt(config.secretLength) ?? 20,
1209
+ tokenWindow: Number.isFinite(parsedTokenWindow) ? parsedTokenWindow : 1,
1210
+ secretLength: Number.isFinite(parsedSecretLength) ? parsedSecretLength : 20,
1143
1211
  qrCodeOptions: {
1144
1212
  errorCorrectionLevel: "M",
1145
1213
  margin: 4,
@@ -1228,25 +1296,35 @@ async function createAuthContainer(database) {
1228
1296
  database.getRepository(import_cca_entities5.AuthEntity)
1229
1297
  );
1230
1298
  container.registerRepository("AuthRepository", authRepository);
1231
- const jwtAuthService = new JwtAuthService(authRepository);
1232
- container.registerService("JwtAuthService", jwtAuthService);
1233
1299
  const configData = await createConfigInstance();
1300
+ const parseExpiry = /* @__PURE__ */ __name((value) => {
1301
+ const numeric = Number(value);
1302
+ return Number.isFinite(numeric) ? numeric : value;
1303
+ }, "parseExpiry");
1304
+ const jwtConfig = {
1305
+ accessTokenSecret: configData.accessTokenSecret,
1306
+ refreshTokenSecret: configData.refreshTokenSecret,
1307
+ accessTokenExpiry: parseExpiry(configData.accessTokenExpiry),
1308
+ refreshTokenExpiry: parseExpiry(configData.refreshTokenExpiry)
1309
+ };
1310
+ const configuredJwtAuthService = new JwtAuthService(authRepository, jwtConfig);
1311
+ container.registerService("JwtAuthService", configuredJwtAuthService);
1234
1312
  const twoFactorService = new TwoFactorService(configData);
1235
1313
  container.registerService("TwoFactorService", twoFactorService);
1236
- const requireComplete2FA = new RequireComplete2FA(jwtAuthService);
1237
- const loginUseCase = new LoginUseCase(authRepository, jwtAuthService);
1314
+ const requireComplete2FA = new RequireComplete2FA(configuredJwtAuthService);
1315
+ const loginUseCase = new LoginUseCase(authRepository, configuredJwtAuthService);
1238
1316
  const logoutUseCase = new LogoutUseCase(authRepository);
1239
1317
  const registerUseCase = new RegisterUseCase(authRepository);
1240
1318
  const refreshTokenUseCase = new RefreshTokenUseCase(
1241
1319
  authRepository,
1242
- jwtAuthService
1320
+ configuredJwtAuthService
1243
1321
  );
1244
1322
  const twoFactorSetupUseCase = new TwoFactorSetupUseCase(twoFactorService, authRepository);
1245
1323
  const twoFactorEnableUseCase = new TwoFactorEnableUseCase(twoFactorService, authRepository);
1246
1324
  const twoFactorVerifyUseCase = new TwoFactorVerifyUseCase(
1247
1325
  twoFactorService,
1248
1326
  authRepository,
1249
- jwtAuthService
1327
+ configuredJwtAuthService
1250
1328
  );
1251
1329
  const twoFactorDisableUseCase = new TwoFactorDisableUseCase(twoFactorService, authRepository);
1252
1330
  container.registerService("LoginUseCase", loginUseCase);