@flusys/nestjs-auth 0.1.0-beta.3 → 1.0.0-rc
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/README.md +274 -301
- package/cjs/config/auth.constants.js +22 -4
- package/cjs/controllers/authentication.controller.js +222 -38
- package/cjs/controllers/branch.controller.js +46 -4
- package/cjs/controllers/company-selection.controller.js +27 -20
- package/cjs/controllers/company.controller.js +46 -4
- package/cjs/controllers/user-permission.controller.js +40 -37
- package/cjs/controllers/user.controller.js +222 -23
- package/cjs/dtos/authentication.dto.js +119 -13
- package/cjs/dtos/user-permission.dto.js +28 -0
- package/cjs/dtos/user.dto.js +19 -4
- package/cjs/entities/index.js +5 -1
- package/cjs/entities/pending-registration.entity.js +125 -0
- package/cjs/entities/user-company-permission.entity.js +0 -6
- package/cjs/entities/user-token.entity.js +129 -0
- package/cjs/guards/auth-throttler.guard.js +53 -0
- package/cjs/interceptors/clear-token.interceptor.js +3 -6
- package/cjs/interceptors/set-token.interceptor.js +38 -31
- package/cjs/interfaces/auth-email-provider.interface.js +45 -0
- package/cjs/interfaces/authentication.interface.js +0 -3
- package/cjs/interfaces/index.js +2 -0
- package/cjs/interfaces/user-enricher.interface.js +4 -0
- package/cjs/modules/auth.module.js +8 -20
- package/cjs/services/auth-config.service.js +42 -47
- package/cjs/services/auth-datasource.provider.js +18 -34
- package/cjs/services/auth-email.service.js +471 -0
- package/cjs/services/authentication.service.js +240 -153
- package/cjs/services/branch.service.js +15 -48
- package/cjs/services/company-selection-session.service.js +1 -1
- package/cjs/services/company.service.js +7 -36
- package/cjs/services/index.js +1 -0
- package/cjs/services/user-permission.service.js +9 -29
- package/cjs/services/user.service.js +228 -107
- package/cjs/strategies/jwt.strategy.js +14 -1
- package/cjs/validators/password.validator.js +45 -0
- package/config/auth.constants.d.ts +5 -0
- package/controllers/authentication.controller.d.ts +13 -9
- package/controllers/company-selection.controller.d.ts +6 -2
- package/controllers/user.controller.d.ts +33 -0
- package/dtos/authentication.dto.d.ts +21 -3
- package/dtos/company-branch.dto.d.ts +0 -1
- package/dtos/company.dto.d.ts +0 -1
- package/dtos/user-permission.dto.d.ts +4 -0
- package/dtos/user.dto.d.ts +1 -2
- package/entities/index.d.ts +7 -3
- package/entities/pending-registration.entity.d.ts +17 -0
- package/entities/user-company-permission.entity.d.ts +0 -2
- package/entities/user-token.entity.d.ts +15 -0
- package/fesm/config/auth.constants.js +11 -8
- package/fesm/controllers/authentication.controller.js +224 -40
- package/fesm/controllers/branch.controller.js +49 -7
- package/fesm/controllers/company-selection.controller.js +28 -21
- package/fesm/controllers/company.controller.js +49 -7
- package/fesm/controllers/user-permission.controller.js +41 -38
- package/fesm/controllers/user.controller.js +225 -26
- package/fesm/dtos/authentication.dto.js +123 -111
- package/fesm/dtos/user-permission.dto.js +28 -0
- package/fesm/dtos/user.dto.js +20 -5
- package/fesm/entities/index.js +7 -1
- package/fesm/entities/pending-registration.entity.js +115 -0
- package/fesm/entities/user-company-permission.entity.js +0 -6
- package/fesm/entities/user-token.entity.js +113 -0
- package/fesm/guards/auth-throttler.guard.js +43 -0
- package/fesm/interceptors/clear-token.interceptor.js +2 -5
- package/fesm/interceptors/set-token.interceptor.js +37 -30
- package/fesm/interfaces/auth-email-provider.interface.js +38 -0
- package/fesm/interfaces/authentication.interface.js +1 -7
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/user-enricher.interface.js +26 -0
- package/fesm/modules/auth.module.js +10 -22
- package/fesm/services/auth-config.service.js +42 -47
- package/fesm/services/auth-datasource.provider.js +19 -35
- package/fesm/services/auth-email.service.js +420 -0
- package/fesm/services/authentication.service.js +238 -151
- package/fesm/services/branch.service.js +16 -49
- package/fesm/services/company-selection-session.service.js +1 -1
- package/fesm/services/company.service.js +8 -37
- package/fesm/services/index.js +1 -0
- package/fesm/services/user-permission.service.js +10 -30
- package/fesm/services/user.service.js +229 -108
- package/fesm/strategies/jwt.strategy.js +14 -1
- package/fesm/validators/password.validator.js +48 -0
- package/guards/auth-throttler.guard.d.ts +7 -0
- package/interceptors/set-token.interceptor.d.ts +1 -0
- package/interfaces/auth-email-provider.interface.d.ts +6 -0
- package/interfaces/auth-module-options.interface.d.ts +4 -1
- package/interfaces/authentication.interface.d.ts +14 -0
- package/interfaces/index.d.ts +2 -0
- package/interfaces/user-enricher.interface.d.ts +64 -0
- package/interfaces/user.interface.d.ts +1 -0
- package/modules/auth.module.d.ts +0 -1
- package/package.json +4 -4
- package/services/auth-config.service.d.ts +5 -1
- package/services/auth-email.service.d.ts +51 -0
- package/services/authentication.service.d.ts +21 -12
- package/services/branch.service.d.ts +2 -5
- package/services/company-selection-session.service.d.ts +1 -1
- package/services/company.service.d.ts +1 -4
- package/services/index.d.ts +1 -0
- package/services/user-permission.service.d.ts +0 -1
- package/services/user.service.d.ts +20 -6
- package/validators/password.validator.d.ts +10 -0
|
@@ -27,46 +27,21 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
}
|
|
28
28
|
import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
|
|
29
29
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
-
import {
|
|
30
|
+
import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
|
|
31
|
+
import { Inject, Injectable, Scope } from '@nestjs/common';
|
|
31
32
|
import { CompanyBranch } from '../entities/company-branch.entity';
|
|
32
33
|
import { AuthConfigService } from './auth-config.service';
|
|
33
34
|
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
34
35
|
export class BranchService extends RequestScopedApiService {
|
|
35
|
-
|
|
36
|
-
* Resolve entity class for this service
|
|
37
|
-
* @returns CompanyBranch entity class
|
|
38
|
-
*/ resolveEntity() {
|
|
36
|
+
resolveEntity() {
|
|
39
37
|
return CompanyBranch;
|
|
40
38
|
}
|
|
41
|
-
|
|
42
|
-
* Get DataSource provider for this service
|
|
43
|
-
* @returns AuthDataSourceProvider instance
|
|
44
|
-
*/ getDataSourceProvider() {
|
|
39
|
+
getDataSourceProvider() {
|
|
45
40
|
return this.dataSourceProvider;
|
|
46
41
|
}
|
|
47
|
-
//
|
|
48
|
-
async convertSingleDtoToEntity(dto, _user) {
|
|
49
|
-
// Repository initialization is handled automatically by RequestScopedApiService
|
|
50
|
-
let branch = new CompanyBranch();
|
|
51
|
-
if ('id' in dto && dto.id && typeof dto.id === 'string') {
|
|
52
|
-
const dbData = await this.repository.findOne({
|
|
53
|
-
where: {
|
|
54
|
-
id: dto.id
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
if (!dbData) {
|
|
58
|
-
throw new NotFoundException('Branch not found');
|
|
59
|
-
}
|
|
60
|
-
branch = dbData;
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
...branch,
|
|
64
|
-
...dto
|
|
65
|
-
};
|
|
66
|
-
}
|
|
42
|
+
// Query Customization
|
|
67
43
|
async getSelectQuery(query, _user, select) {
|
|
68
|
-
|
|
69
|
-
if (!select || !select.length) {
|
|
44
|
+
if (!select?.length) {
|
|
70
45
|
select = [
|
|
71
46
|
'id',
|
|
72
47
|
'name',
|
|
@@ -75,14 +50,13 @@ export class BranchService extends RequestScopedApiService {
|
|
|
75
50
|
'createdAt'
|
|
76
51
|
];
|
|
77
52
|
}
|
|
78
|
-
|
|
79
|
-
query.select(selectFields);
|
|
53
|
+
query.select(select.map((f)=>`${this.entityName}.${f}`));
|
|
80
54
|
return {
|
|
81
55
|
query,
|
|
82
56
|
isRaw: false
|
|
83
57
|
};
|
|
84
58
|
}
|
|
85
|
-
async getGlobalSearchQuery(query, search
|
|
59
|
+
async getGlobalSearchQuery(query, search) {
|
|
86
60
|
query.andWhere('(company_branch.name LIKE :search OR company_branch.slug LIKE :search OR company_branch.email LIKE :search)', {
|
|
87
61
|
search: `%${search}%`
|
|
88
62
|
});
|
|
@@ -91,24 +65,17 @@ export class BranchService extends RequestScopedApiService {
|
|
|
91
65
|
isRaw: false
|
|
92
66
|
};
|
|
93
67
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (isCompanyFeatureEnabled && user?.companyId) {
|
|
102
|
-
query.andWhere('company_branch.company_id = :companyId', {
|
|
103
|
-
companyId: user.companyId
|
|
104
|
-
});
|
|
105
|
-
}
|
|
68
|
+
async getExtraManipulateQuery(query, filterDto, user) {
|
|
69
|
+
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
70
|
+
applyCompanyFilter(query, {
|
|
71
|
+
isCompanyFeatureEnabled: this.authConfig.isCompanyFeatureEnabled(),
|
|
72
|
+
entityAlias: 'company_branch',
|
|
73
|
+
columnName: 'company_id'
|
|
74
|
+
}, user);
|
|
106
75
|
return result;
|
|
107
76
|
}
|
|
108
|
-
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
109
77
|
constructor(cacheManager, utilsService, dataSourceProvider, authConfig){
|
|
110
|
-
|
|
111
|
-
super('company_branch', null, cacheManager, utilsService, BranchService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "authConfig", void 0), _define_property(this, "logger", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.authConfig = authConfig, this.logger = new Logger(BranchService.name);
|
|
78
|
+
super('company_branch', null, cacheManager, utilsService, BranchService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "authConfig", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.authConfig = authConfig;
|
|
112
79
|
}
|
|
113
80
|
}
|
|
114
81
|
BranchService = _ts_decorate([
|
|
@@ -33,7 +33,7 @@ const SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
|
33
33
|
export class CompanySelectionSessionService {
|
|
34
34
|
/**
|
|
35
35
|
* Create a new session for company/branch selection
|
|
36
|
-
*/ async createSession(userId
|
|
36
|
+
*/ async createSession(userId) {
|
|
37
37
|
const sessionId = randomUUID();
|
|
38
38
|
const now = new Date();
|
|
39
39
|
const expiresAt = new Date(now.getTime() + SESSION_TTL_MS);
|
|
@@ -27,45 +27,19 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
}
|
|
28
28
|
import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
|
|
29
29
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
-
import { Inject, Injectable,
|
|
30
|
+
import { Inject, Injectable, Scope } from '@nestjs/common';
|
|
31
31
|
import { Company } from '../entities/company.entity';
|
|
32
32
|
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
33
33
|
export class CompanyService extends RequestScopedApiService {
|
|
34
|
-
|
|
35
|
-
* Resolve entity class for this service
|
|
36
|
-
* @returns Company entity class
|
|
37
|
-
*/ resolveEntity() {
|
|
34
|
+
resolveEntity() {
|
|
38
35
|
return Company;
|
|
39
36
|
}
|
|
40
|
-
|
|
41
|
-
* Get DataSource provider for this service
|
|
42
|
-
* @returns AuthDataSourceProvider instance
|
|
43
|
-
*/ getDataSourceProvider() {
|
|
37
|
+
getDataSourceProvider() {
|
|
44
38
|
return this.dataSourceProvider;
|
|
45
39
|
}
|
|
46
|
-
//
|
|
47
|
-
async convertSingleDtoToEntity(dto, _user) {
|
|
48
|
-
// Repository initialization is handled automatically by RequestScopedApiService
|
|
49
|
-
let company = new Company();
|
|
50
|
-
if ('id' in dto && dto.id && typeof dto.id === 'string') {
|
|
51
|
-
const dbData = await this.repository.findOne({
|
|
52
|
-
where: {
|
|
53
|
-
id: dto.id
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
if (!dbData) {
|
|
57
|
-
throw new NotFoundException('Company not found');
|
|
58
|
-
}
|
|
59
|
-
company = dbData;
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
...company,
|
|
63
|
-
...dto
|
|
64
|
-
};
|
|
65
|
-
}
|
|
40
|
+
// Query Customization
|
|
66
41
|
async getSelectQuery(query, _user, select) {
|
|
67
|
-
|
|
68
|
-
if (!select || !select.length) {
|
|
42
|
+
if (!select?.length) {
|
|
69
43
|
select = [
|
|
70
44
|
'id',
|
|
71
45
|
'name',
|
|
@@ -74,14 +48,13 @@ export class CompanyService extends RequestScopedApiService {
|
|
|
74
48
|
'createdAt'
|
|
75
49
|
];
|
|
76
50
|
}
|
|
77
|
-
|
|
78
|
-
query.select(selectFields);
|
|
51
|
+
query.select(select.map((f)=>`${this.entityName}.${f}`));
|
|
79
52
|
return {
|
|
80
53
|
query,
|
|
81
54
|
isRaw: false
|
|
82
55
|
};
|
|
83
56
|
}
|
|
84
|
-
async getGlobalSearchQuery(query, search
|
|
57
|
+
async getGlobalSearchQuery(query, search) {
|
|
85
58
|
query.andWhere('(company.name LIKE :search OR company.slug LIKE :search OR company.email LIKE :search)', {
|
|
86
59
|
search: `%${search}%`
|
|
87
60
|
});
|
|
@@ -90,10 +63,8 @@ export class CompanyService extends RequestScopedApiService {
|
|
|
90
63
|
isRaw: false
|
|
91
64
|
};
|
|
92
65
|
}
|
|
93
|
-
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
94
66
|
constructor(cacheManager, utilsService, dataSourceProvider){
|
|
95
|
-
|
|
96
|
-
super('company', null, cacheManager, utilsService, CompanyService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "logger", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.logger = new Logger(CompanyService.name);
|
|
67
|
+
super('company', null, cacheManager, utilsService, CompanyService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider;
|
|
97
68
|
}
|
|
98
69
|
}
|
|
99
70
|
CompanyService = _ts_decorate([
|
package/fesm/services/index.js
CHANGED
|
@@ -25,24 +25,18 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import { BadRequestException, Inject, Injectable,
|
|
28
|
+
import { BadRequestException, Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
|
|
29
29
|
import { PermissionType, UserCompanyPermission } from '../entities/user-company-permission.entity';
|
|
30
30
|
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
31
31
|
export class UserPermissionService {
|
|
32
|
-
/**
|
|
33
|
-
* Get repository lazily - initialized on first access
|
|
34
|
-
*/ async getRepository() {
|
|
32
|
+
/** Get repository lazily - initialized on first access */ async getRepository() {
|
|
35
33
|
if (!this._repository) {
|
|
36
34
|
this._repository = await this.dataSourceProvider.getRepository(UserCompanyPermission);
|
|
37
35
|
}
|
|
38
36
|
return this._repository;
|
|
39
37
|
}
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
// ==========================================================================
|
|
43
|
-
/**
|
|
44
|
-
* Find all companies a user has access to
|
|
45
|
-
*/ async findUserCompanies(userId) {
|
|
38
|
+
// Company Permissions
|
|
39
|
+
/** Find all companies a user has access to */ async findUserCompanies(userId) {
|
|
46
40
|
const repository = await this.getRepository();
|
|
47
41
|
return repository.find({
|
|
48
42
|
where: {
|
|
@@ -57,9 +51,7 @@ export class UserPermissionService {
|
|
|
57
51
|
}
|
|
58
52
|
});
|
|
59
53
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Assign user to a company
|
|
62
|
-
*/ async assignUserToCompany(dto) {
|
|
54
|
+
/** Assign user to a company */ async assignUserToCompany(dto) {
|
|
63
55
|
const repository = await this.getRepository();
|
|
64
56
|
// Check if already exists
|
|
65
57
|
const existing = await repository.findOne({
|
|
@@ -80,9 +72,7 @@ export class UserPermissionService {
|
|
|
80
72
|
});
|
|
81
73
|
await repository.save(permission);
|
|
82
74
|
}
|
|
83
|
-
/**
|
|
84
|
-
* Revoke user access to a company
|
|
85
|
-
*/ async revokeCompanyAccess(userId, companyId) {
|
|
75
|
+
/** Revoke user access to a company */ async revokeCompanyAccess(userId, companyId) {
|
|
86
76
|
const repository = await this.getRepository();
|
|
87
77
|
const permission = await repository.findOne({
|
|
88
78
|
where: {
|
|
@@ -96,12 +86,8 @@ export class UserPermissionService {
|
|
|
96
86
|
}
|
|
97
87
|
await repository.remove(permission);
|
|
98
88
|
}
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
// ==========================================================================
|
|
102
|
-
/**
|
|
103
|
-
* Find all branches a user has access to
|
|
104
|
-
*/ async findUserBranches(userId) {
|
|
89
|
+
// Branch Permissions
|
|
90
|
+
/** Find all branches a user has access to */ async findUserBranches(userId) {
|
|
105
91
|
const repository = await this.getRepository();
|
|
106
92
|
return repository.find({
|
|
107
93
|
where: {
|
|
@@ -116,9 +102,7 @@ export class UserPermissionService {
|
|
|
116
102
|
}
|
|
117
103
|
});
|
|
118
104
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Assign user to a branch
|
|
121
|
-
*/ async assignUserToBranch(dto) {
|
|
105
|
+
/** Assign user to a branch */ async assignUserToBranch(dto) {
|
|
122
106
|
const repository = await this.getRepository();
|
|
123
107
|
// Check if already exists
|
|
124
108
|
const existing = await repository.findOne({
|
|
@@ -139,9 +123,7 @@ export class UserPermissionService {
|
|
|
139
123
|
});
|
|
140
124
|
await repository.save(permission);
|
|
141
125
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Revoke user access to a branch
|
|
144
|
-
*/ async revokeBranchAccess(userId, branchId) {
|
|
126
|
+
/** Revoke user access to a branch */ async revokeBranchAccess(userId, branchId) {
|
|
145
127
|
const repository = await this.getRepository();
|
|
146
128
|
const permission = await repository.findOne({
|
|
147
129
|
where: {
|
|
@@ -158,10 +140,8 @@ export class UserPermissionService {
|
|
|
158
140
|
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
159
141
|
constructor(dataSourceProvider){
|
|
160
142
|
_define_property(this, "dataSourceProvider", void 0);
|
|
161
|
-
_define_property(this, "logger", void 0);
|
|
162
143
|
_define_property(this, "_repository", void 0);
|
|
163
144
|
this.dataSourceProvider = dataSourceProvider;
|
|
164
|
-
this.logger = new Logger(UserPermissionService.name);
|
|
165
145
|
this._repository = null;
|
|
166
146
|
}
|
|
167
147
|
}
|