@drax/identity-back 0.38.0 → 0.39.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.
@@ -1,6 +1,6 @@
1
1
  import { AbstractFastifyController } from "@drax/crud-back";
2
2
  import RegistrationCompleteHtml from "../html/RegistrationCompleteHtml.js";
3
- import { CommonConfig, DraxConfig, StoreManager, ValidationError, UnauthorizedError, SecuritySensitiveError, } from "@drax/common-back";
3
+ import { CommonConfig, DraxConfig, StoreManager, ValidationError, UnauthorizedError, SecuritySensitiveError, BadRequestError, } from "@drax/common-back";
4
4
  import UserServiceFactory from "../factory/UserServiceFactory.js";
5
5
  import RoleServiceFactory from "../factory/RoleServiceFactory.js";
6
6
  import UserPermissions from "../permissions/UserPermissions.js";
@@ -17,6 +17,7 @@ class UserController extends AbstractFastifyController {
17
17
  super(UserServiceFactory(), UserPermissions);
18
18
  this.tenantField = "tenant";
19
19
  this.tenantFilter = true;
20
+ this.entityName = 'User';
20
21
  }
21
22
  async auth(request, reply) {
22
23
  try {
@@ -62,13 +63,37 @@ class UserController extends AbstractFastifyController {
62
63
  this.handleError(e, reply);
63
64
  }
64
65
  }
66
+ async onUserEvent(request, action, resourceId = null, detail = null) {
67
+ const requestData = this.extractRequestData(request);
68
+ const eventData = {
69
+ action: action,
70
+ entity: this.entityName,
71
+ resourceId: resourceId.toString(),
72
+ postItem: null,
73
+ preItem: null,
74
+ detail: detail,
75
+ timestamp: new Date(),
76
+ ...requestData
77
+ };
78
+ this.eventEmitter.emitCrudEvent(eventData);
79
+ }
65
80
  async switchTenant(request, reply) {
66
81
  try {
67
82
  request.rbac.assertPermission(UserPermissions.SwitchTenant);
68
83
  if (request.authUser && request.token) {
69
84
  const tenantId = request.body.tenantId;
85
+ if (!tenantId) {
86
+ throw new BadRequestError('Missing tenantId');
87
+ }
88
+ const tenant = await TenantServiceFactory().findById(tenantId);
89
+ if (!tenant) {
90
+ throw new BadRequestError('Invalid tenantId');
91
+ }
92
+ const tenantName = tenant?.name;
70
93
  const userService = UserServiceFactory();
71
- let { accessToken } = await userService.switchTenant(request.token, tenantId);
94
+ let { accessToken } = await userService.switchTenant(request.token, tenantId, tenantName);
95
+ const detail = `Switched to tenant "${tenantName}" (ID: ${tenantId})`;
96
+ this.onUserEvent(request, 'switchTenant', request.rbac.userId, detail);
72
97
  return { accessToken };
73
98
  }
74
99
  else {
@@ -141,6 +166,8 @@ class UserController extends AbstractFastifyController {
141
166
  const userService = UserServiceFactory();
142
167
  let user = await userService.register(payload);
143
168
  if (user) {
169
+ const detail = `User ${user?.username} registered successfully.`;
170
+ this.onUserEvent(request, 'register', user?._id, detail);
144
171
  //SEND EMAIL FOR EMAIL VERIFICATION
145
172
  await UserEmailService.emailVerifyCode(user.emailCode, user.email);
146
173
  return {
@@ -187,6 +214,7 @@ class UserController extends AbstractFastifyController {
187
214
  payload.origin ?? (payload.origin = 'Admin');
188
215
  const userService = UserServiceFactory();
189
216
  let user = await userService.create(payload);
217
+ this.onCreated(request, user);
190
218
  return user;
191
219
  }
192
220
  catch (e) {
@@ -202,7 +230,9 @@ class UserController extends AbstractFastifyController {
202
230
  payload.tenant = request.rbac.getAuthUser.tenantId;
203
231
  }
204
232
  const userService = UserServiceFactory();
233
+ let preUser = await userService.findById(id);
205
234
  let user = await userService.update(id, payload);
235
+ this.onUpdated(request, preUser, user);
206
236
  return user;
207
237
  }
208
238
  catch (e) {
@@ -214,8 +244,10 @@ class UserController extends AbstractFastifyController {
214
244
  request.rbac.assertPermission(UserPermissions.Delete);
215
245
  const id = request.params.id;
216
246
  const userService = UserServiceFactory();
247
+ let preUser = await userService.findById(id);
217
248
  let r = await userService.delete(id);
218
249
  if (r) {
250
+ this.onDeleted(request, preUser);
219
251
  reply.send({
220
252
  id: id,
221
253
  message: 'Item deleted successfully',
@@ -246,11 +278,14 @@ class UserController extends AbstractFastifyController {
246
278
  throw new ValidationError([{ field: 'email', reason: 'validation.email.invalid' }]);
247
279
  }
248
280
  const userService = UserServiceFactory();
281
+ const user = await userService.findByEmail(email);
249
282
  const code = await userService.recoveryCode(email);
250
283
  console.log("CODE", code);
251
284
  if (code) {
252
285
  await UserEmailService.recoveryCode(code, email);
253
286
  }
287
+ const detail = `User ${user?.username} request a password recovery .`;
288
+ this.onUserEvent(request, 'passwordRecoveryRequest', user?._id, detail);
254
289
  reply.send({ message });
255
290
  }
256
291
  catch (e) {
@@ -274,8 +309,10 @@ class UserController extends AbstractFastifyController {
274
309
  throw new ValidationError([{ field: 'newPassword', reason: 'validation.required' }]);
275
310
  }
276
311
  const userService = UserServiceFactory();
277
- const result = await userService.changeUserPasswordByCode(recoveryCode, newPassword);
278
- if (result) {
312
+ const user = await userService.changeUserPasswordByCode(recoveryCode, newPassword);
313
+ if (user) {
314
+ const detail = `User ${user?.username} complete a password recovery .`;
315
+ this.onUserEvent(request, 'passwordRecoveryCompleted', user?._id, detail);
279
316
  reply.send({ message: 'action.success' });
280
317
  }
281
318
  else {
@@ -296,7 +333,9 @@ class UserController extends AbstractFastifyController {
296
333
  const currentPassword = request.body.currentPassword;
297
334
  const newPassword = request.body.newPassword;
298
335
  const userService = UserServiceFactory();
299
- await userService.changeOwnPassword(userId, currentPassword, newPassword);
336
+ const user = await userService.changeOwnPassword(userId, currentPassword, newPassword);
337
+ const detail = `User ${user?.username} changed his password.`;
338
+ this.onUserEvent(request, 'changeMyPassword', user?._id, detail);
300
339
  return { message: 'Password updated successfully' };
301
340
  }
302
341
  catch (e) {
@@ -312,7 +351,9 @@ class UserController extends AbstractFastifyController {
312
351
  }
313
352
  const newPassword = request.body.newPassword;
314
353
  const userService = UserServiceFactory();
315
- await userService.changeUserPassword(userId, newPassword);
354
+ const user = await userService.changeUserPassword(userId, newPassword);
355
+ const detail = `User ${request.rbac.username} changed password for user ${user.username}.`;
356
+ this.onUserEvent(request, 'changePassword', user?._id, detail);
316
357
  return { message: 'Password updated successfully' };
317
358
  }
318
359
  catch (e) {
@@ -334,7 +375,9 @@ class UserController extends AbstractFastifyController {
334
375
  const urlFile = BASE_URL + '/api/users/avatar/' + storedFile.filename;
335
376
  //Save into DB
336
377
  const userService = UserServiceFactory();
337
- await userService.changeAvatar(userId, urlFile);
378
+ const user = await userService.changeAvatar(userId, urlFile);
379
+ const detail = `User ${request.rbac.username} changed avatar.`;
380
+ this.onUserEvent(request, 'changeAvatar', user?._id, detail);
338
381
  return {
339
382
  filename: storedFile.filename,
340
383
  size: storedFile.size,
@@ -1,11 +1,12 @@
1
1
  import UserServiceFactory from "../../factory/UserServiceFactory.js";
2
2
  import { GraphQLError } from "graphql";
3
- import { ValidationErrorToGraphQLError, ValidationError, StoreManager, DraxConfig, CommonConfig } from "@drax/common-back";
3
+ import { ValidationErrorToGraphQLError, ValidationError, StoreManager, DraxConfig, CommonConfig, BadRequestError } from "@drax/common-back";
4
4
  import { UnauthorizedError } from "@drax/common-back";
5
5
  import BadCredentialsError from "../../errors/BadCredentialsError.js";
6
6
  import { join } from "path";
7
7
  import IdentityConfig from "../../config/IdentityConfig.js";
8
8
  import UserPermissions from "../../permissions/UserPermissions.js";
9
+ import TenantServiceFactory from "../../factory/TenantServiceFactory.js";
9
10
  export default {
10
11
  Query: {
11
12
  me: async (_, {}, { authUser }) => {
@@ -79,8 +80,13 @@ export default {
79
80
  rbac.assertPermission(UserPermissions.SwitchTenant);
80
81
  if (authUser && token) {
81
82
  const tenantId = input.tenantId;
83
+ const tenant = await TenantServiceFactory().findById(tenantId);
84
+ if (!tenant) {
85
+ throw new BadRequestError('Invalid tenantId');
86
+ }
87
+ const tenantName = tenant?.name;
82
88
  const userService = UserServiceFactory();
83
- let { accessToken } = await userService.switchTenant(token, tenantId);
89
+ let { accessToken } = await userService.switchTenant(token, tenantId, tenantName);
84
90
  return { accessToken };
85
91
  }
86
92
  else {
package/dist/rbac/Rbac.js CHANGED
@@ -30,13 +30,13 @@ class Rbac {
30
30
  return this.authUser?.session;
31
31
  }
32
32
  get apiKeyId() {
33
- return this.authUser?.apiKeyId.toString();
33
+ return this.authUser?.apiKeyId?.toString();
34
34
  }
35
35
  get apiKeyName() {
36
36
  return this.authUser?.apiKeyName;
37
37
  }
38
38
  get roleId() {
39
- return this.authUser?.roleId.toString();
39
+ return this.authUser?.roleId?.toString();
40
40
  }
41
41
  get roleName() {
42
42
  return this.authUser?.roleName;
@@ -45,7 +45,7 @@ class Rbac {
45
45
  return this.authUser?.tenantId?.toString();
46
46
  }
47
47
  get tenantName() {
48
- return this.authUser?.tenantName;
48
+ return this.authUser?.tenantName ?? undefined;
49
49
  }
50
50
  assertAuthenticated() {
51
51
  if (!this.authUser) {
@@ -51,8 +51,8 @@ class UserService extends AbstractService {
51
51
  });
52
52
  return sessionUUID;
53
53
  }
54
- async switchTenant(accessToken, tenantId) {
55
- const newAccessToken = AuthUtils.switchTenant(accessToken, tenantId);
54
+ async switchTenant(accessToken, tenantId, tenantName) {
55
+ const newAccessToken = AuthUtils.switchTenant(accessToken, tenantId, tenantName);
56
56
  return { accessToken: newAccessToken };
57
57
  }
58
58
  async authByEmail(email, createIfNotFound = false, userData, { userAgent, ip }) {
@@ -87,7 +87,8 @@ class UserService extends AbstractService {
87
87
  if (user) {
88
88
  newPassword = AuthUtils.hashPassword(newPassword);
89
89
  await this._repository.changePassword(userId, newPassword);
90
- return true;
90
+ delete user.password;
91
+ return user;
91
92
  }
92
93
  else {
93
94
  throw new ValidationError([{ field: 'userId', reason: 'validation.notFound' }]);
@@ -102,7 +103,8 @@ class UserService extends AbstractService {
102
103
  if (AuthUtils.checkPassword(currentPassword, user.password)) {
103
104
  newPassword = AuthUtils.hashPassword(newPassword);
104
105
  await this._repository.changePassword(userId, newPassword);
105
- return true;
106
+ delete user.password;
107
+ return user;
106
108
  }
107
109
  else {
108
110
  throw new ValidationError([{ field: 'currentPassword', reason: 'validation.notMatch' }]);
@@ -116,7 +118,7 @@ class UserService extends AbstractService {
116
118
  const user = await this.findById(userId);
117
119
  if (user && user.active) {
118
120
  await this._repository.changeAvatar(userId, avatar);
119
- return true;
121
+ return user;
120
122
  }
121
123
  else {
122
124
  throw new BadCredentialsError();
@@ -141,14 +143,12 @@ class UserService extends AbstractService {
141
143
  }
142
144
  async changeUserPasswordByCode(recoveryCode, newPassword) {
143
145
  try {
144
- console.log("changeUserPasswordByCode recoveryCode", recoveryCode);
145
146
  const user = await this._repository.findByRecoveryCode(recoveryCode);
146
- console.log("changeUserPasswordByCode user", user);
147
147
  if (user && user.active) {
148
148
  newPassword = AuthUtils.hashPassword(newPassword);
149
149
  await this._repository.changePassword(user._id, newPassword);
150
150
  await this._repository.updatePartial(user._id, { recoveryCode: null });
151
- return true;
151
+ return user;
152
152
  }
153
153
  else {
154
154
  throw new ValidationError([{ field: 'recoveryCode', reason: 'validation.notFound' }]);
@@ -54,23 +54,20 @@ class AuthUtils {
54
54
  // Generar el hash en formato hexadecimal
55
55
  return hmac.digest('hex');
56
56
  }
57
- static switchTenant(accessToken, newTenantId) {
57
+ static switchTenant(accessToken, newTenantId, tenantName) {
58
58
  // Verificar que el token actual sea válido
59
59
  const tokenPayload = AuthUtils.verifyToken(accessToken);
60
60
  if (!tokenPayload) {
61
61
  throw new Error("Invalid access token");
62
62
  }
63
63
  tokenPayload.tenantId = newTenantId;
64
+ tokenPayload.tenantName = tenantName;
64
65
  const JWT_SECRET = DraxConfig.getOrLoad(IdentityConfig.JwtSecret);
65
66
  if (!JWT_SECRET) {
66
67
  throw new Error("JWT_SECRET ENV must be provided");
67
68
  }
68
- const JWT_ISSUER = DraxConfig.getOrLoad(IdentityConfig.JwtIssuer) || 'DRAX';
69
69
  const options = {
70
- jwtid: tokenPayload.id,
71
- algorithm: 'HS256',
72
- audience: tokenPayload.username,
73
- issuer: JWT_ISSUER
70
+ algorithm: 'HS256'
74
71
  };
75
72
  return jsonwebtoken.sign(tokenPayload, JWT_SECRET, options);
76
73
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.38.0",
6
+ "version": "0.39.0",
7
7
  "description": "Identity module for user management, authentication and authorization.",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
@@ -28,11 +28,11 @@
28
28
  "author": "Cristian Incarnato & Drax Team",
29
29
  "license": "ISC",
30
30
  "dependencies": {
31
- "@drax/common-back": "^0.38.0",
32
- "@drax/crud-back": "^0.38.0",
33
- "@drax/crud-share": "^0.38.0",
34
- "@drax/email-back": "^0.38.0",
35
- "@drax/identity-share": "^0.38.0",
31
+ "@drax/common-back": "^0.39.0",
32
+ "@drax/crud-back": "^0.39.0",
33
+ "@drax/crud-share": "^0.39.0",
34
+ "@drax/email-back": "^0.39.0",
35
+ "@drax/identity-share": "^0.39.0",
36
36
  "bcryptjs": "^2.4.3",
37
37
  "graphql": "^16.8.2",
38
38
  "jsonwebtoken": "^9.0.2"
@@ -63,5 +63,5 @@
63
63
  "debug": "0"
64
64
  }
65
65
  },
66
- "gitHead": "43c90f3c12165e7527edefbc80dd327a59236dd5"
66
+ "gitHead": "b019c40f954cf60e4ff61c53e27d5bafaea6f16c"
67
67
  }
@@ -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,7 @@ 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'
36
38
  }
37
39
 
38
40
  async auth(request, reply) {
@@ -83,13 +85,45 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
83
85
  }
84
86
  }
85
87
 
88
+ async onUserEvent(request: CustomRequest, action: string, resourceId: string = null, detail: string = null) {
89
+ const requestData = this.extractRequestData(request)
90
+ const eventData : IDraxCrudEvent = {
91
+ action: action,
92
+ entity: this.entityName,
93
+ resourceId: resourceId.toString(),
94
+ postItem: null,
95
+ preItem: null,
96
+ detail: detail,
97
+ timestamp: new Date(),
98
+ ...requestData
99
+ }
100
+ this.eventEmitter.emitCrudEvent(eventData)
101
+ }
102
+
86
103
  async switchTenant(request, reply) {
87
104
  try {
105
+
88
106
  request.rbac.assertPermission(UserPermissions.SwitchTenant)
107
+
89
108
  if (request.authUser && request.token) {
90
109
  const tenantId = request.body.tenantId
110
+ if(!tenantId){
111
+ throw new BadRequestError('Missing tenantId')
112
+ }
113
+
114
+ const tenant = await TenantServiceFactory().findById(tenantId);
115
+
116
+ if(!tenant){
117
+ throw new BadRequestError('Invalid tenantId')
118
+ }
119
+
120
+ const tenantName = tenant?.name;
91
121
  const userService = UserServiceFactory()
92
- let {accessToken} = await userService.switchTenant(request.token, tenantId)
122
+ let {accessToken} = await userService.switchTenant(request.token, tenantId, tenantName)
123
+
124
+ const detail = `Switched to tenant "${tenantName}" (ID: ${tenantId})`;
125
+ this.onUserEvent(request,'switchTenant',request.rbac.userId, detail)
126
+
93
127
  return {accessToken}
94
128
  } else {
95
129
  throw new UnauthorizedError()
@@ -169,6 +203,9 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
169
203
  let user = await userService.register(payload)
170
204
 
171
205
  if(user){
206
+ const detail = `User ${user?.username} registered successfully.`;
207
+ this.onUserEvent(request,'register',user?._id, detail)
208
+
172
209
  //SEND EMAIL FOR EMAIL VERIFICATION
173
210
  await UserEmailService.emailVerifyCode(user.emailCode, user.email)
174
211
 
@@ -221,6 +258,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
221
258
 
222
259
  const userService = UserServiceFactory()
223
260
  let user = await userService.create(payload)
261
+ this.onCreated(request, user)
224
262
  return user
225
263
  } catch (e) {
226
264
  this.handleError(e,reply)
@@ -238,7 +276,9 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
238
276
  }
239
277
 
240
278
  const userService = UserServiceFactory()
279
+ let preUser = await userService.findById(id)
241
280
  let user = await userService.update(id, payload)
281
+ this.onUpdated(request, preUser, user)
242
282
  return user
243
283
  } catch (e) {
244
284
  this.handleError(e,reply)
@@ -250,8 +290,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
250
290
  request.rbac.assertPermission(UserPermissions.Delete)
251
291
  const id = request.params.id
252
292
  const userService = UserServiceFactory()
293
+ let preUser = await userService.findById(id)
253
294
  let r: boolean = await userService.delete(id)
254
295
  if (r) {
296
+ this.onDeleted(request, preUser)
255
297
  reply.send({
256
298
  id: id,
257
299
  message: 'Item deleted successfully',
@@ -284,6 +326,7 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
284
326
  }
285
327
 
286
328
  const userService = UserServiceFactory()
329
+ const user = await userService.findByEmail(email)
287
330
  const code = await userService.recoveryCode(email)
288
331
 
289
332
  console.log("CODE", code)
@@ -292,6 +335,9 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
292
335
  await UserEmailService.recoveryCode(code, email)
293
336
  }
294
337
 
338
+ const detail = `User ${user?.username} request a password recovery .`;
339
+ this.onUserEvent(request,'passwordRecoveryRequest',user?._id, detail)
340
+
295
341
  reply.send({message})
296
342
 
297
343
  } catch (e) {
@@ -319,8 +365,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
319
365
  }
320
366
 
321
367
  const userService = UserServiceFactory()
322
- const result: boolean = await userService.changeUserPasswordByCode(recoveryCode, newPassword)
323
- if(result){
368
+ const user: IUser = await userService.changeUserPasswordByCode(recoveryCode, newPassword)
369
+ if(user){
370
+ const detail = `User ${user?.username} complete a password recovery .`;
371
+ this.onUserEvent(request,'passwordRecoveryCompleted',user?._id, detail)
324
372
  reply.send({message: 'action.success'})
325
373
  }else{
326
374
  reply.statusCode = 400
@@ -342,7 +390,9 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
342
390
  const currentPassword = request.body.currentPassword
343
391
  const newPassword = request.body.newPassword
344
392
  const userService = UserServiceFactory()
345
- await userService.changeOwnPassword(userId, currentPassword, newPassword)
393
+ const user = await userService.changeOwnPassword(userId, currentPassword, newPassword)
394
+ const detail = `User ${user?.username} changed his password.`;
395
+ this.onUserEvent(request,'changeMyPassword',user?._id, detail)
346
396
  return {message: 'Password updated successfully'}
347
397
  } catch (e) {
348
398
  this.handleError(e,reply)
@@ -358,7 +408,9 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
358
408
  }
359
409
  const newPassword = request.body.newPassword
360
410
  const userService = UserServiceFactory()
361
- await userService.changeUserPassword(userId, newPassword)
411
+ const user = await userService.changeUserPassword(userId, newPassword)
412
+ const detail = `User ${request.rbac.username} changed password for user ${user.username}.`;
413
+ this.onUserEvent(request,'changePassword',user?._id, detail)
362
414
  return {message: 'Password updated successfully'}
363
415
  } catch (e) {
364
416
  this.handleError(e,reply)
@@ -385,7 +437,10 @@ class UserController extends AbstractFastifyController<IUser, IUserCreate, IUser
385
437
 
386
438
  //Save into DB
387
439
  const userService = UserServiceFactory()
388
- await userService.changeAvatar(userId, urlFile)
440
+ const user = await userService.changeAvatar(userId, urlFile)
441
+
442
+ const detail = `User ${request.rbac.username} changed avatar.`
443
+ this.onUserEvent(request,'changeAvatar',user?._id, detail)
389
444
 
390
445
  return {
391
446
  filename: storedFile.filename,
@@ -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
@@ -41,7 +41,7 @@ class Rbac implements IRbac{
41
41
  }
42
42
 
43
43
  get apiKeyId(): string {
44
- return this.authUser?.apiKeyId.toString()
44
+ return this.authUser?.apiKeyId?.toString()
45
45
  }
46
46
 
47
47
  get apiKeyName(): string {
@@ -49,7 +49,7 @@ class Rbac implements IRbac{
49
49
  }
50
50
 
51
51
  get roleId(): string {
52
- return this.authUser?.roleId.toString()
52
+ return this.authUser?.roleId?.toString()
53
53
  }
54
54
 
55
55
  get roleName(): string {
@@ -61,7 +61,7 @@ class Rbac implements IRbac{
61
61
  }
62
62
 
63
63
  get tenantName(): string | undefined {
64
- return this.authUser?.tenantName;
64
+ return this.authUser?.tenantName ?? undefined;
65
65
  }
66
66
 
67
67
  assertAuthenticated() {
@@ -64,8 +64,8 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
64
64
  return sessionUUID;
65
65
  }
66
66
 
67
- async switchTenant(accessToken: string, tenantId: string) {
68
- const newAccessToken = AuthUtils.switchTenant(accessToken, tenantId)
67
+ async switchTenant(accessToken: string, tenantId: string, tenantName: string) {
68
+ const newAccessToken = AuthUtils.switchTenant(accessToken, tenantId, tenantName)
69
69
  return {accessToken: newAccessToken}
70
70
  }
71
71
 
@@ -102,19 +102,20 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
102
102
  }
103
103
 
104
104
 
105
- async changeUserPassword(userId: string, newPassword: string) {
105
+ async changeUserPassword(userId: string, newPassword: string):Promise<IUser> {
106
106
  const user = await this._repository.findByIdWithPassword(userId)
107
107
  if (user) {
108
108
  newPassword = AuthUtils.hashPassword(newPassword)
109
109
  await this._repository.changePassword(userId, newPassword)
110
- return true
110
+ delete user.password
111
+ return user
111
112
  } else {
112
113
  throw new ValidationError([{field: 'userId', reason: 'validation.notFound'}])
113
114
  }
114
115
  }
115
116
 
116
117
 
117
- async changeOwnPassword(userId: string, currentPassword: string, newPassword: string) {
118
+ async changeOwnPassword(userId: string, currentPassword: string, newPassword: string): Promise<IUser> {
118
119
  const user = await this._repository.findByIdWithPassword(userId)
119
120
  if (user && user.active) {
120
121
 
@@ -125,7 +126,8 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
125
126
  if (AuthUtils.checkPassword(currentPassword, user.password)) {
126
127
  newPassword = AuthUtils.hashPassword(newPassword)
127
128
  await this._repository.changePassword(userId, newPassword)
128
- return true
129
+ delete user.password
130
+ return user
129
131
  } else {
130
132
  throw new ValidationError([{field: 'currentPassword', reason: 'validation.notMatch'}])
131
133
  }
@@ -135,11 +137,11 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
135
137
  }
136
138
  }
137
139
 
138
- async changeAvatar(userId: string, avatar: string) {
140
+ async changeAvatar(userId: string, avatar: string):Promise<IUser> {
139
141
  const user = await this.findById(userId)
140
142
  if (user && user.active) {
141
143
  await this._repository.changeAvatar(userId, avatar)
142
- return true
144
+ return user
143
145
  } else {
144
146
  throw new BadCredentialsError()
145
147
  }
@@ -161,16 +163,14 @@ class UserService extends AbstractService<IUser, IUserCreate, IUserUpdate> {
161
163
  }
162
164
  }
163
165
 
164
- async changeUserPasswordByCode(recoveryCode: string, newPassword: string): Promise<boolean> {
166
+ async changeUserPasswordByCode(recoveryCode: string, newPassword: string): Promise<IUser> {
165
167
  try {
166
- console.log("changeUserPasswordByCode recoveryCode", recoveryCode)
167
168
  const user = await this._repository.findByRecoveryCode(recoveryCode)
168
- console.log("changeUserPasswordByCode user", user)
169
169
  if (user && user.active) {
170
170
  newPassword = AuthUtils.hashPassword(newPassword)
171
171
  await this._repository.changePassword(user._id, newPassword)
172
172
  await this._repository.updatePartial(user._id, {recoveryCode: null})
173
- return true
173
+ return user
174
174
  } else {
175
175
  throw new ValidationError([{field:'recoveryCode', reason: 'validation.notFound'}])
176
176
  }