@flusys/nestjs-auth 1.0.0-beta → 1.0.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/README.md +590 -473
- package/cjs/config/auth.constants.js +12 -0
- package/cjs/controllers/authentication.controller.js +365 -24
- package/cjs/controllers/branch.controller.js +44 -1
- package/cjs/controllers/company-selection.controller.js +27 -20
- package/cjs/controllers/company.controller.js +44 -1
- package/cjs/controllers/user-permission.controller.js +82 -154
- package/cjs/controllers/user.controller.js +211 -7
- package/cjs/docs/auth-swagger.config.js +14 -7
- package/cjs/dtos/authentication.dto.js +114 -38
- package/cjs/dtos/index.js +0 -1
- 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 +3 -9
- package/cjs/entities/user-token.entity.js +129 -0
- package/cjs/interceptors/clear-token.interceptor.js +10 -23
- package/cjs/interceptors/set-token.interceptor.js +15 -55
- package/cjs/interfaces/auth-email-provider.interface.js +45 -0
- package/cjs/interfaces/index.js +2 -0
- package/cjs/interfaces/user-enricher.interface.js +4 -0
- package/cjs/modules/auth.module.js +65 -143
- package/cjs/services/auth-config.service.js +25 -27
- package/cjs/services/auth-datasource.provider.js +13 -23
- package/cjs/services/auth-email.service.js +456 -0
- package/cjs/services/authentication.service.js +297 -349
- package/cjs/services/branch.service.js +9 -4
- package/cjs/services/company-selection-session.service.js +1 -1
- package/cjs/services/index.js +1 -0
- package/cjs/services/user-permission.service.js +43 -73
- package/cjs/services/user.service.js +184 -34
- package/cjs/strategies/jwt.strategy.js +44 -44
- package/cjs/validators/password.validator.js +45 -0
- package/config/auth.constants.d.ts +3 -0
- package/controllers/authentication.controller.d.ts +16 -10
- package/controllers/company-selection.controller.d.ts +6 -2
- package/controllers/user-permission.controller.d.ts +5 -4
- package/controllers/user.controller.d.ts +33 -0
- package/dtos/authentication.dto.d.ts +20 -6
- package/dtos/company-branch.dto.d.ts +0 -1
- package/dtos/company.dto.d.ts +0 -1
- package/dtos/index.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 +1 -3
- package/entities/user-token.entity.d.ts +15 -0
- package/fesm/config/auth.constants.js +6 -2
- package/fesm/controllers/authentication.controller.js +368 -27
- package/fesm/controllers/branch.controller.js +45 -2
- package/fesm/controllers/company-selection.controller.js +28 -21
- package/fesm/controllers/company.controller.js +45 -2
- package/fesm/controllers/user-permission.controller.js +84 -156
- package/fesm/controllers/user.controller.js +214 -10
- package/fesm/docs/auth-swagger.config.js +14 -7
- package/fesm/dtos/authentication.dto.js +101 -39
- package/fesm/dtos/index.js +0 -1
- 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 +3 -9
- package/fesm/entities/user-token.entity.js +113 -0
- package/fesm/interceptors/clear-token.interceptor.js +9 -22
- package/fesm/interceptors/set-token.interceptor.js +14 -54
- package/fesm/interfaces/auth-email-provider.interface.js +38 -0
- package/fesm/interfaces/authentication.interface.js +1 -1
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/user-enricher.interface.js +26 -0
- package/fesm/modules/auth.module.js +67 -145
- package/fesm/services/auth-config.service.js +26 -28
- package/fesm/services/auth-datasource.provider.js +14 -24
- package/fesm/services/auth-email.service.js +405 -0
- package/fesm/services/authentication.service.js +297 -349
- package/fesm/services/branch.service.js +9 -4
- package/fesm/services/company-selection-session.service.js +1 -1
- package/fesm/services/index.js +1 -0
- package/fesm/services/user-permission.service.js +44 -74
- package/fesm/services/user.service.js +186 -36
- package/fesm/strategies/jwt.strategy.js +44 -44
- package/fesm/validators/password.validator.js +48 -0
- package/interceptors/clear-token.interceptor.d.ts +0 -1
- package/interceptors/set-token.interceptor.d.ts +1 -1
- 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 +13 -3
- 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 +6 -3
- package/package.json +4 -4
- package/services/auth-config.service.d.ts +7 -8
- package/services/auth-datasource.provider.d.ts +2 -4
- package/services/auth-email.service.d.ts +54 -0
- package/services/authentication.service.d.ts +27 -16
- package/services/company-selection-session.service.d.ts +1 -1
- package/services/index.d.ts +1 -0
- package/services/user-permission.service.d.ts +6 -9
- package/services/user.service.d.ts +19 -3
- package/strategies/jwt.strategy.d.ts +4 -1
- package/validators/password.validator.d.ts +10 -0
- package/cjs/dtos/user-company-permission.dto.js +0 -110
- package/dtos/user-company-permission.dto.d.ts +0 -10
- package/fesm/dtos/user-company-permission.dto.js +0 -98
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { registerDecorator } from 'class-validator';
|
|
2
|
+
/**
|
|
3
|
+
* Strong password validation decorator.
|
|
4
|
+
* Validates that passwords meet complexity requirements to prevent weak passwords.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* @IsStrongPassword()
|
|
9
|
+
* password!: string;
|
|
10
|
+
*
|
|
11
|
+
* // With custom options
|
|
12
|
+
* @IsStrongPassword({ minLength: 12, requireSpecialChar: false })
|
|
13
|
+
* password!: string;
|
|
14
|
+
* ```
|
|
15
|
+
*/ export function IsStrongPassword(options = {}, validationOptions) {
|
|
16
|
+
const { minLength = 8, maxLength = 128, requireUppercase = true, requireLowercase = true, requireNumber = true, requireSpecialChar = true } = options;
|
|
17
|
+
return function(object, propertyName) {
|
|
18
|
+
registerDecorator({
|
|
19
|
+
name: 'isStrongPassword',
|
|
20
|
+
target: object.constructor,
|
|
21
|
+
propertyName: propertyName,
|
|
22
|
+
options: validationOptions,
|
|
23
|
+
validator: {
|
|
24
|
+
validate (value) {
|
|
25
|
+
if (typeof value !== 'string') return false;
|
|
26
|
+
const checks = [
|
|
27
|
+
value.length >= minLength,
|
|
28
|
+
value.length <= maxLength,
|
|
29
|
+
!requireUppercase || /[A-Z]/.test(value),
|
|
30
|
+
!requireLowercase || /[a-z]/.test(value),
|
|
31
|
+
!requireNumber || /[0-9]/.test(value),
|
|
32
|
+
!requireSpecialChar || /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~`]/.test(value)
|
|
33
|
+
];
|
|
34
|
+
return checks.every(Boolean);
|
|
35
|
+
},
|
|
36
|
+
defaultMessage (args) {
|
|
37
|
+
const requirements = [];
|
|
38
|
+
if (minLength > 0) requirements.push(`at least ${minLength} characters`);
|
|
39
|
+
if (requireUppercase) requirements.push('one uppercase letter');
|
|
40
|
+
if (requireLowercase) requirements.push('one lowercase letter');
|
|
41
|
+
if (requireNumber) requirements.push('one number');
|
|
42
|
+
if (requireSpecialChar) requirements.push('one special character (!@#$%^&*...)');
|
|
43
|
+
return `Password must contain ${requirements.join(', ')}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -5,7 +5,7 @@ export declare class SetToken implements NestInterceptor {
|
|
|
5
5
|
private readonly authConfig?;
|
|
6
6
|
constructor(authConfig?: AuthConfigService);
|
|
7
7
|
private get cookieName();
|
|
8
|
+
private get maxAgeMs();
|
|
8
9
|
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
9
|
-
private isBrowserRequest;
|
|
10
10
|
private setRefreshTokenCookie;
|
|
11
11
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface IAuthEmailProvider {
|
|
2
|
+
sendPasswordResetEmail(email: string, token: string, resetUrl: string): Promise<void>;
|
|
3
|
+
sendVerificationEmail(email: string, token: string, verifyUrl: string): Promise<void>;
|
|
4
|
+
sendWelcomeEmail?(email: string, name: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare const AUTH_EMAIL_PROVIDER = "AUTH_EMAIL_PROVIDER";
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { IBootstrapAppConfig, IDataSourceServiceOptions, IDynamicModuleConfig, IModuleOptionsFactory } from '@flusys/nestjs-core';
|
|
2
|
-
import { ModuleMetadata, Type } from '@nestjs/common';
|
|
2
|
+
import { ModuleMetadata, Provider, Type } from '@nestjs/common';
|
|
3
3
|
export interface IAuthModuleConfig extends IDataSourceServiceOptions {
|
|
4
4
|
jwtSecret?: string;
|
|
5
5
|
jwtExpiration?: string;
|
|
6
6
|
refreshTokenSecret?: string;
|
|
7
7
|
refreshTokenExpiration?: string;
|
|
8
8
|
refreshTokenCookieName?: string;
|
|
9
|
+
frontendUrl?: string;
|
|
9
10
|
}
|
|
10
11
|
export interface AuthModuleOptions extends IDynamicModuleConfig {
|
|
11
12
|
bootstrapAppConfig?: IBootstrapAppConfig;
|
|
12
13
|
config?: IAuthModuleConfig;
|
|
14
|
+
providers?: Provider[];
|
|
13
15
|
}
|
|
14
16
|
export interface AuthOptionsFactory extends IModuleOptionsFactory<IAuthModuleConfig> {
|
|
15
17
|
createAuthOptions(): Promise<IAuthModuleConfig> | IAuthModuleConfig;
|
|
@@ -21,4 +23,5 @@ export interface AuthModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'>,
|
|
|
21
23
|
inject?: any[];
|
|
22
24
|
useClass?: Type<AuthOptionsFactory>;
|
|
23
25
|
useExisting?: Type<AuthOptionsFactory>;
|
|
26
|
+
providers?: Provider[];
|
|
24
27
|
}
|
|
@@ -22,7 +22,6 @@ export interface LoginResponse {
|
|
|
22
22
|
user: IUserMini;
|
|
23
23
|
company?: ICompanyMini;
|
|
24
24
|
branch?: ICompanyBranchMini;
|
|
25
|
-
companyFeatureEnabled?: boolean;
|
|
26
25
|
}
|
|
27
26
|
export interface MeResponse {
|
|
28
27
|
user: IUserMini;
|
|
@@ -33,14 +32,12 @@ export interface BranchForSelection {
|
|
|
33
32
|
id: string;
|
|
34
33
|
name: string;
|
|
35
34
|
slug: string;
|
|
36
|
-
isActive: boolean;
|
|
37
35
|
logoId?: string | null;
|
|
38
36
|
}
|
|
39
37
|
export interface CompanyWithBranches {
|
|
40
38
|
id: string;
|
|
41
39
|
name: string;
|
|
42
40
|
slug: string;
|
|
43
|
-
isActive: boolean;
|
|
44
41
|
logoId?: string | null;
|
|
45
42
|
branches: BranchForSelection[];
|
|
46
43
|
}
|
|
@@ -51,3 +48,16 @@ export interface LoginResponseRequiresSelection {
|
|
|
51
48
|
user: IUserMini;
|
|
52
49
|
companies: CompanyWithBranches[];
|
|
53
50
|
}
|
|
51
|
+
export interface RegistrationResponse {
|
|
52
|
+
accessToken?: string;
|
|
53
|
+
refreshToken?: string;
|
|
54
|
+
user: IUserMini;
|
|
55
|
+
company?: ICompanyMini;
|
|
56
|
+
branch?: ICompanyBranchMini;
|
|
57
|
+
requiresEmailVerification?: boolean;
|
|
58
|
+
}
|
|
59
|
+
export interface LoginResponseRequiresEmailVerification {
|
|
60
|
+
requiresEmailVerification: true;
|
|
61
|
+
email: string;
|
|
62
|
+
message: string;
|
|
63
|
+
}
|
package/interfaces/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from './authentication.interface';
|
|
2
|
+
export * from './auth-email-provider.interface';
|
|
2
3
|
export * from './company-branch.interface';
|
|
3
4
|
export * from './company.interface';
|
|
4
5
|
export * from './user.interface';
|
|
6
|
+
export * from './user-enricher.interface';
|
|
5
7
|
export * from './auth-module-options.interface';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
2
|
+
import { QueryRunner, SelectQueryBuilder } from 'typeorm';
|
|
3
|
+
import { User } from '../entities/user.entity';
|
|
4
|
+
import { IUser } from './user.interface';
|
|
5
|
+
export interface IProfileSection {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
order: number;
|
|
9
|
+
icon?: string;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
hasFileUpload?: boolean;
|
|
12
|
+
editPermission?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface IProfileSectionData {
|
|
15
|
+
sectionId: string;
|
|
16
|
+
data: Record<string, any>;
|
|
17
|
+
isComplete: boolean;
|
|
18
|
+
files?: IProfileFile[];
|
|
19
|
+
}
|
|
20
|
+
export interface IProfileFile {
|
|
21
|
+
field: string;
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
type?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface IProfileExtras {
|
|
28
|
+
roles?: IProfileRole[];
|
|
29
|
+
actions?: IProfileAction[];
|
|
30
|
+
sections?: IProfileSectionData[];
|
|
31
|
+
completionPercentage?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface IProfileRole {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
description?: string | null;
|
|
37
|
+
}
|
|
38
|
+
export interface IProfileAction {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
code: string;
|
|
42
|
+
description?: string | null;
|
|
43
|
+
}
|
|
44
|
+
export type IEnrichedUser = IUser & IProfileExtras;
|
|
45
|
+
export interface IUserEnricher {
|
|
46
|
+
enrichListQuery?(query: SelectQueryBuilder<User>, user: ILoggedUserInfo | null): Promise<{
|
|
47
|
+
extraFields: string[];
|
|
48
|
+
}>;
|
|
49
|
+
enrichListItems?(users: IUser[], user: ILoggedUserInfo | null): Promise<IEnrichedUser[]>;
|
|
50
|
+
getProfileExtras?(userId: string, user: ILoggedUserInfo): Promise<IProfileExtras>;
|
|
51
|
+
updateProfileExtras?(userId: string, extras: Record<string, any>, queryRunner: QueryRunner): Promise<void>;
|
|
52
|
+
validateProfileExtras?(userId: string, extras: Record<string, any>, user: ILoggedUserInfo): Promise<void>;
|
|
53
|
+
getProfileSections?(): IProfileSection[];
|
|
54
|
+
getProfileSectionData?(userId: string, sectionId: string, user: ILoggedUserInfo): Promise<IProfileSectionData>;
|
|
55
|
+
updateProfileSection?(userId: string, sectionId: string, data: Record<string, any>, queryRunner: QueryRunner): Promise<void>;
|
|
56
|
+
handleSectionFileUpload?(userId: string, sectionId: string, field: string, fileInfo: {
|
|
57
|
+
name: string;
|
|
58
|
+
url: string;
|
|
59
|
+
size: number;
|
|
60
|
+
type: string;
|
|
61
|
+
}, queryRunner: QueryRunner): Promise<IProfileFile>;
|
|
62
|
+
handleSectionFileDelete?(userId: string, sectionId: string, field: string, fileId: string, queryRunner: QueryRunner): Promise<void>;
|
|
63
|
+
calculateProfileCompletion?(userId: string, user: ILoggedUserInfo): Promise<number>;
|
|
64
|
+
}
|
package/modules/auth.module.d.ts
CHANGED
|
@@ -2,9 +2,12 @@ import { DynamicModule } from '@nestjs/common';
|
|
|
2
2
|
import { AuthModuleAsyncOptions, AuthModuleOptions } from '../interfaces/auth-module-options.interface';
|
|
3
3
|
export declare class AuthModule {
|
|
4
4
|
static forRoot(options: AuthModuleOptions): DynamicModule;
|
|
5
|
-
static forRootAsync(
|
|
6
|
-
private static
|
|
5
|
+
static forRootAsync(options: AuthModuleAsyncOptions): DynamicModule;
|
|
6
|
+
private static buildModule;
|
|
7
|
+
private static buildImports;
|
|
8
|
+
private static buildControllers;
|
|
9
|
+
private static buildProviders;
|
|
10
|
+
private static buildExports;
|
|
7
11
|
private static createAsyncProviders;
|
|
8
|
-
private static getRepositoryProviders;
|
|
9
12
|
static getEntities(enableCompanyFeature?: boolean): any[];
|
|
10
13
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-auth",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Authentication and authorization infrastructure for NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -84,14 +84,14 @@
|
|
|
84
84
|
"bcrypt": "^5.0.0 || ^6.0.0",
|
|
85
85
|
"class-transformer": "^0.5.0",
|
|
86
86
|
"class-validator": "^0.14.0",
|
|
87
|
-
"nodemailer": "^
|
|
87
|
+
"nodemailer": "^7.0.0",
|
|
88
88
|
"passport": "^0.7.0",
|
|
89
89
|
"passport-jwt": "^4.0.0",
|
|
90
90
|
"passport-local": "^1.0.0",
|
|
91
91
|
"typeorm": "^0.3.0"
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
|
-
"@flusys/nestjs-core": "1.0.0
|
|
95
|
-
"@flusys/nestjs-shared": "1.0.0
|
|
94
|
+
"@flusys/nestjs-core": "1.0.0",
|
|
95
|
+
"@flusys/nestjs-shared": "1.0.0"
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { DatabaseMode
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { DatabaseMode } from '@flusys/nestjs-core';
|
|
2
|
+
import { IModuleConfigService } from '@flusys/nestjs-shared/interfaces';
|
|
3
|
+
import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
|
|
4
|
+
export declare class AuthConfigService implements IModuleConfigService {
|
|
5
|
+
private readonly logger;
|
|
4
6
|
private readonly options;
|
|
5
7
|
private readonly config;
|
|
8
|
+
private refreshTokenSecretWarned;
|
|
6
9
|
constructor(injectedOptions?: AuthModuleOptions);
|
|
7
10
|
getDatabaseMode(): DatabaseMode;
|
|
8
11
|
isMultiTenant(): boolean;
|
|
@@ -12,9 +15,5 @@ export declare class AuthConfigService {
|
|
|
12
15
|
getRefreshTokenSecret(): string;
|
|
13
16
|
getRefreshTokenExpiration(): string;
|
|
14
17
|
getRefreshTokenCookieName(): string;
|
|
15
|
-
|
|
16
|
-
getTenantDefaultDatabaseConfig(): IDatabaseConfig | undefined;
|
|
17
|
-
getTenants(): ITenantDatabaseConfig[];
|
|
18
|
-
getOptions(): AuthModuleOptions;
|
|
19
|
-
getConfig(): IAuthModuleConfig;
|
|
18
|
+
getFrontendUrl(): string | undefined;
|
|
20
19
|
}
|
|
@@ -17,9 +17,7 @@ export declare class AuthDataSourceProvider extends MultiTenantDataSourceService
|
|
|
17
17
|
protected getSingleDataSource(): Promise<DataSource>;
|
|
18
18
|
protected getOrCreateTenantConnection(tenant: ITenantDatabaseConfig): Promise<DataSource>;
|
|
19
19
|
private static buildParentOptions;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
getEnableCompanyFeatureForCurrentTenant(): boolean;
|
|
23
|
-
getAuthEntities(enableCompanyFeature?: boolean): Promise<any[]>;
|
|
20
|
+
isCompanyFeatureEnabled(tenant?: ITenantDatabaseConfig): boolean;
|
|
21
|
+
getAuthEntities(): Promise<any[]>;
|
|
24
22
|
protected createDataSourceFromConfig(config: IDatabaseConfig): Promise<DataSource>;
|
|
25
23
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { PendingRegistration } from '../entities/pending-registration.entity';
|
|
2
|
+
import { IAuthEmailProvider } from '../interfaces';
|
|
3
|
+
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
4
|
+
export declare class AuthEmailService {
|
|
5
|
+
private readonly dataSourceProvider?;
|
|
6
|
+
private readonly emailProvider?;
|
|
7
|
+
private readonly logger;
|
|
8
|
+
private readonly PASSWORD_RESET_EXPIRY;
|
|
9
|
+
private readonly EMAIL_VERIFICATION_EXPIRY;
|
|
10
|
+
constructor(dataSourceProvider?: AuthDataSourceProvider, emailProvider?: IAuthEmailProvider);
|
|
11
|
+
isEmailEnabled(): boolean;
|
|
12
|
+
private getRepository;
|
|
13
|
+
private generateToken;
|
|
14
|
+
private hashToken;
|
|
15
|
+
private getErrorMessage;
|
|
16
|
+
private assertEmailEnabled;
|
|
17
|
+
private sendVerificationEmailSafe;
|
|
18
|
+
private validateTokenNotExpiredOrUsed;
|
|
19
|
+
hasPendingRegistration(email: string): Promise<boolean>;
|
|
20
|
+
createPendingRegistration(data: {
|
|
21
|
+
email: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
phone?: string;
|
|
24
|
+
password: string;
|
|
25
|
+
companyData?: PendingRegistration['companyData'];
|
|
26
|
+
verifyUrlBase: string;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
success: boolean;
|
|
29
|
+
message: string;
|
|
30
|
+
}>;
|
|
31
|
+
forgotPassword(email: string, resetUrlBase: string): Promise<{
|
|
32
|
+
success: boolean;
|
|
33
|
+
message: string;
|
|
34
|
+
}>;
|
|
35
|
+
resetPassword(token: string, newPassword: string): Promise<{
|
|
36
|
+
success: boolean;
|
|
37
|
+
message: string;
|
|
38
|
+
}>;
|
|
39
|
+
verifyEmail(token: string): Promise<{
|
|
40
|
+
type: 'pending';
|
|
41
|
+
pending: PendingRegistration;
|
|
42
|
+
} | {
|
|
43
|
+
type: 'verified';
|
|
44
|
+
message: string;
|
|
45
|
+
}>;
|
|
46
|
+
resendVerificationEmail(email: string, verifyUrlBase: string): Promise<{
|
|
47
|
+
success: boolean;
|
|
48
|
+
message: string;
|
|
49
|
+
}>;
|
|
50
|
+
cleanupExpired(): Promise<{
|
|
51
|
+
deletedTokens: number;
|
|
52
|
+
deletedPending: number;
|
|
53
|
+
}>;
|
|
54
|
+
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
import { HybridCache } from '@flusys/nestjs-shared/classes';
|
|
1
2
|
import { JwtService } from '@nestjs/jwt';
|
|
2
|
-
import { Repository } from 'typeorm';
|
|
3
|
-
import { AuthConfigService } from './auth-config.service';
|
|
4
|
-
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
5
3
|
import { RegistrationDto } from '../dtos/authentication.dto';
|
|
6
|
-
import { HybridCache } from '@flusys/nestjs-shared/classes';
|
|
7
|
-
import { LoginResponse, LoginResponseRequiresSelection, MeResponse } from '../interfaces/authentication.interface';
|
|
8
4
|
import { CompanyBranch } from '../entities/company-branch.entity';
|
|
9
5
|
import { Company } from '../entities/company.entity';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
6
|
+
import { PendingRegistration } from '../entities/pending-registration.entity';
|
|
7
|
+
import { LoginResponse, LoginResponseRequiresEmailVerification, LoginResponseRequiresSelection, MeResponse, RegistrationResponse } from '../interfaces/authentication.interface';
|
|
8
|
+
import { AuthConfigService } from './auth-config.service';
|
|
9
|
+
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
10
|
+
import { AuthEmailService } from './auth-email.service';
|
|
12
11
|
import { CompanySelectionSessionService } from './company-selection-session.service';
|
|
13
12
|
export declare class AuthenticationService {
|
|
14
13
|
private readonly jwtService;
|
|
@@ -16,23 +15,29 @@ export declare class AuthenticationService {
|
|
|
16
15
|
private readonly cacheManager?;
|
|
17
16
|
private readonly dataSourceProvider?;
|
|
18
17
|
private readonly sessionService?;
|
|
19
|
-
private readonly
|
|
20
|
-
private readonly injectedPermissionRepository?;
|
|
21
|
-
private readonly injectedCompanyRepository?;
|
|
22
|
-
private readonly injectedBranchRepository?;
|
|
18
|
+
private readonly authEmailService?;
|
|
23
19
|
private readonly logger;
|
|
24
|
-
constructor(jwtService: JwtService, authConfig: AuthConfigService, cacheManager?: HybridCache, dataSourceProvider?: AuthDataSourceProvider, sessionService?: CompanySelectionSessionService,
|
|
20
|
+
constructor(jwtService: JwtService, authConfig: AuthConfigService, cacheManager?: HybridCache, dataSourceProvider?: AuthDataSourceProvider, sessionService?: CompanySelectionSessionService, authEmailService?: AuthEmailService);
|
|
21
|
+
private isCompanyFeatureEnabled;
|
|
25
22
|
private getUserRepository;
|
|
26
23
|
private getPermissionRepository;
|
|
27
24
|
private getCompanyRepository;
|
|
28
25
|
private getBranchRepository;
|
|
29
|
-
login(email: string, password: string): Promise<LoginResponse | LoginResponseRequiresSelection>;
|
|
26
|
+
login(email: string, password: string): Promise<LoginResponse | LoginResponseRequiresSelection | LoginResponseRequiresEmailVerification>;
|
|
30
27
|
private handleCompanyBasedLogin;
|
|
31
|
-
register(dto: RegistrationDto): Promise<
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
register(dto: RegistrationDto, verifyUrlBase?: string): Promise<RegistrationResponse | {
|
|
29
|
+
requiresEmailVerification: true;
|
|
30
|
+
message: string;
|
|
31
|
+
}>;
|
|
32
|
+
private handleExistingUserCompanyRegistration;
|
|
33
|
+
private createUserDirectly;
|
|
34
|
+
createUserFromPendingRegistration(pending: PendingRegistration): Promise<RegistrationResponse>;
|
|
35
|
+
private processCompanyRegistration;
|
|
36
|
+
private findOrCreateCompanyAndBranch;
|
|
37
|
+
private assignUserPermissions;
|
|
34
38
|
select(sessionId: string, companyId: string, branchId: string): Promise<LoginResponse>;
|
|
35
39
|
switchCompany(userId: string, companyId: string, branchId: string): Promise<LoginResponse>;
|
|
40
|
+
private validateAndLoginWithCompany;
|
|
36
41
|
refreshToken(refreshToken: string): Promise<{
|
|
37
42
|
accessToken: string;
|
|
38
43
|
refreshToken: string;
|
|
@@ -48,7 +53,13 @@ export declare class AuthenticationService {
|
|
|
48
53
|
getUserInfo(userId: string, companyId?: string, branchId?: string): Promise<MeResponse>;
|
|
49
54
|
private ensureCompanyFeatureEnabled;
|
|
50
55
|
private validateUser;
|
|
56
|
+
private toUserInfo;
|
|
57
|
+
private toCompanyInfo;
|
|
58
|
+
private toBranchInfo;
|
|
59
|
+
private generateTokens;
|
|
51
60
|
private generateLoginResponse;
|
|
52
61
|
private generateLoginResponseWithCompany;
|
|
53
62
|
private generateCompanySelectionResponse;
|
|
63
|
+
private generateRegistrationResponse;
|
|
64
|
+
private generateRegistrationResponseWithCompany;
|
|
54
65
|
}
|
|
@@ -8,7 +8,7 @@ interface StoredSession {
|
|
|
8
8
|
export declare class CompanySelectionSessionService {
|
|
9
9
|
protected cacheManager: HybridCache;
|
|
10
10
|
constructor(cacheManager: HybridCache);
|
|
11
|
-
createSession(userId: string
|
|
11
|
+
createSession(userId: string): Promise<string>;
|
|
12
12
|
getSession(sessionId: string): Promise<StoredSession | null>;
|
|
13
13
|
consumeSession(sessionId: string): Promise<StoredSession | null>;
|
|
14
14
|
deleteSession(sessionId: string): Promise<void>;
|
package/services/index.d.ts
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { UserCompanyPermission } from '../entities/user-company-permission.entity';
|
|
1
|
+
import { PermissionType, UserCompanyPermission } from '../entities/user-company-permission.entity';
|
|
3
2
|
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
4
3
|
export declare class UserPermissionService {
|
|
5
4
|
private readonly dataSourceProvider;
|
|
6
|
-
private readonly logger;
|
|
7
5
|
private _repository;
|
|
8
6
|
constructor(dataSourceProvider: AuthDataSourceProvider);
|
|
9
7
|
private getRepository;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
revokeBranchAccess(userId: string, branchId: string): Promise<void>;
|
|
8
|
+
findUserPermissions(userId: string, type: PermissionType): Promise<UserCompanyPermission[]>;
|
|
9
|
+
assignPermission(userId: string, targetId: string, type: PermissionType, metadata?: Record<string, any>): Promise<void>;
|
|
10
|
+
revokePermission(userId: string, targetId: string, type: PermissionType): Promise<void>;
|
|
11
|
+
findUserCompanies: (userId: string) => Promise<UserCompanyPermission[]>;
|
|
12
|
+
findUserBranches(userId: string, companyId?: string): Promise<UserCompanyPermission[]>;
|
|
16
13
|
}
|
|
@@ -6,23 +6,28 @@ import { AuthConfigService } from './auth-config.service';
|
|
|
6
6
|
import { AuthDataSourceProvider } from './auth-datasource.provider';
|
|
7
7
|
import { CreateUserDto, UpdateUserDto } from '../dtos/user.dto';
|
|
8
8
|
import { IUser } from '../interfaces/user.interface';
|
|
9
|
+
import { IEnrichedUser, IProfileExtras, IProfileSection, IProfileSectionData, IUserEnricher } from '../interfaces/user-enricher.interface';
|
|
9
10
|
import { User } from '../entities/user.entity';
|
|
10
11
|
export declare class UserService extends RequestScopedApiService<CreateUserDto, UpdateUserDto, IUser, User, Repository<User>> {
|
|
11
12
|
protected cacheManager: HybridCache;
|
|
12
13
|
protected utilsService: UtilsService;
|
|
13
14
|
private readonly dataSourceProvider;
|
|
14
15
|
private readonly authConfig;
|
|
16
|
+
private readonly userEnricher?;
|
|
15
17
|
private permissionRepository?;
|
|
16
18
|
private dataSource?;
|
|
17
|
-
constructor(cacheManager: HybridCache, utilsService: UtilsService, dataSourceProvider: AuthDataSourceProvider, authConfig: AuthConfigService);
|
|
19
|
+
constructor(cacheManager: HybridCache, utilsService: UtilsService, dataSourceProvider: AuthDataSourceProvider, authConfig: AuthConfigService, userEnricher?: IUserEnricher);
|
|
18
20
|
protected resolveEntity(): EntityTarget<User>;
|
|
19
21
|
protected getDataSourceProvider(): AuthDataSourceProvider;
|
|
20
22
|
protected ensureRepositoryInitialized(): Promise<void>;
|
|
23
|
+
private getUserForProfile;
|
|
21
24
|
verifyEmail(id: string): Promise<void>;
|
|
22
25
|
verifyPhone(id: string): Promise<void>;
|
|
23
26
|
updateStatus(id: string, isActive: boolean, user?: ILoggedUserInfo | null): Promise<void>;
|
|
24
|
-
protected convertSingleDtoToEntity(dto: CreateUserDto | UpdateUserDto, user:
|
|
27
|
+
protected convertSingleDtoToEntity(dto: CreateUserDto | UpdateUserDto, user: ILoggedUserInfo | null): Promise<User>;
|
|
25
28
|
protected convertEntityToResponseDto(entity: User, isRaw: boolean): IUser;
|
|
29
|
+
private convertRawToResponseDto;
|
|
30
|
+
private convertEntityToDto;
|
|
26
31
|
protected convertEntityListToResponseListDto(entities: User[], isRaw: boolean): IUser[];
|
|
27
32
|
protected getGlobalSearchQuery(query: any, search: string, _user: any): Promise<{
|
|
28
33
|
query: any;
|
|
@@ -33,5 +38,16 @@ export declare class UserService extends RequestScopedApiService<CreateUserDto,
|
|
|
33
38
|
isRaw: boolean;
|
|
34
39
|
}>;
|
|
35
40
|
insert(dto: CreateUserDto, user: ILoggedUserInfo | null): Promise<IUser>;
|
|
36
|
-
|
|
41
|
+
getProfileWithExtras(userId: string, user: ILoggedUserInfo): Promise<{
|
|
42
|
+
user: IUser;
|
|
43
|
+
extras?: IProfileExtras;
|
|
44
|
+
}>;
|
|
45
|
+
getEnrichedList(users: IUser[], user: ILoggedUserInfo | null): Promise<IEnrichedUser[]>;
|
|
46
|
+
getProfileSections(): Promise<IProfileSection[]>;
|
|
47
|
+
getProfileSectionData(userId: string, sectionId: string, user: ILoggedUserInfo): Promise<IProfileSectionData | null>;
|
|
48
|
+
updateProfileSection(userId: string, sectionId: string, data: Record<string, any>, user: ILoggedUserInfo): Promise<void>;
|
|
49
|
+
getProfileCompletion(userId: string, user: ILoggedUserInfo): Promise<number>;
|
|
50
|
+
profile(dto: UpdateUserDto & {
|
|
51
|
+
extras?: Record<string, any>;
|
|
52
|
+
}, user: ILoggedUserInfo): Promise<string>;
|
|
37
53
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
2
2
|
import { ModuleRef } from '@nestjs/core';
|
|
3
3
|
import { Request } from 'express';
|
|
4
|
-
import { AuthConfigService } from '../services/auth-config.service';
|
|
5
4
|
import { TokenPayload, TokenPayloadWithCompany } from '../interfaces/authentication.interface';
|
|
5
|
+
import { AuthConfigService } from '../services/auth-config.service';
|
|
6
6
|
declare const JwtStrategy_base: new (...args: any) => any;
|
|
7
7
|
export declare class JwtStrategy extends JwtStrategy_base {
|
|
8
8
|
private readonly authConfig;
|
|
9
9
|
private readonly moduleRef;
|
|
10
10
|
constructor(authConfig: AuthConfigService, moduleRef: ModuleRef);
|
|
11
11
|
validate(_req: Request, payload: TokenPayload | TokenPayloadWithCompany): Promise<ILoggedUserInfo>;
|
|
12
|
+
private resolveUserRepository;
|
|
13
|
+
private checkTokenRevocation;
|
|
14
|
+
private buildUserInfo;
|
|
12
15
|
}
|
|
13
16
|
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ValidationOptions } from 'class-validator';
|
|
2
|
+
export interface PasswordComplexityOptions {
|
|
3
|
+
minLength?: number;
|
|
4
|
+
maxLength?: number;
|
|
5
|
+
requireUppercase?: boolean;
|
|
6
|
+
requireLowercase?: boolean;
|
|
7
|
+
requireNumber?: boolean;
|
|
8
|
+
requireSpecialChar?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function IsStrongPassword(options?: PasswordComplexityOptions, validationOptions?: ValidationOptions): (object: object, propertyName: string) => void;
|