@ackplus/nest-auth 1.1.18 → 1.1.20
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/package.json +1 -1
- package/src/lib/admin-console/static/index.html +697 -177
- package/src/lib/audit/services/audit.service.d.ts +15 -0
- package/src/lib/audit/services/audit.service.d.ts.map +1 -0
- package/src/lib/audit/services/audit.service.js +143 -0
- package/src/lib/auth/controllers/auth.controller.d.ts +1 -1
- package/src/lib/auth/controllers/mfa.controller.js +5 -5
- package/src/lib/auth/dto/responses/mfa-status.response.dto.d.ts +2 -2
- package/src/lib/auth/dto/responses/mfa-status.response.dto.d.ts.map +1 -1
- package/src/lib/auth/dto/responses/mfa-status.response.dto.js +5 -5
- package/src/lib/auth/events/index.d.ts +13 -0
- package/src/lib/auth/events/index.d.ts.map +1 -0
- package/src/lib/auth/events/index.js +15 -0
- package/src/lib/auth/events/user-2fa-disabled.event.d.ts +10 -0
- package/src/lib/auth/events/user-2fa-disabled.event.d.ts.map +1 -0
- package/src/lib/auth/events/user-2fa-disabled.event.js +12 -0
- package/src/lib/auth/events/user-2fa-enabled.event.d.ts +13 -0
- package/src/lib/auth/events/user-2fa-enabled.event.d.ts.map +1 -0
- package/src/lib/auth/events/user-2fa-enabled.event.js +15 -0
- package/src/lib/auth/events/user-password-changed.event.d.ts +12 -0
- package/src/lib/auth/events/user-password-changed.event.d.ts.map +1 -0
- package/src/lib/auth/events/user-password-changed.event.js +15 -0
- package/src/lib/auth/guards/auth.guard.d.ts +19 -1
- package/src/lib/auth/guards/auth.guard.d.ts.map +1 -1
- package/src/lib/auth/guards/auth.guard.js +113 -25
- package/src/lib/auth/services/auth.service.d.ts +10 -6
- package/src/lib/auth/services/auth.service.d.ts.map +1 -1
- package/src/lib/auth/services/auth.service.js +313 -133
- package/src/lib/auth/services/mfa.service.d.ts +1 -1
- package/src/lib/auth/services/mfa.service.d.ts.map +1 -1
- package/src/lib/auth/services/mfa.service.js +46 -10
- package/src/lib/auth.constants.d.ts +181 -8
- package/src/lib/auth.constants.d.ts.map +1 -1
- package/src/lib/auth.constants.js +142 -10
- package/src/lib/core/interfaces/auth-module-options.interface.d.ts +170 -0
- package/src/lib/core/interfaces/auth-module-options.interface.d.ts.map +1 -1
- package/src/lib/core/interfaces/session-options.interface.d.ts +52 -0
- package/src/lib/core/interfaces/session-options.interface.d.ts.map +1 -1
- package/src/lib/core/interfaces/token-payload.interface.d.ts +14 -6
- package/src/lib/core/interfaces/token-payload.interface.d.ts.map +1 -1
- package/src/lib/core/services/auth-config.service.js +1 -1
- package/src/lib/nest-auth.module.d.ts.map +1 -1
- package/src/lib/nest-auth.module.js +5 -2
- package/src/lib/session/services/session-manager.service.d.ts +6 -6
- package/src/lib/session/services/session-manager.service.d.ts.map +1 -1
- package/src/lib/session/services/session-manager.service.js +54 -21
- package/src/lib/user/entities/user.entity.d.ts.map +1 -1
- package/src/lib/user/entities/user.entity.js +19 -0
- package/src/lib/user/services/user.service.d.ts +8 -6
- package/src/lib/user/services/user.service.d.ts.map +1 -1
- package/src/lib/user/services/user.service.js +51 -46
|
@@ -3,6 +3,8 @@ import { MFAOptions } from './mfa-options.interface';
|
|
|
3
3
|
import { CookieOptions, SessionOptions } from './session-options.interface';
|
|
4
4
|
import { BaseAuthProvider } from '../providers/base-auth.provider';
|
|
5
5
|
import { DebugLogOptions } from '../services/debug-logger.service';
|
|
6
|
+
import { NestAuthUser } from '../../user/entities/user.entity';
|
|
7
|
+
import { SessionPayload, JWTTokenPayload } from './token-payload.interface';
|
|
6
8
|
/**
|
|
7
9
|
* Default Tenant Options
|
|
8
10
|
*
|
|
@@ -41,6 +43,132 @@ export interface RegistrationCollectProfileField {
|
|
|
41
43
|
value: string;
|
|
42
44
|
}>;
|
|
43
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* User lifecycle hooks for customizing user creation and serialization
|
|
48
|
+
*/
|
|
49
|
+
export interface UserHooks {
|
|
50
|
+
/**
|
|
51
|
+
* Transform user data before creation.
|
|
52
|
+
* Use this to set default roles, validate fields, or enrich data.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* beforeCreate: async (userData, input) => ({
|
|
57
|
+
* ...userData,
|
|
58
|
+
* metadata: { ...userData.metadata, source: 'web' }
|
|
59
|
+
* })
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
beforeCreate?: (userData: Partial<NestAuthUser>, input: any) => Promise<Partial<NestAuthUser>> | Partial<NestAuthUser>;
|
|
63
|
+
/**
|
|
64
|
+
* Callback after user creation.
|
|
65
|
+
* Use for side effects like creating related records, sending notifications.
|
|
66
|
+
*/
|
|
67
|
+
afterCreate?: (user: NestAuthUser) => Promise<void> | void;
|
|
68
|
+
/**
|
|
69
|
+
* Control which user fields appear in API responses.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* serialize: (user) => ({
|
|
74
|
+
* id: user.id,
|
|
75
|
+
* email: user.email,
|
|
76
|
+
* roles: user.roles
|
|
77
|
+
* })
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
serialize?: (user: NestAuthUser) => Partial<NestAuthUser>;
|
|
81
|
+
/** Fields to always exclude from responses */
|
|
82
|
+
sensitiveFields?: string[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Authentication response hooks
|
|
86
|
+
*/
|
|
87
|
+
export interface AuthHooks {
|
|
88
|
+
/**
|
|
89
|
+
* Transform authentication response (login/signup).
|
|
90
|
+
* Use to add custom data like user profile, organization info, feature flags.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* transformResponse: async (response, user, session) => ({
|
|
95
|
+
* ...response,
|
|
96
|
+
* user: { id: user.id, email: user.email },
|
|
97
|
+
* organization: await getOrg(user.id)
|
|
98
|
+
* })
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
transformResponse?: (response: any, user: NestAuthUser, session: SessionPayload) => Promise<any> | any;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Password customization hooks
|
|
105
|
+
*/
|
|
106
|
+
export interface PasswordHooks {
|
|
107
|
+
/** Custom password hashing (default: Argon2id) */
|
|
108
|
+
hash?: (password: string) => Promise<string>;
|
|
109
|
+
/** Custom password verification */
|
|
110
|
+
verify?: (password: string, hash: string) => Promise<boolean>;
|
|
111
|
+
/** Password policy validation */
|
|
112
|
+
validate?: (password: string) => {
|
|
113
|
+
valid: boolean;
|
|
114
|
+
errors?: string[];
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* OTP customization options
|
|
119
|
+
*/
|
|
120
|
+
export interface OtpOptions {
|
|
121
|
+
/** Custom OTP generation function */
|
|
122
|
+
generate?: (length?: number) => string | Promise<string>;
|
|
123
|
+
/** OTP length (default: 6) */
|
|
124
|
+
length?: number;
|
|
125
|
+
/** OTP format */
|
|
126
|
+
format?: 'numeric' | 'alphanumeric';
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Guard customization hooks for pre/post auth validation
|
|
130
|
+
*/
|
|
131
|
+
export interface GuardHooks {
|
|
132
|
+
/**
|
|
133
|
+
* Pre-auth validation (IP whitelist, device fingerprint, etc.)
|
|
134
|
+
* Return { reject: true, reason: '...' } to block authentication.
|
|
135
|
+
*/
|
|
136
|
+
beforeAuth?: (request: any, payload: JWTTokenPayload) => Promise<void | {
|
|
137
|
+
reject: boolean;
|
|
138
|
+
reason?: string;
|
|
139
|
+
}>;
|
|
140
|
+
/** Post-auth callback */
|
|
141
|
+
afterAuth?: (request: any, user: NestAuthUser, session: SessionPayload) => Promise<void> | void;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Authorization customization hooks
|
|
145
|
+
*/
|
|
146
|
+
export interface AuthorizationHooks {
|
|
147
|
+
/** Custom role resolution */
|
|
148
|
+
resolveRoles?: (user: NestAuthUser) => Promise<string[]>;
|
|
149
|
+
/** Custom permission resolution */
|
|
150
|
+
resolvePermissions?: (user: NestAuthUser, roles: string[]) => Promise<string[]>;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Audit event structure
|
|
154
|
+
*/
|
|
155
|
+
export interface AuthAuditEvent {
|
|
156
|
+
type: 'login' | 'logout' | 'signup' | 'password_change' | 'mfa_enable' | 'session_revoke';
|
|
157
|
+
userId?: string;
|
|
158
|
+
ip?: string;
|
|
159
|
+
userAgent?: string;
|
|
160
|
+
success: boolean;
|
|
161
|
+
metadata?: Record<string, any>;
|
|
162
|
+
timestamp: Date;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Audit logging options
|
|
166
|
+
*/
|
|
167
|
+
export interface AuditOptions {
|
|
168
|
+
enabled?: boolean;
|
|
169
|
+
/** Callback for audit events */
|
|
170
|
+
onEvent?: (event: AuthAuditEvent) => Promise<void> | void;
|
|
171
|
+
}
|
|
44
172
|
export interface AuthModuleOptions {
|
|
45
173
|
isGlobal?: boolean;
|
|
46
174
|
appName: string;
|
|
@@ -57,6 +185,8 @@ export interface AuthModuleOptions {
|
|
|
57
185
|
secret: string;
|
|
58
186
|
accessTokenExpiresIn?: number | string;
|
|
59
187
|
refreshTokenExpiresIn?: number | string;
|
|
188
|
+
/** Custom token validation - return false to reject the token */
|
|
189
|
+
validateToken?: (payload: JWTTokenPayload, session: SessionPayload) => Promise<boolean>;
|
|
60
190
|
};
|
|
61
191
|
google?: {
|
|
62
192
|
clientId: string;
|
|
@@ -145,6 +275,46 @@ export interface AuthModuleOptions {
|
|
|
145
275
|
*/
|
|
146
276
|
adminConsole?: AdminConsoleOptions;
|
|
147
277
|
debug?: DebugLogOptions;
|
|
278
|
+
/**
|
|
279
|
+
* User lifecycle hooks
|
|
280
|
+
* Customize user creation, validation, and serialization
|
|
281
|
+
*/
|
|
282
|
+
user?: UserHooks;
|
|
283
|
+
/**
|
|
284
|
+
* Authentication hooks
|
|
285
|
+
* Customize auth responses (login/signup)
|
|
286
|
+
*/
|
|
287
|
+
auth?: AuthHooks;
|
|
288
|
+
/**
|
|
289
|
+
* Guard hooks
|
|
290
|
+
* Add custom pre/post authentication validation
|
|
291
|
+
*/
|
|
292
|
+
guards?: GuardHooks;
|
|
293
|
+
/**
|
|
294
|
+
* Password customization
|
|
295
|
+
* Custom hashing, verification, and validation
|
|
296
|
+
*/
|
|
297
|
+
password?: PasswordHooks;
|
|
298
|
+
/**
|
|
299
|
+
* OTP customization
|
|
300
|
+
* Custom generation, format, and length
|
|
301
|
+
*/
|
|
302
|
+
otp?: OtpOptions;
|
|
303
|
+
/**
|
|
304
|
+
* Authorization hooks
|
|
305
|
+
* Custom role and permission resolution
|
|
306
|
+
*/
|
|
307
|
+
authorization?: AuthorizationHooks;
|
|
308
|
+
/**
|
|
309
|
+
* Audit logging
|
|
310
|
+
* Track auth events for compliance
|
|
311
|
+
*/
|
|
312
|
+
audit?: AuditOptions;
|
|
313
|
+
/**
|
|
314
|
+
* Custom error handling
|
|
315
|
+
* Transform errors before sending to client
|
|
316
|
+
*/
|
|
317
|
+
errorHandler?: (error: Error, context: 'login' | 'signup' | 'refresh' | 'mfa' | 'password_reset' | 'password_change') => any;
|
|
148
318
|
}
|
|
149
319
|
export interface AdminConsoleOptions {
|
|
150
320
|
/** Enable or disable the embedded admin console (default: true) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-module-options.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/core/interfaces/auth-module-options.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-module-options.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/core/interfaces/auth-module-options.interface.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { CookieOptions as ExpressCookieOptions } from 'express';
|
|
2
|
+
import { NestAuthUser } from '../../user/entities/user.entity';
|
|
3
|
+
import { SessionDataPayload, SessionPayload, JWTTokenPayload } from './token-payload.interface';
|
|
2
4
|
export declare enum SessionStorageType {
|
|
3
5
|
REDIS = "redis",
|
|
4
6
|
DATABASE = "database",
|
|
@@ -11,6 +13,56 @@ export interface SessionOptions {
|
|
|
11
13
|
refreshTokenExpiry?: number | string;
|
|
12
14
|
maxSessionsPerUser?: number;
|
|
13
15
|
slidingExpiration?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Customize the data stored in the session (database).
|
|
18
|
+
* This data is NOT sent to the client and can include sensitive information.
|
|
19
|
+
* Supports async operations for database lookups.
|
|
20
|
+
*
|
|
21
|
+
* @param defaultData - The default session data (user, roles, permissions, isMfaVerified)
|
|
22
|
+
* @param user - The authenticated user entity
|
|
23
|
+
* @returns Custom session data to store (can be a Promise)
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* customizeSessionData: async (defaultData, user) => ({
|
|
28
|
+
* ...defaultData,
|
|
29
|
+
* organizationId: user.metadata?.organizationId,
|
|
30
|
+
* internalApiKey: await fetchApiKey(user.id), // Async DB lookup
|
|
31
|
+
* })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
customizeSessionData?: (defaultData: SessionDataPayload, user: NestAuthUser) => Promise<SessionDataPayload> | SessionDataPayload;
|
|
35
|
+
/**
|
|
36
|
+
* Customize the JWT token payload sent to the client.
|
|
37
|
+
* Keep this minimal for security - sensitive data should stay in session.
|
|
38
|
+
* Supports async operations for database lookups.
|
|
39
|
+
*
|
|
40
|
+
* @param defaultPayload - The default token payload
|
|
41
|
+
* @param session - The created session (with data from customizeSessionData if configured)
|
|
42
|
+
* @returns Custom token payload (can be a Promise)
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* customizeTokenPayload: async (defaultPayload, session) => ({
|
|
47
|
+
* ...defaultPayload,
|
|
48
|
+
* roles: undefined, // Remove sensitive data from token
|
|
49
|
+
* orgId: session.data?.organizationId, // Add minimal identifier
|
|
50
|
+
* })
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
customizeTokenPayload?: (defaultPayload: JWTTokenPayload, session: SessionPayload) => Promise<JWTTokenPayload> | JWTTokenPayload;
|
|
54
|
+
/**
|
|
55
|
+
* Called when a new session is created (login/signup)
|
|
56
|
+
*/
|
|
57
|
+
onCreated?: (session: SessionPayload, user: any) => Promise<void> | void;
|
|
58
|
+
/**
|
|
59
|
+
* Called when a session is refreshed (token refresh)
|
|
60
|
+
*/
|
|
61
|
+
onRefreshed?: (oldSession: SessionPayload, newSession: SessionPayload) => Promise<void> | void;
|
|
62
|
+
/**
|
|
63
|
+
* Called when a session is revoked (logout, admin action, security)
|
|
64
|
+
*/
|
|
65
|
+
onRevoked?: (session: SessionPayload, reason: 'logout' | 'expired' | 'admin' | 'security' | 'password_change') => Promise<void> | void;
|
|
14
66
|
}
|
|
15
67
|
export type CookieOptions = Omit<ExpressCookieOptions, 'maxAge'>;
|
|
16
68
|
//# sourceMappingURL=session-options.interface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-options.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/core/interfaces/session-options.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,IAAI,oBAAoB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"session-options.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/core/interfaces/session-options.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,IAAI,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEhG,oBAAY,kBAAkB;IAC1B,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,MAAM,WAAW;CACpB;AAED,MAAM,WAAW,cAAc;IAC3B,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;;;;;;;;;;;;;;OAiBG;IACH,oBAAoB,CAAC,EAAE,CACnB,WAAW,EAAE,kBAAkB,EAC/B,IAAI,EAAE,YAAY,KACjB,OAAO,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAAC;IAEtD;;;;;;;;;;;;;;;;;OAiBG;IACH,qBAAqB,CAAC,EAAE,CACpB,cAAc,EAAE,eAAe,EAC/B,OAAO,EAAE,cAAc,KACtB,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAC;IAMhD;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEzE;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAE/F;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1I;AAGD,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA"}
|
|
@@ -15,6 +15,19 @@ export interface JWTTokenPayload {
|
|
|
15
15
|
exp?: number;
|
|
16
16
|
iat?: number;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Data stored in the session (database-side).
|
|
20
|
+
* This data is NOT sent to the client and can include sensitive information.
|
|
21
|
+
*/
|
|
22
|
+
export interface SessionDataPayload {
|
|
23
|
+
user: NestAuthUser;
|
|
24
|
+
isMfaVerified: boolean;
|
|
25
|
+
isMfaEnabled?: boolean;
|
|
26
|
+
roles: Partial<NestAuthRole>[];
|
|
27
|
+
permissions: string[];
|
|
28
|
+
/** Allow custom fields to be added */
|
|
29
|
+
[key: string]: any;
|
|
30
|
+
}
|
|
18
31
|
export interface SessionPayload {
|
|
19
32
|
id?: string;
|
|
20
33
|
userId?: string;
|
|
@@ -22,12 +35,7 @@ export interface SessionPayload {
|
|
|
22
35
|
userAgent?: string;
|
|
23
36
|
ipAddress?: string;
|
|
24
37
|
deviceName?: string;
|
|
25
|
-
data?:
|
|
26
|
-
user: NestAuthUser;
|
|
27
|
-
isMfaVerified: boolean;
|
|
28
|
-
roles: Partial<NestAuthRole>[];
|
|
29
|
-
permissions: string[];
|
|
30
|
-
};
|
|
38
|
+
data?: SessionDataPayload;
|
|
31
39
|
expiresAt?: Date;
|
|
32
40
|
lastActive: Date;
|
|
33
41
|
createdAt?: Date;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-payload.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/core/interfaces/token-payload.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"token-payload.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/core/interfaces/token-payload.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,sCAAsC;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,YAAY,CAAC;CACvB"}
|
|
@@ -56,7 +56,7 @@ let AuthConfigService = AuthConfigService_1 = class AuthConfigService {
|
|
|
56
56
|
}
|
|
57
57
|
static setOptions(options) {
|
|
58
58
|
const deepmerge = require('deepmerge');
|
|
59
|
-
const mergedOptions = deepmerge(this.defaultOptions, options);
|
|
59
|
+
const mergedOptions = deepmerge(this.defaultOptions, options, { clone: false });
|
|
60
60
|
// Ensure adminConsole exists
|
|
61
61
|
if (!mergedOptions.adminConsole) {
|
|
62
62
|
mergedOptions.adminConsole = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest-auth.module.d.ts","sourceRoot":"","sources":["../../../../../packages/nest-auth/src/lib/nest-auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAE,kBAAkB,EAAY,MAAM,gBAAgB,CAAC;AAErF,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAA4B,MAAM,iDAAiD,CAAC;
|
|
1
|
+
{"version":3,"file":"nest-auth.module.d.ts","sourceRoot":"","sources":["../../../../../packages/nest-auth/src/lib/nest-auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAE,kBAAkB,EAAY,MAAM,gBAAgB,CAAC;AAErF,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAA4B,MAAM,iDAAiD,CAAC;AAgBtI,qBACa,cAAc;IACzB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa;IA0CzD,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,sBAAsB,GAAG,aAAa;IAwCnE,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAkBnC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA0BzC,OAAO,CAAC,MAAM,CAAC,UAAU;IAOzB,SAAS,CAAC,QAAQ,EAAE,kBAAkB;CAGvC"}
|
|
@@ -17,13 +17,14 @@ const auth_config_service_1 = require("./core/services/auth-config.service");
|
|
|
17
17
|
const refresh_token_interceptor_1 = require("./auth/interceptors/refresh-token.interceptor");
|
|
18
18
|
const auth_constants_1 = require("./auth.constants");
|
|
19
19
|
const admin_console_module_1 = require("./admin-console/admin-console.module");
|
|
20
|
+
const audit_service_1 = require("./audit/services/audit.service");
|
|
20
21
|
let NestAuthModule = NestAuthModule_1 = class NestAuthModule {
|
|
21
22
|
static forRoot(options) {
|
|
22
23
|
const mergedOptions = this.getOptions(options);
|
|
23
24
|
// Set options in static service
|
|
24
25
|
auth_config_service_1.AuthConfigService.setOptions(mergedOptions);
|
|
25
26
|
// Conditionally add refresh token interceptor (enabled by default)
|
|
26
|
-
const providers = [];
|
|
27
|
+
const providers = [audit_service_1.AuditService];
|
|
27
28
|
if (mergedOptions.enableAutoRefresh !== false) {
|
|
28
29
|
providers.push({
|
|
29
30
|
provide: core_1.APP_INTERCEPTOR,
|
|
@@ -52,13 +53,14 @@ let NestAuthModule = NestAuthModule_1 = class NestAuthModule {
|
|
|
52
53
|
role_module_1.RoleModule,
|
|
53
54
|
session_module_1.SessionModule,
|
|
54
55
|
admin_console_module_1.AdminConsoleModule,
|
|
56
|
+
audit_service_1.AuditService,
|
|
55
57
|
],
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
static forRootAsync(options) {
|
|
59
61
|
const asyncProviders = this.createAsyncProviders(options);
|
|
60
62
|
// Add refresh token interceptor provider (enabled by default)
|
|
61
|
-
const providers = [...asyncProviders];
|
|
63
|
+
const providers = [...asyncProviders, audit_service_1.AuditService];
|
|
62
64
|
if (options.enableAutoRefresh !== false) {
|
|
63
65
|
providers.push({
|
|
64
66
|
provide: core_1.APP_INTERCEPTOR,
|
|
@@ -88,6 +90,7 @@ let NestAuthModule = NestAuthModule_1 = class NestAuthModule {
|
|
|
88
90
|
role_module_1.RoleModule,
|
|
89
91
|
session_module_1.SessionModule,
|
|
90
92
|
admin_console_module_1.AdminConsoleModule,
|
|
93
|
+
audit_service_1.AuditService,
|
|
91
94
|
],
|
|
92
95
|
};
|
|
93
96
|
}
|
|
@@ -8,10 +8,10 @@ export declare const SESSION_REPOSITORY = "SESSION_REPOSITORY";
|
|
|
8
8
|
*/
|
|
9
9
|
export declare class SessionManagerService {
|
|
10
10
|
private readonly repository;
|
|
11
|
-
private options;
|
|
12
|
-
private readonly maxSessionsPerUser;
|
|
13
|
-
private readonly slidingExpiration;
|
|
14
11
|
constructor(repository: ISessionRepository);
|
|
12
|
+
private get options();
|
|
13
|
+
private get maxSessionsPerUser();
|
|
14
|
+
private get slidingExpiration();
|
|
15
15
|
/**
|
|
16
16
|
* Create a new session
|
|
17
17
|
*/
|
|
@@ -87,10 +87,10 @@ export declare class SessionManagerService {
|
|
|
87
87
|
isMfaVerified?: boolean;
|
|
88
88
|
}): Promise<NestAuthSession>;
|
|
89
89
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
90
|
+
* Refresh an existing session
|
|
91
|
+
* Updates expiration and last active time
|
|
92
92
|
*/
|
|
93
|
-
|
|
93
|
+
refreshSession(session: NestAuthSession): Promise<NestAuthSession>;
|
|
94
94
|
/**
|
|
95
95
|
* Get current active sessions for a user
|
|
96
96
|
* For backward compatibility with AuthService
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/session/services/session-manager.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAK7D,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAI/D,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAEvD;;;GAGG;AACH,qBACa,qBAAqB;
|
|
1
|
+
{"version":3,"file":"session-manager.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/session/services/session-manager.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAK7D,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAI/D,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAEvD;;;GAGG;AACH,qBACa,qBAAqB;IAG1B,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,kBAAkB;IAGnD,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,kBAAkB,GAE7B;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAED;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE;QACzB,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,OAAO,CAAC,eAAe,CAAC;IA+B5B;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,UAAO,GAAG,OAAO,CAAC,eAAe,CAAC;IAqBpF;;OAEG;IACG,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAIjE;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAInE;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IAInG;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAerD;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D;;OAEG;IACG,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlF;;OAEG;IACG,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI/C;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAKnF;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQzE;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK7D;;OAEG;YACW,kBAAkB;IAmBhC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;OAEG;IACH,OAAO,CAAC,SAAS;IAKjB;;;OAGG;IACG,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,GAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,eAAe,CAAC;IAkCtH;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAiBxE;;;OAGG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAGvE"}
|
|
@@ -15,9 +15,15 @@ exports.SESSION_REPOSITORY = 'SESSION_REPOSITORY';
|
|
|
15
15
|
let SessionManagerService = class SessionManagerService {
|
|
16
16
|
constructor(repository) {
|
|
17
17
|
this.repository = repository;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
}
|
|
19
|
+
get options() {
|
|
20
|
+
return auth_config_service_1.AuthConfigService.getOptions();
|
|
21
|
+
}
|
|
22
|
+
get maxSessionsPerUser() {
|
|
23
|
+
return this.options.session?.maxSessionsPerUser || 10;
|
|
24
|
+
}
|
|
25
|
+
get slidingExpiration() {
|
|
26
|
+
return this.options.session?.slidingExpiration ?? true;
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
23
29
|
* Create a new session
|
|
@@ -37,7 +43,15 @@ let SessionManagerService = class SessionManagerService {
|
|
|
37
43
|
ipAddress: ipAddress || request_context_1.RequestContext.getDeviceInfo().ipAddress,
|
|
38
44
|
lastActive: new Date(),
|
|
39
45
|
};
|
|
40
|
-
|
|
46
|
+
const session = await this.repository.create(sessionPayload);
|
|
47
|
+
// Apply onCreated hook if configured
|
|
48
|
+
if (this.options.session?.onCreated) {
|
|
49
|
+
// We need to pass the user object if available.
|
|
50
|
+
// The payload might have data.user if it came from createSessionFromUser
|
|
51
|
+
const user = data?.user;
|
|
52
|
+
await this.options.session.onCreated(session, user);
|
|
53
|
+
}
|
|
54
|
+
return session;
|
|
41
55
|
}
|
|
42
56
|
/**
|
|
43
57
|
* Get session by ID and optionally refresh it
|
|
@@ -80,7 +94,16 @@ let SessionManagerService = class SessionManagerService {
|
|
|
80
94
|
* Revoke (delete) a session
|
|
81
95
|
*/
|
|
82
96
|
async revokeSession(sessionId) {
|
|
97
|
+
// Get session before deleting to pass to hook
|
|
98
|
+
let session = null;
|
|
99
|
+
if (this.options.session?.onRevoked) {
|
|
100
|
+
session = await this.repository.findById(sessionId);
|
|
101
|
+
}
|
|
83
102
|
await this.repository.delete(sessionId);
|
|
103
|
+
// Apply onRevoked hook if configured
|
|
104
|
+
if (this.options.session?.onRevoked && session) {
|
|
105
|
+
await this.options.session.onRevoked(session, 'admin'); // Default reason, could be passed as arg
|
|
106
|
+
}
|
|
84
107
|
}
|
|
85
108
|
/**
|
|
86
109
|
* Revoke all sessions for a user
|
|
@@ -177,33 +200,43 @@ let SessionManagerService = class SessionManagerService {
|
|
|
177
200
|
}
|
|
178
201
|
const roles = await user.getRoles();
|
|
179
202
|
const permissions = await user.getPermissions();
|
|
203
|
+
// Build default session data
|
|
204
|
+
let sessionData = {
|
|
205
|
+
user,
|
|
206
|
+
isMfaVerified,
|
|
207
|
+
roles,
|
|
208
|
+
permissions,
|
|
209
|
+
};
|
|
210
|
+
// Apply custom session data hook if configured
|
|
211
|
+
if (this.options.session?.customizeSessionData) {
|
|
212
|
+
sessionData = await this.options.session.customizeSessionData(sessionData, user);
|
|
213
|
+
}
|
|
180
214
|
// Create session using createSession method
|
|
181
215
|
return await this.createSession({
|
|
182
216
|
userId: user.id,
|
|
183
|
-
data:
|
|
184
|
-
user,
|
|
185
|
-
isMfaVerified,
|
|
186
|
-
roles,
|
|
187
|
-
permissions,
|
|
188
|
-
},
|
|
217
|
+
data: sessionData,
|
|
189
218
|
userAgent: [browser, deviceName].join(' - '),
|
|
190
219
|
ipAddress,
|
|
191
220
|
deviceName,
|
|
192
221
|
});
|
|
193
222
|
}
|
|
194
223
|
/**
|
|
195
|
-
*
|
|
196
|
-
*
|
|
224
|
+
* Refresh an existing session
|
|
225
|
+
* Updates expiration and last active time
|
|
197
226
|
*/
|
|
198
|
-
async
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
227
|
+
async refreshSession(session) {
|
|
228
|
+
const updates = {
|
|
229
|
+
expiresAt: this.calculateExpiration(),
|
|
230
|
+
lastActive: new Date(),
|
|
231
|
+
};
|
|
232
|
+
// Apply onRefreshed hook if configured
|
|
233
|
+
if (this.options.session?.onRefreshed) {
|
|
234
|
+
// We need to pass the old session (current state) and the new session (future state)
|
|
235
|
+
// Since we are updating in place, we can construct the "new" session object for the hook
|
|
236
|
+
const newSession = { ...session, ...updates };
|
|
237
|
+
await this.options.session.onRefreshed(session, newSession);
|
|
238
|
+
}
|
|
239
|
+
return await this.updateSession(session.id, updates);
|
|
207
240
|
}
|
|
208
241
|
/**
|
|
209
242
|
* Get current active sessions for a user
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.entity.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/user/entities/user.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAQH,UAAU,EAMb,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"user.entity.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/user/entities/user.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAQH,UAAU,EAMb,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAExE,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,qBACa,YAAa,SAAQ,UAAU;IAExC,EAAE,EAAE,MAAM,CAAC;IAIX,KAAK,EAAE,MAAM,CAAC;IAId,eAAe,EAAE,IAAI,CAAC;IAItB,KAAK,EAAE,MAAM,CAAC;IAId,eAAe,EAAE,IAAI,CAAC;IAGtB,YAAY,EAAE,MAAM,CAAC;IAGrB,UAAU,EAAE,OAAO,CAAC;IAGpB,QAAQ,EAAE,OAAO,CAAC;IAGlB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAG/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,YAAY,EAAE,OAAO,CAAC;IAGtB,eAAe,CAAC,EAAE,MAAM,CAAC;IAGzB,MAAM,EAAE,cAAc,CAAC;IAGvB,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAG/B,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAGhC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAG5B,IAAI,EAAE,WAAW,EAAE,CAAC;IAGpB,KAAK,EAAE,YAAY,EAAE,CAAC;IAItB,WAAW,EAAE,MAAM,CAAC;IAIpB,WAAW,EAAE,MAAM,CAAC;IAGpB,SAAS,EAAE,IAAI,CAAC;IAGhB,SAAS,EAAE,IAAI,CAAC;IAKhB,kBAAkB;IASZ,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAkBnC,QAAQ,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAenC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnE,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAiBzD,sBAAsB,CACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAChC,OAAO,CAAC,gBAAgB,CAAC;IAiBtB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBpD,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAyBrD"}
|
|
@@ -4,6 +4,7 @@ exports.NestAuthUser = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const typeorm_1 = require("typeorm");
|
|
6
6
|
const argon2 = tslib_1.__importStar(require("argon2"));
|
|
7
|
+
const auth_config_service_1 = require("../../core/services/auth-config.service");
|
|
7
8
|
const tenant_entity_1 = require("../../tenant/entities/tenant.entity");
|
|
8
9
|
const identity_entity_1 = require("./identity.entity");
|
|
9
10
|
const session_entity_1 = require("../../session/entities/session.entity");
|
|
@@ -93,6 +94,11 @@ let NestAuthUser = class NestAuthUser extends typeorm_1.BaseEntity {
|
|
|
93
94
|
async validatePassword(password) {
|
|
94
95
|
if (!this.passwordHash)
|
|
95
96
|
return false;
|
|
97
|
+
// Apply password.verify hook if configured
|
|
98
|
+
const options = auth_config_service_1.AuthConfigService.getOptions();
|
|
99
|
+
if (options.password?.verify) {
|
|
100
|
+
return await options.password.verify(password, this.passwordHash);
|
|
101
|
+
}
|
|
96
102
|
try {
|
|
97
103
|
return await argon2.verify(this.passwordHash, password);
|
|
98
104
|
}
|
|
@@ -102,6 +108,19 @@ let NestAuthUser = class NestAuthUser extends typeorm_1.BaseEntity {
|
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
async setPassword(password) {
|
|
111
|
+
const options = auth_config_service_1.AuthConfigService.getOptions();
|
|
112
|
+
// Apply password.validate hook if configured
|
|
113
|
+
if (options.password?.validate) {
|
|
114
|
+
const isValid = await options.password.validate(password);
|
|
115
|
+
if (!isValid) {
|
|
116
|
+
throw new Error('Password does not meet requirements');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Apply password.hash hook if configured
|
|
120
|
+
if (options.password?.hash) {
|
|
121
|
+
this.passwordHash = await options.password.hash(password);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
105
124
|
// Argon2id is the recommended variant (hybrid of Argon2i and Argon2d)
|
|
106
125
|
this.passwordHash = await argon2.hash(password, {
|
|
107
126
|
type: argon2.argon2id,
|
|
@@ -3,13 +3,15 @@ import { NestAuthUser } from '../entities/user.entity';
|
|
|
3
3
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
4
4
|
import { TenantService } from '../../tenant';
|
|
5
5
|
import { DebugLoggerService } from '../../core/services/debug-logger.service';
|
|
6
|
+
import { AuthConfigService } from '../../core/services/auth-config.service';
|
|
6
7
|
export declare class UserService {
|
|
7
|
-
private userRepository;
|
|
8
|
-
private
|
|
9
|
-
private
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
private readonly userRepository;
|
|
9
|
+
private readonly tenantService;
|
|
10
|
+
private readonly eventEmitter;
|
|
11
|
+
private readonly authConfigService;
|
|
12
|
+
private readonly debugLogger;
|
|
13
|
+
constructor(userRepository: Repository<NestAuthUser>, tenantService: TenantService, eventEmitter: EventEmitter2, authConfigService: AuthConfigService, debugLogger: DebugLoggerService);
|
|
14
|
+
createUser(data: Partial<NestAuthUser>, context?: any): Promise<NestAuthUser>;
|
|
13
15
|
getUserById(id: string, options?: FindOneOptions<NestAuthUser>): Promise<NestAuthUser>;
|
|
14
16
|
getUserByEmail(email: string, tenantId?: string, options?: FindOneOptions<NestAuthUser>): Promise<NestAuthUser>;
|
|
15
17
|
getUserByPhone(phone: string, tenantId?: string, options?: FindOneOptions<NestAuthUser>): Promise<NestAuthUser>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/user/services/user.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAe,UAAU,EAAE,MAAM,SAAS,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAKtD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/user/services/user.service.ts"],"names":[],"mappings":"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"}
|