@flusys/nestjs-auth 0.1.0-beta.3 → 1.1.0-beta
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 +1 -11
- package/cjs/config/auth.constants.js +14 -4
- package/cjs/controllers/authentication.controller.js +173 -36
- package/cjs/controllers/branch.controller.js +3 -4
- package/cjs/controllers/company.controller.js +3 -4
- package/cjs/controllers/user-permission.controller.js +6 -18
- package/cjs/controllers/user.controller.js +168 -22
- package/cjs/dtos/authentication.dto.js +106 -3
- package/cjs/entities/index.js +5 -1
- package/cjs/entities/pending-registration.entity.js +125 -0
- package/cjs/entities/user-token.entity.js +129 -0
- 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 -2
- package/cjs/services/auth-config.service.js +22 -44
- package/cjs/services/auth-datasource.provider.js +17 -33
- package/cjs/services/auth-email.service.js +452 -0
- package/cjs/services/authentication.service.js +229 -115
- package/cjs/services/branch.service.js +10 -44
- package/cjs/services/company.service.js +7 -36
- package/cjs/services/index.js +1 -0
- package/cjs/services/user-permission.service.js +9 -27
- package/cjs/services/user.service.js +177 -99
- package/cjs/strategies/jwt.strategy.js +14 -1
- package/config/auth.constants.d.ts +3 -0
- package/controllers/authentication.controller.d.ts +13 -9
- package/controllers/user.controller.d.ts +27 -0
- package/dtos/authentication.dto.d.ts +21 -3
- package/dtos/user.dto.d.ts +1 -0
- package/entities/index.d.ts +7 -3
- package/entities/pending-registration.entity.d.ts +17 -0
- package/entities/user-token.entity.d.ts +15 -0
- package/fesm/config/auth.constants.js +18 -8
- package/fesm/controllers/authentication.controller.js +174 -37
- package/fesm/controllers/branch.controller.js +5 -6
- package/fesm/controllers/company.controller.js +5 -6
- package/fesm/controllers/user-permission.controller.js +6 -18
- package/fesm/controllers/user.controller.js +168 -22
- package/fesm/dtos/authentication.dto.js +109 -100
- package/fesm/entities/index.js +7 -1
- package/fesm/entities/pending-registration.entity.js +115 -0
- package/fesm/entities/user-token.entity.js +113 -0
- 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 +9 -3
- package/fesm/services/auth-config.service.js +22 -44
- package/fesm/services/auth-datasource.provider.js +17 -33
- package/fesm/services/auth-email.service.js +401 -0
- package/fesm/services/authentication.service.js +227 -113
- package/fesm/services/branch.service.js +11 -45
- package/fesm/services/company.service.js +8 -37
- package/fesm/services/index.js +1 -0
- package/fesm/services/user-permission.service.js +9 -27
- package/fesm/services/user.service.js +178 -100
- package/fesm/strategies/jwt.strategy.js +14 -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 +14 -0
- package/interfaces/index.d.ts +2 -0
- package/interfaces/user-enricher.interface.d.ts +67 -0
- package/interfaces/user.interface.d.ts +1 -0
- package/package.json +3 -3
- package/services/auth-config.service.d.ts +1 -0
- package/services/auth-email.service.d.ts +50 -0
- package/services/authentication.service.d.ts +21 -5
- package/services/branch.service.d.ts +2 -5
- package/services/company.service.d.ts +1 -4
- package/services/index.d.ts +1 -0
- package/services/user.service.d.ts +17 -6
|
@@ -14,6 +14,7 @@ const _passport = require("@nestjs/passport");
|
|
|
14
14
|
const _passportjwt = require("passport-jwt");
|
|
15
15
|
const _authconfigservice = require("../services/auth-config.service");
|
|
16
16
|
const _authdatasourceprovider = require("../services/auth-datasource.provider");
|
|
17
|
+
const _authenticationservice = require("../services/authentication.service");
|
|
17
18
|
const _userentity = require("../entities/user.entity");
|
|
18
19
|
function _define_property(obj, key, value) {
|
|
19
20
|
if (key in obj) {
|
|
@@ -44,8 +45,9 @@ function _ts_metadata(k, v) {
|
|
|
44
45
|
}
|
|
45
46
|
let JwtStrategy = class JwtStrategy extends (0, _passport.PassportStrategy)(_passportjwt.Strategy, 'jwt') {
|
|
46
47
|
async validate(_req, payload) {
|
|
47
|
-
// Resolve request-scoped
|
|
48
|
+
// Resolve request-scoped services for this request
|
|
48
49
|
let userRepository = null;
|
|
50
|
+
let authService = null;
|
|
49
51
|
try {
|
|
50
52
|
const dataSourceProvider = await this.moduleRef.resolve(_authdatasourceprovider.AuthDataSourceProvider, undefined, {
|
|
51
53
|
strict: false
|
|
@@ -53,12 +55,23 @@ let JwtStrategy = class JwtStrategy extends (0, _passport.PassportStrategy)(_pas
|
|
|
53
55
|
if (dataSourceProvider) {
|
|
54
56
|
userRepository = await dataSourceProvider.getRepository(_userentity.User);
|
|
55
57
|
}
|
|
58
|
+
// Resolve AuthenticationService for token revocation check
|
|
59
|
+
authService = await this.moduleRef.resolve(_authenticationservice.AuthenticationService, undefined, {
|
|
60
|
+
strict: false
|
|
61
|
+
});
|
|
56
62
|
} catch (error) {
|
|
57
63
|
throw new _common.UnauthorizedException('Unable to access user data');
|
|
58
64
|
}
|
|
59
65
|
if (!userRepository) {
|
|
60
66
|
throw new _common.UnauthorizedException('User repository not available');
|
|
61
67
|
}
|
|
68
|
+
// Check if token is revoked (logged out)
|
|
69
|
+
if (authService && payload.iat) {
|
|
70
|
+
const isRevoked = await authService.isTokenRevoked(payload.id, payload.iat);
|
|
71
|
+
if (isRevoked) {
|
|
72
|
+
throw new _common.UnauthorizedException('Token has been revoked');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
62
75
|
// Find user and check if active
|
|
63
76
|
const user = await userRepository.findOne({
|
|
64
77
|
where: {
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export declare const AUTH_MODULE_OPTIONS = "AUTH_MODULE_OPTIONS";
|
|
2
|
+
export declare const USER_ENRICHER = "USER_ENRICHER";
|
|
3
|
+
export declare const BCRYPT_SALT_ROUNDS = 12;
|
|
2
4
|
export declare const SESSION_CACHE_PREFIX = "auth:session";
|
|
5
|
+
export declare const TOKEN_REVOKED_PREFIX = "auth:revoked";
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
2
2
|
import { Request } from 'express';
|
|
3
|
-
import { ChangePasswordDto, CompanySelectionResponseDto, LoginDto, LoginResponseDto, MeResponseDto, RefreshTokenDto, RegistrationDto, RegistrationResponseDto } from '../dtos/authentication.dto';
|
|
3
|
+
import { ChangePasswordDto, CompanySelectionResponseDto, ForgotPasswordDto, LoginDto, LoginResponseDto, MeResponseDto, RefreshTokenDto, RegistrationDto, RegistrationResponseDto, ResendVerificationDto, ResetPasswordDto, VerifyEmailDto } from '../dtos/authentication.dto';
|
|
4
|
+
import { MessageResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
4
5
|
import { AuthConfigService } from '../services/auth-config.service';
|
|
6
|
+
import { AuthEmailService } from '../services/auth-email.service';
|
|
5
7
|
import { AuthenticationService } from '../services/authentication.service';
|
|
6
8
|
export declare class AuthenticationController {
|
|
7
9
|
private readonly authService;
|
|
8
10
|
private readonly authConfig?;
|
|
9
|
-
|
|
11
|
+
private readonly authEmailService?;
|
|
12
|
+
constructor(authService: AuthenticationService, authConfig?: AuthConfigService, authEmailService?: AuthEmailService);
|
|
13
|
+
private buildAuthUrl;
|
|
10
14
|
login(loginDto: LoginDto): Promise<LoginResponseDto | CompanySelectionResponseDto>;
|
|
11
|
-
register(registrationDto: RegistrationDto): Promise<RegistrationResponseDto>;
|
|
15
|
+
register(req: Request, registrationDto: RegistrationDto): Promise<RegistrationResponseDto>;
|
|
12
16
|
refreshToken(req: Request, refreshTokenDto: RefreshTokenDto): Promise<{
|
|
13
17
|
accessToken: string;
|
|
14
18
|
}>;
|
|
15
19
|
getCurrentUser(user: ILoggedUserInfo): Promise<MeResponseDto>;
|
|
16
|
-
logout(userId: string): Promise<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
logout(userId: string): Promise<MessageResponseDto>;
|
|
21
|
+
changePassword(userId: string, dto: ChangePasswordDto): Promise<MessageResponseDto>;
|
|
22
|
+
forgotPassword(req: Request, dto: ForgotPasswordDto): Promise<MessageResponseDto>;
|
|
23
|
+
resetPassword(dto: ResetPasswordDto): Promise<MessageResponseDto>;
|
|
24
|
+
resendVerification(req: Request, dto: ResendVerificationDto): Promise<MessageResponseDto>;
|
|
25
|
+
verifyEmail(dto: VerifyEmailDto): Promise<MessageResponseDto | RegistrationResponseDto>;
|
|
22
26
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
2
2
|
import { CreateUserDto, UpdateUserDto, UserResponseDto } from '../dtos/user.dto';
|
|
3
|
+
import { IUser } from '../interfaces/user.interface';
|
|
3
4
|
import { UserService } from '../services/user.service';
|
|
4
5
|
declare const UserController_base: abstract new (service: UserService) => {
|
|
5
6
|
service: UserService;
|
|
@@ -14,6 +15,13 @@ declare const UserController_base: abstract new (service: UserService) => {
|
|
|
14
15
|
export declare class UserController extends UserController_base {
|
|
15
16
|
service: UserService;
|
|
16
17
|
constructor(service: UserService);
|
|
18
|
+
getProfileWithExtras(id: string, user: ILoggedUserInfo): Promise<{
|
|
19
|
+
success: boolean;
|
|
20
|
+
data: {
|
|
21
|
+
user: IUser;
|
|
22
|
+
extras?: import("..").IProfileExtras;
|
|
23
|
+
};
|
|
24
|
+
}>;
|
|
17
25
|
verifyEmail(id: string): Promise<{
|
|
18
26
|
message: string;
|
|
19
27
|
}>;
|
|
@@ -24,8 +32,27 @@ export declare class UserController extends UserController_base {
|
|
|
24
32
|
message: string;
|
|
25
33
|
}>;
|
|
26
34
|
profile(dto: UpdateUserDto, user: ILoggedUserInfo): Promise<{
|
|
35
|
+
success: boolean;
|
|
27
36
|
message: string;
|
|
28
37
|
data: string;
|
|
29
38
|
}>;
|
|
39
|
+
getProfileSections(): Promise<{
|
|
40
|
+
success: boolean;
|
|
41
|
+
data: import("..").IProfileSection[];
|
|
42
|
+
}>;
|
|
43
|
+
getProfileSectionData(id: string, sectionId: string, user: ILoggedUserInfo): Promise<{
|
|
44
|
+
success: boolean;
|
|
45
|
+
data: import("..").IProfileSectionData;
|
|
46
|
+
}>;
|
|
47
|
+
updateProfileSection(id: string, sectionId: string, data: Record<string, any>, user: ILoggedUserInfo): Promise<{
|
|
48
|
+
success: boolean;
|
|
49
|
+
message: string;
|
|
50
|
+
}>;
|
|
51
|
+
getProfileCompletion(id: string, user: ILoggedUserInfo): Promise<{
|
|
52
|
+
success: boolean;
|
|
53
|
+
data: {
|
|
54
|
+
completionPercentage: number;
|
|
55
|
+
};
|
|
56
|
+
}>;
|
|
30
57
|
}
|
|
31
58
|
export {};
|
|
@@ -71,12 +71,13 @@ export declare class LoginResponseDto {
|
|
|
71
71
|
companyFeatureEnabled?: boolean;
|
|
72
72
|
}
|
|
73
73
|
export declare class RegistrationResponseDto {
|
|
74
|
-
accessToken
|
|
75
|
-
refreshToken
|
|
74
|
+
accessToken?: string;
|
|
75
|
+
refreshToken?: string;
|
|
76
76
|
user: UserInfoDto;
|
|
77
77
|
company?: CompanyInfoDto;
|
|
78
78
|
branch?: BranchInfoDto;
|
|
79
|
-
companyFeatureEnabled
|
|
79
|
+
companyFeatureEnabled?: boolean;
|
|
80
|
+
requiresEmailVerification?: boolean;
|
|
80
81
|
}
|
|
81
82
|
export declare class MeResponseDto {
|
|
82
83
|
user: UserInfoDto;
|
|
@@ -90,3 +91,20 @@ export declare class CompanySelectionResponseDto {
|
|
|
90
91
|
user: UserInfoDto;
|
|
91
92
|
companies: CompanyWithBranchesDto[];
|
|
92
93
|
}
|
|
94
|
+
export declare class LoginResponseRequiresEmailVerificationDto {
|
|
95
|
+
requiresEmailVerification: true;
|
|
96
|
+
email: string;
|
|
97
|
+
message: string;
|
|
98
|
+
}
|
|
99
|
+
export declare class ForgotPasswordDto {
|
|
100
|
+
email: string;
|
|
101
|
+
}
|
|
102
|
+
export declare class ResetPasswordDto {
|
|
103
|
+
token: string;
|
|
104
|
+
newPassword: string;
|
|
105
|
+
}
|
|
106
|
+
export declare class VerifyEmailDto {
|
|
107
|
+
token: string;
|
|
108
|
+
}
|
|
109
|
+
export declare class ResendVerificationDto extends ForgotPasswordDto {
|
|
110
|
+
}
|
package/dtos/user.dto.d.ts
CHANGED
package/entities/index.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
export * from './company-branch.entity';
|
|
2
2
|
export * from './company.entity';
|
|
3
|
+
export * from './pending-registration.entity';
|
|
3
4
|
export { PermissionType, UserCompanyPermission } from './user-company-permission.entity';
|
|
4
5
|
export * from './user.entity';
|
|
6
|
+
export * from './user-token.entity';
|
|
5
7
|
import { CompanyBranch } from './company-branch.entity';
|
|
6
8
|
import { Company } from './company.entity';
|
|
9
|
+
import { PendingRegistration } from './pending-registration.entity';
|
|
7
10
|
import { UserCompanyPermission } from './user-company-permission.entity';
|
|
8
11
|
import { User } from './user.entity';
|
|
9
|
-
|
|
12
|
+
import { UserToken } from './user-token.entity';
|
|
13
|
+
export declare const CoreEntities: (typeof PendingRegistration | typeof User | typeof UserToken)[];
|
|
10
14
|
export declare const CompanyEntities: (typeof Company | typeof CompanyBranch | typeof UserCompanyPermission)[];
|
|
11
|
-
export declare const AllEntities: (typeof Company | typeof CompanyBranch | typeof User | typeof UserCompanyPermission)[];
|
|
12
|
-
export declare function getEntitiesByConfig(enableCompanyFeature: boolean): (typeof Company | typeof CompanyBranch | typeof User | typeof UserCompanyPermission)[];
|
|
15
|
+
export declare const AllEntities: (typeof Company | typeof CompanyBranch | typeof PendingRegistration | typeof User | typeof UserCompanyPermission | typeof UserToken)[];
|
|
16
|
+
export declare function getEntitiesByConfig(enableCompanyFeature: boolean): (typeof Company | typeof CompanyBranch | typeof PendingRegistration | typeof User | typeof UserCompanyPermission | typeof UserToken)[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class PendingRegistration {
|
|
2
|
+
id: string;
|
|
3
|
+
email: string;
|
|
4
|
+
name: string | null;
|
|
5
|
+
phone: string | null;
|
|
6
|
+
passwordHash: string;
|
|
7
|
+
token: string;
|
|
8
|
+
expiresAt: Date;
|
|
9
|
+
companyData: {
|
|
10
|
+
companySlug?: string;
|
|
11
|
+
branchSlug?: string;
|
|
12
|
+
newCompanyName?: string;
|
|
13
|
+
newCompanyPhone?: string;
|
|
14
|
+
newCompanyAddress?: string;
|
|
15
|
+
} | null;
|
|
16
|
+
createdAt: Date;
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare enum TokenType {
|
|
2
|
+
PASSWORD_RESET = "password_reset",
|
|
3
|
+
EMAIL_VERIFICATION = "email_verification",
|
|
4
|
+
EMAIL_CHANGE = "email_change"
|
|
5
|
+
}
|
|
6
|
+
export declare class UserToken {
|
|
7
|
+
id: string;
|
|
8
|
+
userId: string;
|
|
9
|
+
type: TokenType;
|
|
10
|
+
token: string;
|
|
11
|
+
expiresAt: Date;
|
|
12
|
+
usedAt: Date | null;
|
|
13
|
+
metadata: string | null;
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
// Injection Tokens
|
|
2
|
+
export const AUTH_MODULE_OPTIONS = 'AUTH_MODULE_OPTIONS';
|
|
3
|
+
/**
|
|
4
|
+
* User Enricher Provider Token
|
|
5
|
+
*
|
|
6
|
+
* Optional provider for extending user list and profile.
|
|
7
|
+
* Consuming apps can provide their own implementation.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* providers: [
|
|
11
|
+
* { provide: USER_ENRICHER, useClass: MyUserEnricher },
|
|
12
|
+
* ]
|
|
13
|
+
*/ export const USER_ENRICHER = 'USER_ENRICHER';
|
|
14
|
+
// Security Configuration
|
|
15
|
+
/** Bcrypt salt rounds (12 = ~250ms hashing time) */ export const BCRYPT_SALT_ROUNDS = 12;
|
|
16
|
+
// Cache Key Prefixes
|
|
17
|
+
export const SESSION_CACHE_PREFIX = 'auth:session';
|
|
18
|
+
export const TOKEN_REVOKED_PREFIX = 'auth:revoked';
|
|
@@ -31,43 +31,35 @@ import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
|
31
31
|
import { Body, Controller, Get, HttpCode, HttpStatus, Inject, Optional, Post, Req, UnauthorizedException, UseGuards, UseInterceptors } from '@nestjs/common';
|
|
32
32
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
33
33
|
import { Request } from 'express';
|
|
34
|
-
import { ChangePasswordDto, CompanySelectionResponseDto, LoginDto, LoginResponseDto, MeResponseDto, RefreshTokenDto, RegistrationDto, RegistrationResponseDto } from '../dtos/authentication.dto';
|
|
34
|
+
import { ChangePasswordDto, CompanySelectionResponseDto, ForgotPasswordDto, LoginDto, LoginResponseDto, MeResponseDto, RefreshTokenDto, RegistrationDto, RegistrationResponseDto, ResendVerificationDto, ResetPasswordDto, VerifyEmailDto } from '../dtos/authentication.dto';
|
|
35
|
+
import { MessageResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
35
36
|
import { ClearToken } from '../interceptors/clear-token.interceptor';
|
|
36
37
|
import { SetToken } from '../interceptors/set-token.interceptor';
|
|
37
38
|
import { AuthConfigService } from '../services/auth-config.service';
|
|
39
|
+
import { AuthEmailService } from '../services/auth-email.service';
|
|
38
40
|
import { AuthenticationService } from '../services/authentication.service';
|
|
39
41
|
export class AuthenticationController {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* Browser: refreshToken set in HTTP-only cookie, not in response body
|
|
47
|
-
* API/Mobile: refreshToken included in response body
|
|
48
|
-
*/ async login(loginDto) {
|
|
42
|
+
/** Build auth URL for email links */ buildAuthUrl(req, path) {
|
|
43
|
+
const frontendUrl = this.authConfig?.getFrontendUrl();
|
|
44
|
+
return frontendUrl ? `${frontendUrl}${path}` : `${req.protocol}://${req.get('host')}${path}`;
|
|
45
|
+
}
|
|
46
|
+
// Core Endpoints
|
|
47
|
+
/** Login - Returns tokens or company/branch selection requirement */ async login(loginDto) {
|
|
49
48
|
const result = await this.authService.login(loginDto.email, loginDto.password);
|
|
50
49
|
if ('requiresSelection' in result) {
|
|
51
50
|
return result;
|
|
52
51
|
}
|
|
53
52
|
return result;
|
|
54
53
|
}
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* Browser: refreshToken set in HTTP-only cookie
|
|
59
|
-
*/ async register(registrationDto) {
|
|
60
|
-
const result = await this.authService.register(registrationDto);
|
|
54
|
+
/** Register new user. If company feature enabled, can join/create company. */ async register(req, registrationDto) {
|
|
55
|
+
const verifyUrlBase = this.buildAuthUrl(req, '/auth/verify-email');
|
|
56
|
+
const result = await this.authService.register(registrationDto, verifyUrlBase);
|
|
61
57
|
return {
|
|
62
58
|
...result,
|
|
63
59
|
companyFeatureEnabled: this.authConfig?.isCompanyFeatureEnabled() ?? false
|
|
64
60
|
};
|
|
65
61
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Refresh access token
|
|
68
|
-
* Browser: Gets refreshToken from HTTP-only cookie
|
|
69
|
-
* API/Mobile: Gets refreshToken from request body
|
|
70
|
-
*/ async refreshToken(req, refreshTokenDto) {
|
|
62
|
+
/** Refresh access token. Browser uses HTTP-only cookie, API/Mobile uses request body. */ async refreshToken(req, refreshTokenDto) {
|
|
71
63
|
// Get refresh token from cookie (browser) or body (API/mobile)
|
|
72
64
|
const cookieName = this.authConfig?.getRefreshTokenCookieName() ?? 'fsn_refresh_token';
|
|
73
65
|
const refreshToken = req.cookies?.[cookieName] || refreshTokenDto.refreshToken;
|
|
@@ -76,37 +68,80 @@ export class AuthenticationController {
|
|
|
76
68
|
}
|
|
77
69
|
return this.authService.refreshToken(refreshToken);
|
|
78
70
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Get current user info
|
|
81
|
-
* Returns only user, company, and branch data (no tokens)
|
|
82
|
-
* Uses existing access token from Authorization header
|
|
83
|
-
* Company/branch fields are automatically excluded from Swagger when company feature is disabled
|
|
84
|
-
*/ async getCurrentUser(user) {
|
|
71
|
+
/** Get current user info. Returns user, company, and branch data (no tokens). */ async getCurrentUser(user) {
|
|
85
72
|
return this.authService.getUserInfo(user.id, user.companyId, user.branchId);
|
|
86
73
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Logout
|
|
89
|
-
* Clears refresh token cookie for browsers
|
|
90
|
-
*/ async logout(userId) {
|
|
74
|
+
/** Logout - Clears refresh token cookie for browsers */ async logout(userId) {
|
|
91
75
|
await this.authService.logout(userId);
|
|
92
76
|
return {
|
|
77
|
+
success: true,
|
|
93
78
|
message: 'Logged out successfully'
|
|
94
79
|
};
|
|
95
80
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Change password
|
|
98
|
-
*/ async changePassword(userId, dto) {
|
|
81
|
+
/** Change password */ async changePassword(userId, dto) {
|
|
99
82
|
await this.authService.changePassword(userId, dto.currentPassword, dto.newPassword);
|
|
100
83
|
return {
|
|
84
|
+
success: true,
|
|
101
85
|
message: 'Password changed successfully'
|
|
102
86
|
};
|
|
103
87
|
}
|
|
88
|
+
// Email Auth Endpoints
|
|
89
|
+
/** Forgot password - Request password reset email */ async forgotPassword(req, dto) {
|
|
90
|
+
if (!this.authEmailService) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
message: 'Email service is not configured'
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return this.authEmailService.forgotPassword(dto.email, this.buildAuthUrl(req, '/auth/reset-password'));
|
|
97
|
+
}
|
|
98
|
+
/** Reset password - Reset password using token */ async resetPassword(dto) {
|
|
99
|
+
if (!this.authEmailService) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
message: 'Email service is not configured'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return this.authEmailService.resetPassword(dto.token, dto.newPassword);
|
|
106
|
+
}
|
|
107
|
+
/** Resend verification email - For unauthenticated users (handles both pending registration and existing users) */ async resendVerification(req, dto) {
|
|
108
|
+
if (!this.authEmailService) {
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
message: 'Email service is not configured'
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return this.authEmailService.resendVerificationEmail(dto.email, this.buildAuthUrl(req, '/auth/verify-email'));
|
|
115
|
+
}
|
|
116
|
+
/** Verify email - Verify email using token. Handles both pending registration and existing user verification. */ async verifyEmail(dto) {
|
|
117
|
+
if (!this.authEmailService) {
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
message: 'Email service is not configured'
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const result = await this.authEmailService.verifyEmail(dto.token);
|
|
124
|
+
if (result.type === 'pending') {
|
|
125
|
+
// Create user from pending registration
|
|
126
|
+
const registrationResult = await this.authService.createUserFromPendingRegistration(result.pending);
|
|
127
|
+
return {
|
|
128
|
+
...registrationResult,
|
|
129
|
+
companyFeatureEnabled: this.authConfig?.isCompanyFeatureEnabled() ?? false
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
success: true,
|
|
134
|
+
message: result.message
|
|
135
|
+
};
|
|
136
|
+
}
|
|
104
137
|
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
105
|
-
constructor(authService, authConfig){
|
|
138
|
+
constructor(authService, authConfig, authEmailService){
|
|
106
139
|
_define_property(this, "authService", void 0);
|
|
107
140
|
_define_property(this, "authConfig", void 0);
|
|
141
|
+
_define_property(this, "authEmailService", void 0);
|
|
108
142
|
this.authService = authService;
|
|
109
143
|
this.authConfig = authConfig;
|
|
144
|
+
this.authEmailService = authEmailService;
|
|
110
145
|
}
|
|
111
146
|
}
|
|
112
147
|
_ts_decorate([
|
|
@@ -148,9 +183,11 @@ _ts_decorate([
|
|
|
148
183
|
status: 201,
|
|
149
184
|
type: RegistrationResponseDto
|
|
150
185
|
}),
|
|
151
|
-
_ts_param(0,
|
|
186
|
+
_ts_param(0, Req()),
|
|
187
|
+
_ts_param(1, Body()),
|
|
152
188
|
_ts_metadata("design:type", Function),
|
|
153
189
|
_ts_metadata("design:paramtypes", [
|
|
190
|
+
typeof Request === "undefined" ? Object : Request,
|
|
154
191
|
typeof RegistrationDto === "undefined" ? Object : RegistrationDto
|
|
155
192
|
]),
|
|
156
193
|
_ts_metadata("design:returntype", Promise)
|
|
@@ -200,6 +237,10 @@ _ts_decorate([
|
|
|
200
237
|
ApiOperation({
|
|
201
238
|
summary: 'Logout user'
|
|
202
239
|
}),
|
|
240
|
+
ApiResponse({
|
|
241
|
+
status: 200,
|
|
242
|
+
type: MessageResponseDto
|
|
243
|
+
}),
|
|
203
244
|
_ts_param(0, CurrentUser('id')),
|
|
204
245
|
_ts_metadata("design:type", Function),
|
|
205
246
|
_ts_metadata("design:paramtypes", [
|
|
@@ -218,6 +259,10 @@ _ts_decorate([
|
|
|
218
259
|
ApiBody({
|
|
219
260
|
type: ChangePasswordDto
|
|
220
261
|
}),
|
|
262
|
+
ApiResponse({
|
|
263
|
+
status: 200,
|
|
264
|
+
type: MessageResponseDto
|
|
265
|
+
}),
|
|
221
266
|
_ts_param(0, CurrentUser('id')),
|
|
222
267
|
_ts_param(1, Body()),
|
|
223
268
|
_ts_metadata("design:type", Function),
|
|
@@ -227,15 +272,107 @@ _ts_decorate([
|
|
|
227
272
|
]),
|
|
228
273
|
_ts_metadata("design:returntype", Promise)
|
|
229
274
|
], AuthenticationController.prototype, "changePassword", null);
|
|
275
|
+
_ts_decorate([
|
|
276
|
+
Post('forgot-password'),
|
|
277
|
+
HttpCode(HttpStatus.OK),
|
|
278
|
+
ApiOperation({
|
|
279
|
+
summary: 'Request password reset email'
|
|
280
|
+
}),
|
|
281
|
+
ApiBody({
|
|
282
|
+
type: ForgotPasswordDto
|
|
283
|
+
}),
|
|
284
|
+
ApiResponse({
|
|
285
|
+
status: 200,
|
|
286
|
+
type: MessageResponseDto
|
|
287
|
+
}),
|
|
288
|
+
_ts_param(0, Req()),
|
|
289
|
+
_ts_param(1, Body()),
|
|
290
|
+
_ts_metadata("design:type", Function),
|
|
291
|
+
_ts_metadata("design:paramtypes", [
|
|
292
|
+
typeof Request === "undefined" ? Object : Request,
|
|
293
|
+
typeof ForgotPasswordDto === "undefined" ? Object : ForgotPasswordDto
|
|
294
|
+
]),
|
|
295
|
+
_ts_metadata("design:returntype", Promise)
|
|
296
|
+
], AuthenticationController.prototype, "forgotPassword", null);
|
|
297
|
+
_ts_decorate([
|
|
298
|
+
Post('reset-password'),
|
|
299
|
+
HttpCode(HttpStatus.OK),
|
|
300
|
+
ApiOperation({
|
|
301
|
+
summary: 'Reset password using token'
|
|
302
|
+
}),
|
|
303
|
+
ApiBody({
|
|
304
|
+
type: ResetPasswordDto
|
|
305
|
+
}),
|
|
306
|
+
ApiResponse({
|
|
307
|
+
status: 200,
|
|
308
|
+
type: MessageResponseDto
|
|
309
|
+
}),
|
|
310
|
+
_ts_param(0, Body()),
|
|
311
|
+
_ts_metadata("design:type", Function),
|
|
312
|
+
_ts_metadata("design:paramtypes", [
|
|
313
|
+
typeof ResetPasswordDto === "undefined" ? Object : ResetPasswordDto
|
|
314
|
+
]),
|
|
315
|
+
_ts_metadata("design:returntype", Promise)
|
|
316
|
+
], AuthenticationController.prototype, "resetPassword", null);
|
|
317
|
+
_ts_decorate([
|
|
318
|
+
Post('resend-verification'),
|
|
319
|
+
HttpCode(HttpStatus.OK),
|
|
320
|
+
ApiOperation({
|
|
321
|
+
summary: 'Resend email verification link'
|
|
322
|
+
}),
|
|
323
|
+
ApiBody({
|
|
324
|
+
type: ResendVerificationDto
|
|
325
|
+
}),
|
|
326
|
+
ApiResponse({
|
|
327
|
+
status: 200,
|
|
328
|
+
type: MessageResponseDto
|
|
329
|
+
}),
|
|
330
|
+
_ts_param(0, Req()),
|
|
331
|
+
_ts_param(1, Body()),
|
|
332
|
+
_ts_metadata("design:type", Function),
|
|
333
|
+
_ts_metadata("design:paramtypes", [
|
|
334
|
+
typeof Request === "undefined" ? Object : Request,
|
|
335
|
+
typeof ResendVerificationDto === "undefined" ? Object : ResendVerificationDto
|
|
336
|
+
]),
|
|
337
|
+
_ts_metadata("design:returntype", Promise)
|
|
338
|
+
], AuthenticationController.prototype, "resendVerification", null);
|
|
339
|
+
_ts_decorate([
|
|
340
|
+
Post('verify-email'),
|
|
341
|
+
HttpCode(HttpStatus.OK),
|
|
342
|
+
UseInterceptors(SetToken),
|
|
343
|
+
ApiOperation({
|
|
344
|
+
summary: 'Verify email using token'
|
|
345
|
+
}),
|
|
346
|
+
ApiBody({
|
|
347
|
+
type: VerifyEmailDto
|
|
348
|
+
}),
|
|
349
|
+
ApiResponse({
|
|
350
|
+
status: 200,
|
|
351
|
+
type: MessageResponseDto
|
|
352
|
+
}),
|
|
353
|
+
ApiResponse({
|
|
354
|
+
status: 200,
|
|
355
|
+
type: RegistrationResponseDto
|
|
356
|
+
}),
|
|
357
|
+
_ts_param(0, Body()),
|
|
358
|
+
_ts_metadata("design:type", Function),
|
|
359
|
+
_ts_metadata("design:paramtypes", [
|
|
360
|
+
typeof VerifyEmailDto === "undefined" ? Object : VerifyEmailDto
|
|
361
|
+
]),
|
|
362
|
+
_ts_metadata("design:returntype", Promise)
|
|
363
|
+
], AuthenticationController.prototype, "verifyEmail", null);
|
|
230
364
|
AuthenticationController = _ts_decorate([
|
|
231
365
|
ApiTags('Authentication'),
|
|
232
366
|
Controller('auth'),
|
|
233
367
|
_ts_param(0, Inject(AuthenticationService)),
|
|
234
368
|
_ts_param(1, Optional()),
|
|
235
369
|
_ts_param(1, Inject(AuthConfigService)),
|
|
370
|
+
_ts_param(2, Optional()),
|
|
371
|
+
_ts_param(2, Inject(AuthEmailService)),
|
|
236
372
|
_ts_metadata("design:type", Function),
|
|
237
373
|
_ts_metadata("design:paramtypes", [
|
|
238
374
|
typeof AuthenticationService === "undefined" ? Object : AuthenticationService,
|
|
239
|
-
typeof AuthConfigService === "undefined" ? Object : AuthConfigService
|
|
375
|
+
typeof AuthConfigService === "undefined" ? Object : AuthConfigService,
|
|
376
|
+
typeof AuthEmailService === "undefined" ? Object : AuthEmailService
|
|
240
377
|
])
|
|
241
378
|
], AuthenticationController);
|
|
@@ -26,21 +26,20 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { createApiController } from '@flusys/nestjs-shared/classes';
|
|
29
|
-
import { Controller, Inject
|
|
30
|
-
import {
|
|
29
|
+
import { Controller, Inject } from '@nestjs/common';
|
|
30
|
+
import { ApiTags } from '@nestjs/swagger';
|
|
31
31
|
import { CompanyBranchResponseDto, CreateCompanyBranchDto, UpdateCompanyBranchDto } from '../dtos/company-branch.dto';
|
|
32
|
-
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
33
32
|
import { BranchService } from '../services/branch.service';
|
|
34
|
-
export class BranchController extends createApiController(CreateCompanyBranchDto, UpdateCompanyBranchDto, CompanyBranchResponseDto
|
|
33
|
+
export class BranchController extends createApiController(CreateCompanyBranchDto, UpdateCompanyBranchDto, CompanyBranchResponseDto, {
|
|
34
|
+
security: 'jwt'
|
|
35
|
+
}) {
|
|
35
36
|
constructor(branchService){
|
|
36
37
|
super(branchService), _define_property(this, "branchService", void 0), this.branchService = branchService;
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
BranchController = _ts_decorate([
|
|
40
41
|
ApiTags('Branches'),
|
|
41
|
-
ApiBearerAuth(),
|
|
42
42
|
Controller('administration/branch'),
|
|
43
|
-
UseGuards(JwtAuthGuard),
|
|
44
43
|
_ts_param(0, Inject(BranchService)),
|
|
45
44
|
_ts_metadata("design:type", Function),
|
|
46
45
|
_ts_metadata("design:paramtypes", [
|
|
@@ -26,21 +26,20 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { createApiController } from '@flusys/nestjs-shared/classes';
|
|
29
|
-
import { Controller, Inject
|
|
30
|
-
import {
|
|
29
|
+
import { Controller, Inject } from '@nestjs/common';
|
|
30
|
+
import { ApiTags } from '@nestjs/swagger';
|
|
31
31
|
import { CompanyResponseDto, CreateCompanyDto, UpdateCompanyDto } from '../dtos/company.dto';
|
|
32
|
-
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
33
32
|
import { CompanyService } from '../services/company.service';
|
|
34
|
-
export class CompanyController extends createApiController(CreateCompanyDto, UpdateCompanyDto, CompanyResponseDto
|
|
33
|
+
export class CompanyController extends createApiController(CreateCompanyDto, UpdateCompanyDto, CompanyResponseDto, {
|
|
34
|
+
security: 'jwt'
|
|
35
|
+
}) {
|
|
35
36
|
constructor(companyService){
|
|
36
37
|
super(companyService), _define_property(this, "companyService", void 0), this.companyService = companyService;
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
CompanyController = _ts_decorate([
|
|
40
41
|
ApiTags('Companies'),
|
|
41
|
-
ApiBearerAuth(),
|
|
42
42
|
Controller('administration/company'),
|
|
43
|
-
UseGuards(JwtAuthGuard),
|
|
44
43
|
_ts_param(0, Inject(CompanyService)),
|
|
45
44
|
_ts_metadata("design:type", Function),
|
|
46
45
|
_ts_metadata("design:paramtypes", [
|