@flusys/nestjs-auth 6.0.2 → 6.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.
- package/cjs/controllers/authentication.controller.spec.js +219 -0
- package/cjs/controllers/branch.controller.spec.js +134 -0
- package/cjs/controllers/company-selection.controller.spec.js +84 -0
- package/cjs/controllers/company.controller.spec.js +131 -0
- package/cjs/controllers/email-verification.controller.spec.js +142 -0
- package/cjs/controllers/user-permission.controller.spec.js +138 -0
- package/cjs/controllers/user.controller.spec.js +204 -0
- package/cjs/docs/auth-swagger.config.spec.js +130 -0
- package/cjs/entities/index.spec.js +73 -0
- package/cjs/helpers/auth-response.mapper.js +46 -0
- package/cjs/helpers/auth-response.mapper.spec.js +139 -0
- package/cjs/helpers/index.js +19 -0
- package/cjs/helpers/token.helper.js +58 -0
- package/cjs/helpers/token.helper.spec.js +86 -0
- package/cjs/index.js +1 -0
- package/cjs/interceptors/clear-token.interceptor.spec.js +107 -0
- package/cjs/interceptors/set-token.interceptor.spec.js +165 -0
- package/cjs/modules/auth.module.spec.js +243 -0
- package/cjs/services/auth-config.service.spec.js +97 -0
- package/cjs/services/auth-datasource.provider.spec.js +161 -0
- package/cjs/services/auth-email.service.spec.js +404 -0
- package/cjs/services/authentication.service.js +37 -109
- package/cjs/services/authentication.service.spec.js +904 -0
- package/cjs/services/branch.service.spec.js +154 -0
- package/cjs/services/company-selection-session.service.spec.js +90 -0
- package/cjs/services/company.service.spec.js +113 -0
- package/cjs/services/user-permission.service.spec.js +202 -0
- package/cjs/services/user.service.spec.js +704 -0
- package/cjs/strategies/jwt.strategy.js +1 -1
- package/cjs/strategies/jwt.strategy.spec.js +166 -0
- package/cjs/validators/password.validator.spec.js +161 -0
- package/entities/pending-registration.entity.d.ts +2 -7
- package/fesm/controllers/authentication.controller.spec.js +215 -0
- package/fesm/controllers/branch.controller.spec.js +130 -0
- package/fesm/controllers/company-selection.controller.spec.js +80 -0
- package/fesm/controllers/company.controller.spec.js +127 -0
- package/fesm/controllers/email-verification.controller.spec.js +138 -0
- package/fesm/controllers/user-permission.controller.spec.js +134 -0
- package/fesm/controllers/user.controller.spec.js +200 -0
- package/fesm/docs/auth-swagger.config.spec.js +126 -0
- package/fesm/entities/index.spec.js +69 -0
- package/fesm/helpers/auth-response.mapper.js +25 -0
- package/fesm/helpers/auth-response.mapper.spec.js +135 -0
- package/fesm/helpers/index.js +2 -0
- package/fesm/helpers/token.helper.js +40 -0
- package/fesm/helpers/token.helper.spec.js +82 -0
- package/fesm/index.js +1 -0
- package/fesm/interceptors/clear-token.interceptor.spec.js +103 -0
- package/fesm/interceptors/set-token.interceptor.spec.js +161 -0
- package/fesm/interfaces/authentication.interface.js +1 -1
- package/fesm/modules/auth.module.spec.js +239 -0
- package/fesm/services/auth-config.service.spec.js +93 -0
- package/fesm/services/auth-datasource.provider.spec.js +157 -0
- package/fesm/services/auth-email.service.spec.js +359 -0
- package/fesm/services/authentication.service.js +37 -109
- package/fesm/services/authentication.service.spec.js +859 -0
- package/fesm/services/branch.service.spec.js +150 -0
- package/fesm/services/company-selection-session.service.spec.js +86 -0
- package/fesm/services/company.service.spec.js +109 -0
- package/fesm/services/user-permission.service.spec.js +198 -0
- package/fesm/services/user.service.spec.js +659 -0
- package/fesm/strategies/jwt.strategy.js +1 -1
- package/fesm/strategies/jwt.strategy.spec.js +162 -0
- package/fesm/validators/password.validator.spec.js +157 -0
- package/helpers/auth-response.mapper.d.ts +22 -0
- package/helpers/index.d.ts +2 -0
- package/helpers/token.helper.d.ts +8 -0
- package/index.d.ts +1 -0
- package/interfaces/authentication.interface.d.ts +7 -0
- package/package.json +8 -3
- package/services/authentication.service.d.ts +1 -8
|
@@ -42,6 +42,7 @@ import { Company } from '../entities/company.entity';
|
|
|
42
42
|
import { PendingRegistration } from '../entities/pending-registration.entity';
|
|
43
43
|
import { UserCompanyPermission } from '../entities/user-company-permission.entity';
|
|
44
44
|
import { PermissionType } from '../enums';
|
|
45
|
+
import { generateTokens, parseExpiryToMs, toBranchInfo, toCompanyInfo, toUserInfo } from '../helpers';
|
|
45
46
|
import { IUserEnricher } from '../interfaces/user-enricher.interface';
|
|
46
47
|
import { AuthConfigService } from './auth-config.service';
|
|
47
48
|
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
@@ -68,17 +69,9 @@ export class AuthenticationService {
|
|
|
68
69
|
}
|
|
69
70
|
return this.dataSourceProvider.getRepository(AppUser);
|
|
70
71
|
}
|
|
71
|
-
async
|
|
72
|
+
async getCompanyScopedRepository(entity) {
|
|
72
73
|
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
73
|
-
return this.dataSourceProvider.getRepository(
|
|
74
|
-
}
|
|
75
|
-
async getCompanyRepository() {
|
|
76
|
-
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
77
|
-
return this.dataSourceProvider.getRepository(Company);
|
|
78
|
-
}
|
|
79
|
-
async getBranchRepository() {
|
|
80
|
-
if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
|
|
81
|
-
return this.dataSourceProvider.getRepository(CompanyBranch);
|
|
74
|
+
return this.dataSourceProvider.getRepository(entity);
|
|
82
75
|
}
|
|
83
76
|
async login(email, password) {
|
|
84
77
|
if (this.isEmailVerificationEnabled() && await this.authEmailService.hasPendingRegistration(email)) {
|
|
@@ -110,8 +103,8 @@ export class AuthenticationService {
|
|
|
110
103
|
return await this.handleCompanyBasedLogin(user);
|
|
111
104
|
}
|
|
112
105
|
async handleCompanyBasedLogin(user) {
|
|
113
|
-
const permissionRepository = await this.
|
|
114
|
-
const branchRepository = await this.
|
|
106
|
+
const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
|
|
107
|
+
const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
|
|
115
108
|
if (!permissionRepository || !branchRepository) {
|
|
116
109
|
return this.generateLoginResponse(user);
|
|
117
110
|
}
|
|
@@ -121,7 +114,7 @@ export class AuthenticationService {
|
|
|
121
114
|
permissionType: PermissionType.COMPANY
|
|
122
115
|
}
|
|
123
116
|
});
|
|
124
|
-
const companyRepository = await this.
|
|
117
|
+
const companyRepository = await this.getCompanyScopedRepository(Company);
|
|
125
118
|
if (!companyRepository) {
|
|
126
119
|
return this.generateLoginResponse(user);
|
|
127
120
|
}
|
|
@@ -199,8 +192,8 @@ export class AuthenticationService {
|
|
|
199
192
|
messageKey: AUTH_MESSAGES.REGISTER_EMAIL_EXISTS
|
|
200
193
|
});
|
|
201
194
|
}
|
|
202
|
-
const permissionRepository = await this.
|
|
203
|
-
const companyRepository = await this.
|
|
195
|
+
const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
|
|
196
|
+
const companyRepository = await this.getCompanyScopedRepository(Company);
|
|
204
197
|
if (!permissionRepository || !companyRepository) {
|
|
205
198
|
throw new BadRequestException({
|
|
206
199
|
message: 'Company feature repositories not available',
|
|
@@ -334,9 +327,9 @@ export class AuthenticationService {
|
|
|
334
327
|
}
|
|
335
328
|
}
|
|
336
329
|
async processCompanyRegistration(user, data, throwOnUnavailable = false) {
|
|
337
|
-
const companyRepository = await this.
|
|
338
|
-
const branchRepository = await this.
|
|
339
|
-
const permissionRepository = await this.
|
|
330
|
+
const companyRepository = await this.getCompanyScopedRepository(Company);
|
|
331
|
+
const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
|
|
332
|
+
const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
|
|
340
333
|
if (!companyRepository || !branchRepository || !permissionRepository) {
|
|
341
334
|
if (throwOnUnavailable) throw new BadRequestException({
|
|
342
335
|
message: 'Company feature repositories not available',
|
|
@@ -472,9 +465,9 @@ export class AuthenticationService {
|
|
|
472
465
|
messageKey: USER_MESSAGES.NOT_FOUND
|
|
473
466
|
});
|
|
474
467
|
}
|
|
475
|
-
const permissionRepository = await this.
|
|
476
|
-
const companyRepository = await this.
|
|
477
|
-
const branchRepository = await this.
|
|
468
|
+
const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
|
|
469
|
+
const companyRepository = await this.getCompanyScopedRepository(Company);
|
|
470
|
+
const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
|
|
478
471
|
if (!permissionRepository || !companyRepository || !branchRepository) {
|
|
479
472
|
throw new BadRequestException({
|
|
480
473
|
message: 'Repositories not available',
|
|
@@ -564,8 +557,8 @@ export class AuthenticationService {
|
|
|
564
557
|
});
|
|
565
558
|
}
|
|
566
559
|
if (payload.companyId) {
|
|
567
|
-
const companyRepository = await this.
|
|
568
|
-
const permissionRepository = await this.
|
|
560
|
+
const companyRepository = await this.getCompanyScopedRepository(Company);
|
|
561
|
+
const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
|
|
569
562
|
if (companyRepository) {
|
|
570
563
|
const company = await companyRepository.findOne({
|
|
571
564
|
where: {
|
|
@@ -596,7 +589,7 @@ export class AuthenticationService {
|
|
|
596
589
|
}
|
|
597
590
|
}
|
|
598
591
|
if (payload.branchId) {
|
|
599
|
-
const branchRepository = await this.
|
|
592
|
+
const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
|
|
600
593
|
if (branchRepository) {
|
|
601
594
|
const branch = await branchRepository.findOne({
|
|
602
595
|
where: {
|
|
@@ -629,7 +622,7 @@ export class AuthenticationService {
|
|
|
629
622
|
}
|
|
630
623
|
}
|
|
631
624
|
}
|
|
632
|
-
return this.
|
|
625
|
+
return generateTokens(this.jwtService, this.authConfig, {
|
|
633
626
|
id: user.id,
|
|
634
627
|
email: user.email,
|
|
635
628
|
type: 'access',
|
|
@@ -678,7 +671,7 @@ export class AuthenticationService {
|
|
|
678
671
|
const revokedAt = Math.floor(Date.now() / 1000);
|
|
679
672
|
const cacheKey = `${TOKEN_REVOKED_PREFIX}:${userId}`;
|
|
680
673
|
const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
|
|
681
|
-
const ttlMs =
|
|
674
|
+
const ttlMs = parseExpiryToMs(refreshTokenExpiry);
|
|
682
675
|
await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
|
|
683
676
|
}
|
|
684
677
|
async isTokenRevoked(userId, tokenIssuedAt) {
|
|
@@ -692,28 +685,10 @@ export class AuthenticationService {
|
|
|
692
685
|
}
|
|
693
686
|
return tokenIssuedAt < revokedAt;
|
|
694
687
|
}
|
|
695
|
-
parseExpiryToMs(expiry) {
|
|
696
|
-
const match = expiry.match(/^(\d+)([smhd])$/);
|
|
697
|
-
if (!match) return 7 * 24 * 60 * 60 * 1000;
|
|
698
|
-
const value = parseInt(match[1], 10);
|
|
699
|
-
const unit = match[2];
|
|
700
|
-
switch(unit){
|
|
701
|
-
case 's':
|
|
702
|
-
return value * 1000;
|
|
703
|
-
case 'm':
|
|
704
|
-
return value * 60 * 1000;
|
|
705
|
-
case 'h':
|
|
706
|
-
return value * 60 * 60 * 1000;
|
|
707
|
-
case 'd':
|
|
708
|
-
return value * 24 * 60 * 60 * 1000;
|
|
709
|
-
default:
|
|
710
|
-
return 7 * 24 * 60 * 60 * 1000;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
688
|
async getUserCompanies(userId) {
|
|
714
689
|
this.ensureCompanyFeatureEnabled();
|
|
715
|
-
const permissionRepository = await this.
|
|
716
|
-
const companyRepository = await this.
|
|
690
|
+
const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
|
|
691
|
+
const companyRepository = await this.getCompanyScopedRepository(Company);
|
|
717
692
|
if (!permissionRepository || !companyRepository) {
|
|
718
693
|
throw new BadRequestException({
|
|
719
694
|
message: 'Repositories not available',
|
|
@@ -739,8 +714,8 @@ export class AuthenticationService {
|
|
|
739
714
|
}
|
|
740
715
|
async getUserBranches(userId, companyId) {
|
|
741
716
|
this.ensureCompanyFeatureEnabled();
|
|
742
|
-
const permissionRepository = await this.
|
|
743
|
-
const branchRepository = await this.
|
|
717
|
+
const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
|
|
718
|
+
const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
|
|
744
719
|
if (!permissionRepository || !branchRepository) {
|
|
745
720
|
throw new BadRequestException({
|
|
746
721
|
message: 'Repositories not available',
|
|
@@ -780,7 +755,7 @@ export class AuthenticationService {
|
|
|
780
755
|
}).orderBy('b.serial', 'ASC').addOrderBy('b.name', 'ASC').getMany();
|
|
781
756
|
}
|
|
782
757
|
async getCompanyById(companyId) {
|
|
783
|
-
const companyRepository = await this.
|
|
758
|
+
const companyRepository = await this.getCompanyScopedRepository(Company);
|
|
784
759
|
if (!companyRepository) {
|
|
785
760
|
return null;
|
|
786
761
|
}
|
|
@@ -791,7 +766,7 @@ export class AuthenticationService {
|
|
|
791
766
|
});
|
|
792
767
|
}
|
|
793
768
|
async getBranchById(branchId) {
|
|
794
|
-
const branchRepository = await this.
|
|
769
|
+
const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
|
|
795
770
|
if (!branchRepository) {
|
|
796
771
|
return null;
|
|
797
772
|
}
|
|
@@ -813,7 +788,7 @@ export class AuthenticationService {
|
|
|
813
788
|
messageKey: USER_MESSAGES.NOT_FOUND
|
|
814
789
|
});
|
|
815
790
|
const response = {
|
|
816
|
-
user:
|
|
791
|
+
user: toUserInfo(user)
|
|
817
792
|
};
|
|
818
793
|
if (this.isCompanyFeatureEnabled()) {
|
|
819
794
|
if (!companyId) {
|
|
@@ -827,14 +802,14 @@ export class AuthenticationService {
|
|
|
827
802
|
message: 'Company not found.',
|
|
828
803
|
messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
|
|
829
804
|
});
|
|
830
|
-
response.company =
|
|
805
|
+
response.company = toCompanyInfo(company);
|
|
831
806
|
if (branchId) {
|
|
832
807
|
const branch = await this.getBranchById(branchId);
|
|
833
808
|
if (!branch) throw new UnauthorizedException({
|
|
834
809
|
message: 'Branch not found.',
|
|
835
810
|
messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
|
|
836
811
|
});
|
|
837
|
-
response.branch =
|
|
812
|
+
response.branch = toBranchInfo(branch);
|
|
838
813
|
}
|
|
839
814
|
}
|
|
840
815
|
return response;
|
|
@@ -864,55 +839,8 @@ export class AuthenticationService {
|
|
|
864
839
|
await userRepository.save(user);
|
|
865
840
|
return user;
|
|
866
841
|
}
|
|
867
|
-
toUserInfo(user) {
|
|
868
|
-
return {
|
|
869
|
-
id: user.id,
|
|
870
|
-
email: user.email,
|
|
871
|
-
name: user.name ?? undefined,
|
|
872
|
-
phone: user.phone ?? null,
|
|
873
|
-
profilePictureId: user.profilePictureId ?? null
|
|
874
|
-
};
|
|
875
|
-
}
|
|
876
|
-
toCompanyInfo(company) {
|
|
877
|
-
return {
|
|
878
|
-
id: company.id,
|
|
879
|
-
name: company.name,
|
|
880
|
-
slug: company.slug,
|
|
881
|
-
logoId: company.logoId ?? null
|
|
882
|
-
};
|
|
883
|
-
}
|
|
884
|
-
toBranchInfo(branch) {
|
|
885
|
-
return {
|
|
886
|
-
id: branch.id,
|
|
887
|
-
name: branch.name,
|
|
888
|
-
slug: branch.slug,
|
|
889
|
-
logoId: branch.logoId ?? null
|
|
890
|
-
};
|
|
891
|
-
}
|
|
892
|
-
generateTokens(payload) {
|
|
893
|
-
const accessToken = this.jwtService.sign({
|
|
894
|
-
...payload,
|
|
895
|
-
type: 'access'
|
|
896
|
-
}, {
|
|
897
|
-
secret: this.authConfig.getJwtSecret(),
|
|
898
|
-
expiresIn: this.authConfig.getJwtExpiration(),
|
|
899
|
-
algorithm: 'HS256'
|
|
900
|
-
});
|
|
901
|
-
const refreshToken = this.jwtService.sign({
|
|
902
|
-
...payload,
|
|
903
|
-
type: 'refresh'
|
|
904
|
-
}, {
|
|
905
|
-
secret: this.authConfig.getRefreshTokenSecret(),
|
|
906
|
-
expiresIn: this.authConfig.getRefreshTokenExpiration(),
|
|
907
|
-
algorithm: 'HS256'
|
|
908
|
-
});
|
|
909
|
-
return {
|
|
910
|
-
accessToken,
|
|
911
|
-
refreshToken
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
842
|
generateLoginResponse(user) {
|
|
915
|
-
const { accessToken, refreshToken } = this.
|
|
843
|
+
const { accessToken, refreshToken } = generateTokens(this.jwtService, this.authConfig, {
|
|
916
844
|
id: user.id,
|
|
917
845
|
email: user.email,
|
|
918
846
|
type: 'access'
|
|
@@ -921,11 +849,11 @@ export class AuthenticationService {
|
|
|
921
849
|
return {
|
|
922
850
|
accessToken,
|
|
923
851
|
refreshToken,
|
|
924
|
-
user:
|
|
852
|
+
user: toUserInfo(user)
|
|
925
853
|
};
|
|
926
854
|
}
|
|
927
855
|
generateLoginResponseWithCompany(user, company, branch) {
|
|
928
|
-
const { accessToken, refreshToken } = this.
|
|
856
|
+
const { accessToken, refreshToken } = generateTokens(this.jwtService, this.authConfig, {
|
|
929
857
|
id: user.id,
|
|
930
858
|
email: user.email,
|
|
931
859
|
type: 'access',
|
|
@@ -936,9 +864,9 @@ export class AuthenticationService {
|
|
|
936
864
|
return {
|
|
937
865
|
accessToken,
|
|
938
866
|
refreshToken,
|
|
939
|
-
user:
|
|
940
|
-
company:
|
|
941
|
-
branch: branch ?
|
|
867
|
+
user: toUserInfo(user),
|
|
868
|
+
company: toCompanyInfo(company),
|
|
869
|
+
branch: branch ? toBranchInfo(branch) : undefined
|
|
942
870
|
};
|
|
943
871
|
}
|
|
944
872
|
sendLoginNotification(userId, companyId) {
|
|
@@ -963,10 +891,10 @@ export class AuthenticationService {
|
|
|
963
891
|
}
|
|
964
892
|
const sessionId = await this.sessionService.createSession(user.id);
|
|
965
893
|
const companiesWithBranches = companies.map((company)=>({
|
|
966
|
-
...
|
|
894
|
+
...toCompanyInfo(company),
|
|
967
895
|
isActive: company.isActive,
|
|
968
896
|
branches: branches.filter((b)=>b.companyId === company.id).map((b)=>({
|
|
969
|
-
...
|
|
897
|
+
...toBranchInfo(b),
|
|
970
898
|
isActive: b.isActive
|
|
971
899
|
}))
|
|
972
900
|
}));
|
|
@@ -974,7 +902,7 @@ export class AuthenticationService {
|
|
|
974
902
|
requiresSelection: true,
|
|
975
903
|
sessionId,
|
|
976
904
|
expiresAt: new Date(Date.now() + 5 * 60 * 1000),
|
|
977
|
-
user:
|
|
905
|
+
user: toUserInfo(user),
|
|
978
906
|
companies: companiesWithBranches
|
|
979
907
|
};
|
|
980
908
|
}
|