@things-factory/auth-base 8.0.0-alpha.27 → 8.0.0-alpha.29

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/auth-base",
3
- "version": "8.0.0-alpha.27",
3
+ "version": "8.0.0-alpha.29",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -32,10 +32,10 @@
32
32
  "dependencies": {
33
33
  "@simplewebauthn/browser": "^10.0.0",
34
34
  "@simplewebauthn/server": "^10.0.0",
35
- "@things-factory/email-base": "^8.0.0-alpha.27",
35
+ "@things-factory/email-base": "^8.0.0-alpha.29",
36
36
  "@things-factory/env": "^8.0.0-alpha.8",
37
- "@things-factory/shell": "^8.0.0-alpha.27",
38
- "@things-factory/utils": "^8.0.0-alpha.14",
37
+ "@things-factory/shell": "^8.0.0-alpha.29",
38
+ "@things-factory/utils": "^8.0.0-alpha.29",
39
39
  "@types/webappsec-credential-management": "^0.6.8",
40
40
  "jsonwebtoken": "^9.0.0",
41
41
  "koa-passport": "^6.0.0",
@@ -46,5 +46,5 @@
46
46
  "passport-jwt": "^4.0.0",
47
47
  "passport-local": "^1.0.0"
48
48
  },
49
- "gitHead": "6c55d218253341cc51e8fa7b2f9dc8a7c061aa55"
49
+ "gitHead": "a7592d7dc0886734d2798ee5756c51b0c0aa13fa"
50
50
  }
@@ -1,6 +1,6 @@
1
1
  import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
2
  import { GraphQLEmailAddress } from 'graphql-scalars'
3
- import { ILike, In, SelectQueryBuilder } from 'typeorm'
3
+ import { ILike, In, SelectQueryBuilder, EntityManager } from 'typeorm'
4
4
 
5
5
  import { config } from '@things-factory/env'
6
6
  import { Domain, getRepository, ObjectRef } from '@things-factory/shell'
@@ -17,13 +17,13 @@ export class UserMutation {
17
17
  @Directive('@transaction')
18
18
  @Mutation(returns => User, { description: 'To create new user' })
19
19
  async createUser(@Arg('user') user: NewUser, @Ctx() context: ResolverContext) {
20
- const { domain } = context.state
20
+ const { domain, tx } = context.state
21
21
  const { defaultPassword } = config.get('password')
22
22
  const { email } = user
23
23
 
24
24
  user.email = email.trim()
25
25
 
26
- const oldUser: User = await getRepository(User).findOne({ where: { email: ILike(user.email) } })
26
+ const oldUser: User = await getRepository(User, tx).findOne({ where: { email: ILike(user.email) } })
27
27
  if (oldUser) {
28
28
  throw new Error(context.t('error.x already exists in y', { x: context.t('field.user'), y: 'operato' }))
29
29
  }
@@ -38,14 +38,14 @@ export class UserMutation {
38
38
 
39
39
  const salt = User.generateSalt()
40
40
 
41
- return await getRepository(User).save({
41
+ return await getRepository(User, tx).save({
42
42
  creator: context.state.user,
43
43
  updater: context.state.user,
44
44
  ...user,
45
45
  domains: [domain],
46
46
  roles:
47
47
  user.roles && user.roles.length
48
- ? await getRepository(Role).findBy({
48
+ ? await getRepository(Role, tx).findBy({
49
49
  id: In(user.roles.map(role => role.id)),
50
50
  domain: { id: domain.id }
51
51
  })
@@ -64,7 +64,7 @@ export class UserMutation {
64
64
  @Arg('patch') patch: UserPatch,
65
65
  @Ctx() context: ResolverContext
66
66
  ) {
67
- const { domain, user: updater }: { domain: Domain; user: User } = context.state
67
+ const { domain, user: updater, tx }: { domain: Domain; user: User; tx?: EntityManager } = context.state
68
68
  const qb: SelectQueryBuilder<User> = buildDomainUsersQueryBuilder(domain.id, 'USER')
69
69
  const user: User = await qb
70
70
  .andWhere('LOWER(USER.email) = :email', { email: email?.toLowerCase().trim() || '' })
@@ -73,14 +73,16 @@ export class UserMutation {
73
73
  .getOne()
74
74
 
75
75
  if (patch.roles) {
76
- patch.roles = await getRepository(Role).find({ where: { id: In(patch.roles.map((r: Partial<Role>) => r.id)) } })
76
+ patch.roles = await getRepository(Role, tx).find({
77
+ where: { id: In(patch.roles.map((r: Partial<Role>) => r.id)) }
78
+ })
77
79
  }
78
80
 
79
81
  if (patch.status && patch.status === 'activated') {
80
82
  user.status = UserStatus.ACTIVATED
81
83
  }
82
84
 
83
- return await getRepository(User).save({
85
+ return await getRepository(User, tx).save({
84
86
  ...user,
85
87
  ...patch,
86
88
  updater
@@ -92,7 +94,7 @@ export class UserMutation {
92
94
  @Mutation(returns => [User], { description: 'To modify multiple users information' })
93
95
  async updateMultipleUser(@Arg('patches', type => [UserPatch]) patches: UserPatch[], @Ctx() context: ResolverContext) {
94
96
  const { domain, user, tx } = context.state
95
- const userRepo = tx.getRepository(User)
97
+ const userRepo = getRepository(User, tx)
96
98
 
97
99
  let results = []
98
100
  const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
@@ -207,8 +209,8 @@ export class UserMutation {
207
209
  @Arg('email', type => GraphQLEmailAddress) email: string,
208
210
  @Ctx() context: ResolverContext
209
211
  ): Promise<boolean> {
210
- const { domain } = context.state
211
- const invitee: User = await getRepository(User).findOne({
212
+ const { domain, tx } = context.state
213
+ const invitee: User = await getRepository(User, tx).findOne({
212
214
  where: { email: ILike(email) },
213
215
  relations: ['domains']
214
216
  })
@@ -222,7 +224,7 @@ export class UserMutation {
222
224
  throw new Error(context.t('error.x already exists in y', { x: context.t('field.user'), y: domain.name }))
223
225
  }
224
226
  invitee.domains = [...existingDomains, domain]
225
- await getRepository(User).save(invitee)
227
+ await getRepository(User, tx).save(invitee)
226
228
 
227
229
  return true
228
230
  }
@@ -236,9 +238,10 @@ export class UserMutation {
236
238
  ): Promise<boolean> {
237
239
  const { tx, domain } = context.state
238
240
 
239
- let user: User = await tx
240
- .getRepository(User)
241
- .findOne({ where: { email: ILike(email) }, relations: ['domains', 'roles', 'roles.domain'] })
241
+ let user: User = await getRepository(User, tx).findOne({
242
+ where: { email: ILike(email) },
243
+ relations: ['domains', 'roles', 'roles.domain']
244
+ })
242
245
  if (!user) {
243
246
  throw new Error(context.t('error.failed to find x', { x: context.t('field.user') }))
244
247
  }
@@ -254,7 +257,7 @@ export class UserMutation {
254
257
  // Remove domain's roles that user has
255
258
  user.roles = user.roles.filter((role: Role) => role.domain.id !== domain.id)
256
259
 
257
- await tx.getRepository(User).save(user)
260
+ await getRepository(User, tx).save(user)
258
261
 
259
262
  return true
260
263
  }
@@ -266,12 +269,30 @@ export class UserMutation {
266
269
  @Arg('email', type => GraphQLEmailAddress) email: string,
267
270
  @Ctx() context: ResolverContext
268
271
  ): Promise<boolean> {
269
- const { domain } = context.state
270
- const user: User = await getRepository(User).findOne({
271
- where: { email: ILike(email) }
272
+ const { domain, tx } = context.state
273
+ const user: User = await getRepository(User, tx).findOne({
274
+ where: { email: ILike(email) },
275
+ relations: ['domains', 'roles']
272
276
  })
277
+
278
+ if (!user) {
279
+ throw new Error('Failed to find user')
280
+ }
281
+
282
+ if (user.status !== UserStatus.ACTIVATED) {
283
+ throw new Error('Only activated users are eligible to receive admin privileges.')
284
+ }
285
+
286
+ if (user.domains.map((d: Domain) => d.id).indexOf(domain.id) < 0) {
287
+ throw new Error(`User is not belongs to current domain`)
288
+ }
289
+
290
+ if (user.roles.filter((r: Role) => r.domainId == domain.id).length == 0) {
291
+ throw new Error(`Only users with at least one role in this domain are eligible to receive admin privileges.`)
292
+ }
293
+
273
294
  domain.owner = user.id
274
- await getRepository(Domain).save(domain)
295
+ await getRepository(Domain, tx).save(domain)
275
296
 
276
297
  return true
277
298
  }
@@ -282,7 +303,7 @@ export class UserMutation {
282
303
  async activateUser(@Arg('userId') userId: string, @Ctx() context: ResolverContext): Promise<boolean> {
283
304
  const { tx, domain } = context.state
284
305
 
285
- const targetUser: User = await tx.getRepository(User).findOne({
306
+ const targetUser: User = await getRepository(User, tx).findOne({
286
307
  where: { id: userId },
287
308
  relations: ['domains']
288
309
  })
@@ -297,7 +318,7 @@ export class UserMutation {
297
318
  targetUser.failCount = 0
298
319
  targetUser.status = UserStatus.ACTIVATED
299
320
 
300
- await tx.getRepository(User).save(targetUser)
321
+ await getRepository(User, tx).save(targetUser)
301
322
 
302
323
  return true
303
324
  }
@@ -308,7 +329,7 @@ export class UserMutation {
308
329
  async inactivateUser(@Arg('userId') userId: string, @Ctx() context: ResolverContext): Promise<boolean> {
309
330
  const { tx, domain } = context.state
310
331
 
311
- const targetUser: User = await tx.getRepository(User).findOne({
332
+ const targetUser: User = await getRepository(User, tx).findOne({
312
333
  where: { id: userId },
313
334
  relations: ['domains']
314
335
  })
@@ -326,7 +347,7 @@ export class UserMutation {
326
347
 
327
348
  targetUser.status = UserStatus.INACTIVE
328
349
 
329
- await tx.getRepository(User).save(targetUser)
350
+ await getRepository(User, tx).save(targetUser)
330
351
 
331
352
  return true
332
353
  }
@@ -342,7 +363,7 @@ export class UserMutation {
342
363
  throw new Error('No default password found')
343
364
  }
344
365
 
345
- const targetUser: User = await tx.getRepository(User).findOne({
366
+ const targetUser: User = await getRepository(User, tx).findOne({
346
367
  where: { id: userId },
347
368
  relations: ['domains']
348
369
  })
@@ -356,7 +377,7 @@ export class UserMutation {
356
377
 
357
378
  targetUser.salt = User.generateSalt()
358
379
  targetUser.password = User.encode(defaultPassword, targetUser.salt)
359
- await tx.getRepository(User).save(targetUser)
380
+ await getRepository(User, tx).save(targetUser)
360
381
 
361
382
  return true
362
383
  }
@@ -371,7 +392,7 @@ export class UserMutation {
371
392
  @Ctx() context: ResolverContext
372
393
  ) {
373
394
  const { domain, tx } = context.state
374
- let user: User = await tx.getRepository(User).findOne({
395
+ let user: User = await getRepository(User, tx).findOne({
375
396
  where: { id: userId },
376
397
  relations: ['domains', 'roles']
377
398
  })
@@ -387,6 +408,6 @@ export class UserMutation {
387
408
  user.roles = user.roles.filter((r: Role) => availableRoleIds.indexOf(r.id) < 0)
388
409
  user.roles = user.roles.concat(selectedRoles as Role[])
389
410
 
390
- return await tx.getRepository(User).save(user)
411
+ return await getRepository(User, tx).save(user)
391
412
  }
392
413
  }