@drax/identity-back 0.38.1 → 0.40.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/dist/controllers/UserController.js +86 -8
- package/dist/graphql/resolvers/user.resolvers.js +8 -2
- package/dist/rbac/Rbac.js +9 -9
- package/dist/services/UserService.js +10 -9
- package/dist/utils/AuthUtils.js +3 -6
- package/package.json +7 -7
- package/src/controllers/UserController.ts +128 -38
- package/src/graphql/resolvers/user.resolvers.ts +9 -2
- package/src/rbac/Rbac.ts +9 -9
- package/src/services/UserService.ts +14 -13
- package/src/utils/AuthUtils.ts +5 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/types/controllers/UserController.d.ts +3 -0
- package/types/controllers/UserController.d.ts.map +1 -1
- package/types/graphql/resolvers/user.resolvers.d.ts +5 -3
- package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
- package/types/services/UserService.d.ts +7 -5
- package/types/services/UserService.d.ts.map +1 -1
- package/types/utils/AuthUtils.d.ts +1 -1
- package/types/utils/AuthUtils.d.ts.map +1 -1
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
DraxConfig,
|
|
7
7
|
StoreManager,
|
|
8
8
|
ValidationError,
|
|
9
|
-
UnauthorizedError, SecuritySensitiveError,
|
|
9
|
+
UnauthorizedError, SecuritySensitiveError, BadRequestError,
|
|
10
10
|
} from "@drax/common-back";
|
|
11
11
|
|
|
12
12
|
import UserServiceFactory from "../factory/UserServiceFactory.js";
|
|
@@ -17,8 +17,9 @@ import BadCredentialsError from "../errors/BadCredentialsError.js";
|
|
|
17
17
|
import {join} from "path";
|
|
18
18
|
import {IdentityConfig} from "../config/IdentityConfig.js";
|
|
19
19
|
import UserEmailService from "../services/UserEmailService.js";
|
|
20
|
-
import {IDraxFieldFilter} from "@drax/crud-share";
|
|
20
|
+
import {IDraxCrudEvent, IDraxFieldFilter} from "@drax/crud-share";
|
|
21
21
|
import TenantServiceFactory from "../factory/TenantServiceFactory.js";
|
|
22
|
+
import {CustomRequest} from "@drax/crud-back/dist";
|
|
22
23
|
|
|
23
24
|
const BASE_FILE_DIR = DraxConfig.getOrLoad(CommonConfig.FileDir) || 'files';
|
|
24
25
|
const AVATAR_DIR = DraxConfig.getOrLoad(IdentityConfig.AvatarDir) || 'avatar';
|
|
@@ -33,6 +34,40 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
33
34
|
super(UserServiceFactory(), UserPermissions)
|
|
34
35
|
this.tenantField = "tenant";
|
|
35
36
|
this.tenantFilter = true;
|
|
37
|
+
this.entityName = 'User'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async onUserLoggedIn(request: CustomRequest, user: IUser, session: string) {
|
|
41
|
+
const eventData: IDraxCrudEvent = {
|
|
42
|
+
action: 'loggedIn',
|
|
43
|
+
entity: this.entityName,
|
|
44
|
+
resourceId: user._id.toString(),
|
|
45
|
+
postItem: null,
|
|
46
|
+
preItem: null,
|
|
47
|
+
detail: `User ${user.username} logged in.`,
|
|
48
|
+
timestamp: new Date(),
|
|
49
|
+
ip: request.ip,
|
|
50
|
+
userAgent: request.headers['user-agent'],
|
|
51
|
+
requestId: request.id,
|
|
52
|
+
user: {
|
|
53
|
+
id: user._id.toString(),
|
|
54
|
+
username: user.username,
|
|
55
|
+
role:{
|
|
56
|
+
id: user?.role?._id.toString(),
|
|
57
|
+
name: user?.role?.name,
|
|
58
|
+
},
|
|
59
|
+
tenant: {
|
|
60
|
+
id: user?.tenant?._id.toString(),
|
|
61
|
+
name: user?.tenant?.name,
|
|
62
|
+
},
|
|
63
|
+
apiKey: {
|
|
64
|
+
id: null,
|
|
65
|
+
name: null,
|
|
66
|
+
},
|
|
67
|
+
session: session,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
this.eventEmitter.emitCrudEvent(eventData)
|
|
36
71
|
}
|
|
37
72
|
|
|
38
73
|
async auth(request, reply) {
|
|
@@ -42,8 +77,9 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
42
77
|
const userAgent = request.headers['user-agent'];
|
|
43
78
|
const ip = request.ip;
|
|
44
79
|
const userService = UserServiceFactory()
|
|
45
|
-
|
|
46
|
-
|
|
80
|
+
const {user, accessToken, session} = await userService.auth(username, password, {userAgent, ip})
|
|
81
|
+
this.onUserLoggedIn(request, user, session)
|
|
82
|
+
return {accessToken}
|
|
47
83
|
} catch (e) {
|
|
48
84
|
console.error('/api/auth error', e)
|
|
49
85
|
if (e instanceof BadCredentialsError) {
|
|
@@ -64,10 +100,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
64
100
|
delete user.password
|
|
65
101
|
|
|
66
102
|
//handle SwitchTenant setted in accessToken
|
|
67
|
-
if(request.authUser.tenantId != user?.tenant?._id){
|
|
103
|
+
if (request.authUser.tenantId != user?.tenant?._id) {
|
|
68
104
|
const tenantService = TenantServiceFactory()
|
|
69
105
|
const tenant = await tenantService.findById(request.authUser.tenantId)
|
|
70
|
-
if(tenant){
|
|
106
|
+
if (tenant) {
|
|
71
107
|
user.tenant = tenant
|
|
72
108
|
}
|
|
73
109
|
}
|
|
@@ -79,23 +115,56 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
79
115
|
|
|
80
116
|
}
|
|
81
117
|
} catch (e) {
|
|
82
|
-
this.handleError(e,reply)
|
|
118
|
+
this.handleError(e, reply)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async onUserEvent(request: CustomRequest, action: string, resourceId: string = null, detail: string = null) {
|
|
123
|
+
const requestData = this.extractRequestData(request)
|
|
124
|
+
const eventData: IDraxCrudEvent = {
|
|
125
|
+
action: action,
|
|
126
|
+
entity: this.entityName,
|
|
127
|
+
resourceId: resourceId.toString(),
|
|
128
|
+
postItem: null,
|
|
129
|
+
preItem: null,
|
|
130
|
+
detail: detail,
|
|
131
|
+
timestamp: new Date(),
|
|
132
|
+
...requestData
|
|
83
133
|
}
|
|
134
|
+
this.eventEmitter.emitCrudEvent(eventData)
|
|
84
135
|
}
|
|
85
136
|
|
|
86
137
|
async switchTenant(request, reply) {
|
|
87
138
|
try {
|
|
139
|
+
|
|
88
140
|
request.rbac.assertPermission(UserPermissions.SwitchTenant)
|
|
141
|
+
|
|
89
142
|
if (request.authUser && request.token) {
|
|
90
143
|
const tenantId = request.body.tenantId
|
|
144
|
+
if (!tenantId) {
|
|
145
|
+
throw new BadRequestError('Missing tenantId')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const tenant = await TenantServiceFactory().findById(tenantId);
|
|
149
|
+
|
|
150
|
+
if (!tenant) {
|
|
151
|
+
throw new BadRequestError('Invalid tenantId')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const tenantName = tenant?.name;
|
|
91
155
|
const userService = UserServiceFactory()
|
|
92
|
-
let {accessToken} = await userService.switchTenant(request.token, tenantId)
|
|
156
|
+
let {accessToken} = await userService.switchTenant(request.token, tenantId, tenantName)
|
|
157
|
+
|
|
158
|
+
const username = request.rbac.username
|
|
159
|
+
const detail = `User ${username} switched to tenant "${tenantName}" (ID: ${tenantId})`;
|
|
160
|
+
this.onUserEvent(request, 'switchTenant', request.rbac.userId, detail)
|
|
161
|
+
|
|
93
162
|
return {accessToken}
|
|
94
163
|
} else {
|
|
95
164
|
throw new UnauthorizedError()
|
|
96
165
|
}
|
|
97
166
|
} catch (e) {
|
|
98
|
-
this.handleError(e,reply)
|
|
167
|
+
this.handleError(e, reply)
|
|
99
168
|
}
|
|
100
169
|
}
|
|
101
170
|
|
|
@@ -119,7 +188,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
119
188
|
}
|
|
120
189
|
return paginateResult
|
|
121
190
|
} catch (e) {
|
|
122
|
-
this.handleError(e,reply)
|
|
191
|
+
this.handleError(e, reply)
|
|
123
192
|
}
|
|
124
193
|
}
|
|
125
194
|
|
|
@@ -135,7 +204,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
135
204
|
let item = await this.service.search(search, 1000, filters)
|
|
136
205
|
return item
|
|
137
206
|
} catch (e) {
|
|
138
|
-
this.handleError(e,reply)
|
|
207
|
+
this.handleError(e, reply)
|
|
139
208
|
}
|
|
140
209
|
}
|
|
141
210
|
|
|
@@ -168,7 +237,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
168
237
|
const userService = UserServiceFactory()
|
|
169
238
|
let user = await userService.register(payload)
|
|
170
239
|
|
|
171
|
-
if(user){
|
|
240
|
+
if (user) {
|
|
241
|
+
const detail = `User ${user?.username} registered successfully.`;
|
|
242
|
+
this.onUserEvent(request, 'register', user?._id, detail)
|
|
243
|
+
|
|
172
244
|
//SEND EMAIL FOR EMAIL VERIFICATION
|
|
173
245
|
await UserEmailService.emailVerifyCode(user.emailCode, user.email)
|
|
174
246
|
|
|
@@ -180,7 +252,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
180
252
|
|
|
181
253
|
|
|
182
254
|
} catch (e) {
|
|
183
|
-
this.handleError(e,reply)
|
|
255
|
+
this.handleError(e, reply)
|
|
184
256
|
}
|
|
185
257
|
}
|
|
186
258
|
|
|
@@ -189,12 +261,12 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
189
261
|
const emailCode = request.params.code
|
|
190
262
|
const userService = UserServiceFactory()
|
|
191
263
|
const r = await userService.verifyEmail(emailCode)
|
|
192
|
-
if(r){
|
|
264
|
+
if (r) {
|
|
193
265
|
const html = RegistrationCompleteHtml
|
|
194
266
|
reply.header('Content-Type', 'text/html; charset=utf-8').send(html)
|
|
195
267
|
}
|
|
196
268
|
} catch (e) {
|
|
197
|
-
this.handleError(e,reply)
|
|
269
|
+
this.handleError(e, reply)
|
|
198
270
|
}
|
|
199
271
|
}
|
|
200
272
|
|
|
@@ -204,7 +276,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
204
276
|
const userService = UserServiceFactory()
|
|
205
277
|
return await userService.verifyPhone(phoneCode)
|
|
206
278
|
} catch (e) {
|
|
207
|
-
this.handleError(e,reply)
|
|
279
|
+
this.handleError(e, reply)
|
|
208
280
|
}
|
|
209
281
|
}
|
|
210
282
|
|
|
@@ -221,9 +293,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
221
293
|
|
|
222
294
|
const userService = UserServiceFactory()
|
|
223
295
|
let user = await userService.create(payload)
|
|
296
|
+
this.onCreated(request, user)
|
|
224
297
|
return user
|
|
225
298
|
} catch (e) {
|
|
226
|
-
this.handleError(e,reply)
|
|
299
|
+
this.handleError(e, reply)
|
|
227
300
|
}
|
|
228
301
|
}
|
|
229
302
|
|
|
@@ -238,10 +311,12 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
238
311
|
}
|
|
239
312
|
|
|
240
313
|
const userService = UserServiceFactory()
|
|
314
|
+
let preUser = await userService.findById(id)
|
|
241
315
|
let user = await userService.update(id, payload)
|
|
316
|
+
this.onUpdated(request, preUser, user)
|
|
242
317
|
return user
|
|
243
318
|
} catch (e) {
|
|
244
|
-
this.handleError(e,reply)
|
|
319
|
+
this.handleError(e, reply)
|
|
245
320
|
}
|
|
246
321
|
}
|
|
247
322
|
|
|
@@ -250,8 +325,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
250
325
|
request.rbac.assertPermission(UserPermissions.Delete)
|
|
251
326
|
const id = request.params.id
|
|
252
327
|
const userService = UserServiceFactory()
|
|
328
|
+
let preUser = await userService.findById(id)
|
|
253
329
|
let r: boolean = await userService.delete(id)
|
|
254
330
|
if (r) {
|
|
331
|
+
this.onDeleted(request, preUser)
|
|
255
332
|
reply.send({
|
|
256
333
|
id: id,
|
|
257
334
|
message: 'Item deleted successfully',
|
|
@@ -267,7 +344,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
267
344
|
})
|
|
268
345
|
}
|
|
269
346
|
} catch (e) {
|
|
270
|
-
this.handleError(e,reply)
|
|
347
|
+
this.handleError(e, reply)
|
|
271
348
|
}
|
|
272
349
|
}
|
|
273
350
|
|
|
@@ -279,11 +356,12 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
279
356
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
280
357
|
const email = request.body.email
|
|
281
358
|
|
|
282
|
-
if(!email || !emailRegex.test(email)){
|
|
359
|
+
if (!email || !emailRegex.test(email)) {
|
|
283
360
|
throw new ValidationError([{field: 'email', reason: 'validation.email.invalid'}])
|
|
284
361
|
}
|
|
285
362
|
|
|
286
363
|
const userService = UserServiceFactory()
|
|
364
|
+
const user = await userService.findByEmail(email)
|
|
287
365
|
const code = await userService.recoveryCode(email)
|
|
288
366
|
|
|
289
367
|
console.log("CODE", code)
|
|
@@ -292,14 +370,17 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
292
370
|
await UserEmailService.recoveryCode(code, email)
|
|
293
371
|
}
|
|
294
372
|
|
|
373
|
+
const detail = `User ${user?.username} request a password recovery .`;
|
|
374
|
+
this.onUserEvent(request, 'passwordRecoveryRequest', user?._id, detail)
|
|
375
|
+
|
|
295
376
|
reply.send({message})
|
|
296
377
|
|
|
297
378
|
} catch (e) {
|
|
298
379
|
console.error("ERROR RECOVERY", e)
|
|
299
|
-
if(e instanceof SecuritySensitiveError){
|
|
380
|
+
if (e instanceof SecuritySensitiveError) {
|
|
300
381
|
reply.send({message})
|
|
301
|
-
}else{
|
|
302
|
-
this.handleError(e,reply)
|
|
382
|
+
} else {
|
|
383
|
+
this.handleError(e, reply)
|
|
303
384
|
}
|
|
304
385
|
}
|
|
305
386
|
}
|
|
@@ -310,25 +391,27 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
310
391
|
const recoveryCode = request.body.recoveryCode
|
|
311
392
|
const newPassword = request.body.newPassword
|
|
312
393
|
|
|
313
|
-
if(!recoveryCode){
|
|
314
|
-
throw new ValidationError([{field:'recoveryCode', reason: 'validation.required'}])
|
|
394
|
+
if (!recoveryCode) {
|
|
395
|
+
throw new ValidationError([{field: 'recoveryCode', reason: 'validation.required'}])
|
|
315
396
|
}
|
|
316
397
|
|
|
317
|
-
if(!newPassword){
|
|
318
|
-
throw new ValidationError([{field:'newPassword', reason: 'validation.required'}])
|
|
398
|
+
if (!newPassword) {
|
|
399
|
+
throw new ValidationError([{field: 'newPassword', reason: 'validation.required'}])
|
|
319
400
|
}
|
|
320
401
|
|
|
321
402
|
const userService = UserServiceFactory()
|
|
322
|
-
const
|
|
323
|
-
if(
|
|
403
|
+
const user: IUser = await userService.changeUserPasswordByCode(recoveryCode, newPassword)
|
|
404
|
+
if (user) {
|
|
405
|
+
const detail = `User ${user?.username} complete a password recovery .`;
|
|
406
|
+
this.onUserEvent(request, 'passwordRecoveryCompleted', user?._id, detail)
|
|
324
407
|
reply.send({message: 'action.success'})
|
|
325
|
-
}else{
|
|
408
|
+
} else {
|
|
326
409
|
reply.statusCode = 400
|
|
327
410
|
reply.send({message: 'action.failure'})
|
|
328
411
|
}
|
|
329
412
|
|
|
330
413
|
} catch (e) {
|
|
331
|
-
this.handleError(e,reply)
|
|
414
|
+
this.handleError(e, reply)
|
|
332
415
|
}
|
|
333
416
|
}
|
|
334
417
|
|
|
@@ -342,10 +425,12 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
342
425
|
const currentPassword = request.body.currentPassword
|
|
343
426
|
const newPassword = request.body.newPassword
|
|
344
427
|
const userService = UserServiceFactory()
|
|
345
|
-
await userService.changeOwnPassword(userId, currentPassword, newPassword)
|
|
428
|
+
const user = await userService.changeOwnPassword(userId, currentPassword, newPassword)
|
|
429
|
+
const detail = `User ${user?.username} changed his password.`;
|
|
430
|
+
this.onUserEvent(request, 'changeMyPassword', user?._id, detail)
|
|
346
431
|
return {message: 'Password updated successfully'}
|
|
347
432
|
} catch (e) {
|
|
348
|
-
this.handleError(e,reply)
|
|
433
|
+
this.handleError(e, reply)
|
|
349
434
|
}
|
|
350
435
|
}
|
|
351
436
|
|
|
@@ -358,10 +443,12 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
358
443
|
}
|
|
359
444
|
const newPassword = request.body.newPassword
|
|
360
445
|
const userService = UserServiceFactory()
|
|
361
|
-
await userService.changeUserPassword(userId, newPassword)
|
|
446
|
+
const user = await userService.changeUserPassword(userId, newPassword)
|
|
447
|
+
const detail = `User ${request.rbac.username} changed password for user ${user.username}.`;
|
|
448
|
+
this.onUserEvent(request, 'changePassword', user?._id, detail)
|
|
362
449
|
return {message: 'Password updated successfully'}
|
|
363
450
|
} catch (e) {
|
|
364
|
-
this.handleError(e,reply)
|
|
451
|
+
this.handleError(e, reply)
|
|
365
452
|
}
|
|
366
453
|
}
|
|
367
454
|
|
|
@@ -385,7 +472,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
385
472
|
|
|
386
473
|
//Save into DB
|
|
387
474
|
const userService = UserServiceFactory()
|
|
388
|
-
await userService.changeAvatar(userId, urlFile)
|
|
475
|
+
const user = await userService.changeAvatar(userId, urlFile)
|
|
476
|
+
|
|
477
|
+
const detail = `User ${request.rbac.username} changed avatar.`
|
|
478
|
+
this.onUserEvent(request, 'changeAvatar', user?._id, detail)
|
|
389
479
|
|
|
390
480
|
return {
|
|
391
481
|
filename: storedFile.filename,
|
|
@@ -394,7 +484,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
394
484
|
url: urlFile,
|
|
395
485
|
}
|
|
396
486
|
} catch (e) {
|
|
397
|
-
this.handleError(e,reply)
|
|
487
|
+
this.handleError(e, reply)
|
|
398
488
|
}
|
|
399
489
|
|
|
400
490
|
}
|
|
@@ -407,7 +497,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
|
|
|
407
497
|
//console.log("FILE_DIR: ",fileDir, " FILENAME:", filename)
|
|
408
498
|
return reply.sendFile(filename, fileDir)
|
|
409
499
|
} catch (e) {
|
|
410
|
-
this.handleError(e,reply)
|
|
500
|
+
this.handleError(e, reply)
|
|
411
501
|
}
|
|
412
502
|
|
|
413
503
|
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ValidationError,
|
|
6
6
|
StoreManager,
|
|
7
7
|
DraxConfig,
|
|
8
|
-
CommonConfig
|
|
8
|
+
CommonConfig, BadRequestError
|
|
9
9
|
} from "@drax/common-back";
|
|
10
10
|
import {UnauthorizedError} from "@drax/common-back";
|
|
11
11
|
import BadCredentialsError from "../../errors/BadCredentialsError.js";
|
|
@@ -13,6 +13,7 @@ import {join} from "path";
|
|
|
13
13
|
import IdentityConfig from "../../config/IdentityConfig.js";
|
|
14
14
|
import {IDraxPaginateOptions} from "@drax/crud-share";
|
|
15
15
|
import UserPermissions from "../../permissions/UserPermissions.js";
|
|
16
|
+
import TenantServiceFactory from "../../factory/TenantServiceFactory.js";
|
|
16
17
|
|
|
17
18
|
export default {
|
|
18
19
|
Query: {
|
|
@@ -88,8 +89,14 @@ export default {
|
|
|
88
89
|
rbac.assertPermission(UserPermissions.SwitchTenant)
|
|
89
90
|
if (authUser && token) {
|
|
90
91
|
const tenantId = input.tenantId
|
|
92
|
+
const tenant = await TenantServiceFactory().findById(tenantId);
|
|
93
|
+
|
|
94
|
+
if(!tenant){
|
|
95
|
+
throw new BadRequestError('Invalid tenantId')
|
|
96
|
+
}
|
|
97
|
+
const tenantName = tenant?.name;
|
|
91
98
|
const userService = UserServiceFactory()
|
|
92
|
-
let {accessToken} = await userService.switchTenant(token, tenantId)
|
|
99
|
+
let {accessToken} = await userService.switchTenant(token, tenantId, tenantName)
|
|
93
100
|
return {accessToken}
|
|
94
101
|
} else {
|
|
95
102
|
throw new UnauthorizedError()
|
package/src/rbac/Rbac.ts
CHANGED
|
@@ -29,39 +29,39 @@ class Rbac implements IRbac{
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
get username(): string{
|
|
32
|
-
return this
|
|
32
|
+
return this?.authUser?.username
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
get userId(): string {
|
|
36
|
-
return this
|
|
36
|
+
return this?.authUser?.id.toString()
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
get session(): string {
|
|
40
|
-
return this
|
|
40
|
+
return this?.authUser?.session
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
get apiKeyId(): string {
|
|
44
|
-
return this
|
|
44
|
+
return this?.authUser?.apiKeyId?.toString()
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
get apiKeyName(): string {
|
|
48
|
-
return this
|
|
48
|
+
return this?.authUser?.apiKeyName
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
get roleId(): string {
|
|
52
|
-
return this
|
|
52
|
+
return this?.authUser?.roleId?.toString()
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
get roleName(): string {
|
|
56
|
-
return this
|
|
56
|
+
return this?.authUser?.roleName
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
get tenantId(): string | undefined {
|
|
60
|
-
return this
|
|
60
|
+
return this?.authUser?.tenantId?.toString();
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
get tenantName(): string | undefined {
|
|
64
|
-
return this
|
|
64
|
+
return this?.authUser?.tenantName ?? undefined;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
assertAuthenticated() {
|
|
@@ -40,7 +40,8 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const accessToken = AuthUtils.generateToken(tokenPayload)
|
|
43
|
-
|
|
43
|
+
delete user.password
|
|
44
|
+
return {accessToken: accessToken, user: user, session: sessionUUID}
|
|
44
45
|
} else {
|
|
45
46
|
const userLoginFailService = UserLoginFailServiceFactory()
|
|
46
47
|
await userLoginFailService.create({
|
|
@@ -64,8 +65,8 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
|
|
|
64
65
|
return sessionUUID;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
async switchTenant(accessToken: string, tenantId: string) {
|
|
68
|
-
const newAccessToken = AuthUtils.switchTenant(accessToken, tenantId)
|
|
68
|
+
async switchTenant(accessToken: string, tenantId: string, tenantName: string) {
|
|
69
|
+
const newAccessToken = AuthUtils.switchTenant(accessToken, tenantId, tenantName)
|
|
69
70
|
return {accessToken: newAccessToken}
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -102,19 +103,20 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
|
|
105
|
-
async changeUserPassword(userId: string, newPassword: string) {
|
|
106
|
+
async changeUserPassword(userId: string, newPassword: string):Promise<IUser> {
|
|
106
107
|
const user = await this._repository.findByIdWithPassword(userId)
|
|
107
108
|
if (user) {
|
|
108
109
|
newPassword = AuthUtils.hashPassword(newPassword)
|
|
109
110
|
await this._repository.changePassword(userId, newPassword)
|
|
110
|
-
|
|
111
|
+
delete user.password
|
|
112
|
+
return user
|
|
111
113
|
} else {
|
|
112
114
|
throw new ValidationError([{field: 'userId', reason: 'validation.notFound'}])
|
|
113
115
|
}
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
|
|
117
|
-
async changeOwnPassword(userId: string, currentPassword: string, newPassword: string) {
|
|
119
|
+
async changeOwnPassword(userId: string, currentPassword: string, newPassword: string): Promise<IUser> {
|
|
118
120
|
const user = await this._repository.findByIdWithPassword(userId)
|
|
119
121
|
if (user && user.active) {
|
|
120
122
|
|
|
@@ -125,7 +127,8 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
|
|
|
125
127
|
if (AuthUtils.checkPassword(currentPassword, user.password)) {
|
|
126
128
|
newPassword = AuthUtils.hashPassword(newPassword)
|
|
127
129
|
await this._repository.changePassword(userId, newPassword)
|
|
128
|
-
|
|
130
|
+
delete user.password
|
|
131
|
+
return user
|
|
129
132
|
} else {
|
|
130
133
|
throw new ValidationError([{field: 'currentPassword', reason: 'validation.notMatch'}])
|
|
131
134
|
}
|
|
@@ -135,11 +138,11 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
|
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
async changeAvatar(userId: string, avatar: string) {
|
|
141
|
+
async changeAvatar(userId: string, avatar: string):Promise<IUser> {
|
|
139
142
|
const user = await this.findById(userId)
|
|
140
143
|
if (user && user.active) {
|
|
141
144
|
await this._repository.changeAvatar(userId, avatar)
|
|
142
|
-
return
|
|
145
|
+
return user
|
|
143
146
|
} else {
|
|
144
147
|
throw new BadCredentialsError()
|
|
145
148
|
}
|
|
@@ -161,16 +164,14 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
|
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
|
|
164
|
-
async changeUserPasswordByCode(recoveryCode: string, newPassword: string): Promise<
|
|
167
|
+
async changeUserPasswordByCode(recoveryCode: string, newPassword: string): Promise<IUser> {
|
|
165
168
|
try {
|
|
166
|
-
console.log("changeUserPasswordByCode recoveryCode", recoveryCode)
|
|
167
169
|
const user = await this._repository.findByRecoveryCode(recoveryCode)
|
|
168
|
-
console.log("changeUserPasswordByCode user", user)
|
|
169
170
|
if (user && user.active) {
|
|
170
171
|
newPassword = AuthUtils.hashPassword(newPassword)
|
|
171
172
|
await this._repository.changePassword(user._id, newPassword)
|
|
172
173
|
await this._repository.updatePartial(user._id, {recoveryCode: null})
|
|
173
|
-
return
|
|
174
|
+
return user
|
|
174
175
|
} else {
|
|
175
176
|
throw new ValidationError([{field:'recoveryCode', reason: 'validation.notFound'}])
|
|
176
177
|
}
|
package/src/utils/AuthUtils.ts
CHANGED
|
@@ -6,6 +6,7 @@ import crypto from "crypto";
|
|
|
6
6
|
import type {IAuthUser} from "@drax/identity-share";
|
|
7
7
|
import {TokenPayloadSchema} from "../schemas/TokenPayloadSchema.js";
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
class AuthUtils{
|
|
10
11
|
|
|
11
12
|
static verifyToken(token : string): IAuthUser {
|
|
@@ -74,7 +75,7 @@ class AuthUtils{
|
|
|
74
75
|
return hmac.digest('hex');
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
static switchTenant(accessToken: string, newTenantId: string, tenantName: string): string {
|
|
78
79
|
// Verificar que el token actual sea válido
|
|
79
80
|
const tokenPayload = AuthUtils.verifyToken(accessToken) as IAuthUser & { exp?: number };
|
|
80
81
|
|
|
@@ -83,19 +84,16 @@ class AuthUtils{
|
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
tokenPayload.tenantId = newTenantId;
|
|
87
|
+
tokenPayload.tenantName = tenantName;
|
|
88
|
+
|
|
86
89
|
|
|
87
90
|
const JWT_SECRET = DraxConfig.getOrLoad(IdentityConfig.JwtSecret);
|
|
88
91
|
if (!JWT_SECRET) {
|
|
89
92
|
throw new Error("JWT_SECRET ENV must be provided");
|
|
90
93
|
}
|
|
91
94
|
|
|
92
|
-
const JWT_ISSUER = DraxConfig.getOrLoad(IdentityConfig.JwtIssuer) || 'DRAX';
|
|
93
|
-
|
|
94
95
|
const options: SignOptions = {
|
|
95
|
-
|
|
96
|
-
algorithm: 'HS256',
|
|
97
|
-
audience: tokenPayload.username,
|
|
98
|
-
issuer: JWT_ISSUER
|
|
96
|
+
algorithm: 'HS256'
|
|
99
97
|
};
|
|
100
98
|
|
|
101
99
|
return jsonwebtoken.sign(tokenPayload, JWT_SECRET, options);
|