@drax/identity-back 0.0.31 → 0.1.2

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.
Files changed (156) hide show
  1. package/dist/config/IdentityConfig.js +2 -3
  2. package/dist/factory/RoleServiceFactory.js +8 -7
  3. package/dist/factory/TenantServiceFactory.js +8 -7
  4. package/dist/factory/UserApiKeyServiceFactory.js +24 -0
  5. package/dist/factory/UserServiceFactory.js +8 -7
  6. package/dist/graphql/resolvers/user-api-key.resolvers.js +89 -0
  7. package/dist/graphql/resolvers/user.resolvers.js +7 -2
  8. package/dist/graphql/types/userApiKey.graphql +33 -0
  9. package/dist/index.js +4 -2
  10. package/dist/interfaces/IUserApiKeyRepository.js +1 -0
  11. package/dist/middleware/apiKeyMiddleware.js +30 -0
  12. package/dist/middleware/rbacMiddleware.js +0 -1
  13. package/dist/models/UserApiKeyModel.js +44 -0
  14. package/dist/permissions/IdentityPermissions.js +6 -0
  15. package/dist/rbac/Rbac.js +8 -0
  16. package/dist/repository/mongo/UserApiKeyMongoRepository.js +82 -0
  17. package/dist/repository/mongo/UserMongoRepository.js +3 -3
  18. package/dist/repository/sqlite/RoleSqliteRepository.js +16 -18
  19. package/dist/repository/sqlite/TenantSqliteRepository.js +13 -11
  20. package/dist/repository/sqlite/UserApiKeySqliteRepository.js +147 -0
  21. package/dist/repository/sqlite/UserSqliteRepository.js +29 -26
  22. package/dist/routes/UserApiKeyRoutes.js +119 -0
  23. package/dist/routes/UserRoutes.js +5 -1
  24. package/dist/services/TenantService.js +42 -11
  25. package/dist/services/UserApiKeyService.js +90 -0
  26. package/dist/services/UserService.js +34 -8
  27. package/dist/setup/LoadIdentityConfigFromEnv.js +3 -3
  28. package/dist/utils/AuthUtils.js +10 -0
  29. package/dist/zod/UserApiKeyZod.js +9 -0
  30. package/package.json +7 -6
  31. package/src/config/IdentityConfig.ts +4 -3
  32. package/src/factory/RoleServiceFactory.ts +11 -11
  33. package/src/factory/TenantServiceFactory.ts +11 -11
  34. package/src/factory/UserApiKeyServiceFactory.ts +30 -0
  35. package/src/factory/UserServiceFactory.ts +8 -7
  36. package/src/graphql/resolvers/tenant.resolvers.ts +0 -1
  37. package/src/graphql/resolvers/user-api-key.resolvers.ts +94 -0
  38. package/src/graphql/resolvers/user.resolvers.ts +9 -2
  39. package/src/graphql/types/userApiKey.graphql +33 -0
  40. package/src/index.ts +10 -0
  41. package/src/interfaces/IUserApiKeyRepository.ts +8 -0
  42. package/src/middleware/apiKeyMiddleware.ts +35 -0
  43. package/src/middleware/rbacMiddleware.ts +1 -2
  44. package/src/models/UserApiKeyModel.ts +59 -0
  45. package/src/permissions/IdentityPermissions.ts +7 -0
  46. package/src/rbac/Rbac.ts +13 -2
  47. package/src/repository/mongo/UserApiKeyMongoRepository.ts +114 -0
  48. package/src/repository/mongo/UserMongoRepository.ts +3 -3
  49. package/src/repository/sqlite/RoleSqliteRepository.ts +28 -20
  50. package/src/repository/sqlite/TenantSqliteRepository.ts +25 -11
  51. package/src/repository/sqlite/UserApiKeySqliteRepository.ts +197 -0
  52. package/src/repository/sqlite/UserSqliteRepository.ts +37 -27
  53. package/src/routes/UserApiKeyRoutes.ts +128 -0
  54. package/src/routes/UserRoutes.ts +5 -1
  55. package/src/services/TenantService.ts +49 -17
  56. package/src/services/UserApiKeyService.ts +111 -0
  57. package/src/services/UserService.ts +74 -48
  58. package/src/setup/LoadIdentityConfigFromEnv.ts +5 -3
  59. package/src/utils/AuthUtils.ts +11 -0
  60. package/src/zod/UserApiKeyZod.ts +15 -0
  61. package/test/data-obj/apikey/root-mongo-user-apikey.ts +10 -0
  62. package/test/data-obj/roles/admin-mongo-role.ts +0 -3
  63. package/test/initializers/RoleMongoInitializer.ts +1 -0
  64. package/test/initializers/RoleSqliteInitializer.ts +1 -0
  65. package/test/initializers/UserMongoInitializer.ts +18 -0
  66. package/test/repository/mongo/user-apikey-mongo-repository.test.ts +73 -0
  67. package/tsconfig.tsbuildinfo +1 -1
  68. package/types/config/IdentityConfig.d.ts +2 -3
  69. package/types/config/IdentityConfig.d.ts.map +1 -1
  70. package/types/errors/BadCredentialsError.d.ts +6 -0
  71. package/types/errors/BadCredentialsError.d.ts.map +1 -0
  72. package/types/errors/UnauthorizedError.d.ts +6 -0
  73. package/types/errors/UnauthorizedError.d.ts.map +1 -0
  74. package/types/factory/RoleServiceFactory.d.ts +4 -0
  75. package/types/factory/RoleServiceFactory.d.ts.map +1 -1
  76. package/types/factory/TenantServiceFactory.d.ts +4 -0
  77. package/types/factory/TenantServiceFactory.d.ts.map +1 -1
  78. package/types/factory/UserApiKeyServiceFactory.d.ts +4 -0
  79. package/types/factory/UserApiKeyServiceFactory.d.ts.map +1 -0
  80. package/types/factory/UserServiceFactory.d.ts +4 -0
  81. package/types/factory/UserServiceFactory.d.ts.map +1 -1
  82. package/types/graphql/index.d.ts +6 -0
  83. package/types/graphql/resolvers/tenant.resolvers.d.ts.map +1 -1
  84. package/types/graphql/resolvers/user-api-key.resolvers.d.ts +37 -0
  85. package/types/graphql/resolvers/user-api-key.resolvers.d.ts.map +1 -0
  86. package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
  87. package/types/index.d.ts +35 -0
  88. package/types/index.d.ts.map +1 -1
  89. package/types/interfaces/IRoleRepository.d.ts +9 -0
  90. package/types/interfaces/ITenantRepository.d.ts +9 -0
  91. package/types/interfaces/IUserApiKeyRepository.d.ts +7 -0
  92. package/types/interfaces/IUserApiKeyRepository.d.ts.map +1 -0
  93. package/types/interfaces/IUserRepository.d.ts +10 -0
  94. package/types/middleware/apiKeyMiddleware.d.ts +4 -0
  95. package/types/middleware/apiKeyMiddleware.d.ts.map +1 -0
  96. package/types/middleware/jwtMiddleware.d.ts +4 -0
  97. package/types/middleware/rbacMiddleware.d.ts +4 -0
  98. package/types/middleware/rbacMiddleware.d.ts.map +1 -1
  99. package/types/models/RoleModel.d.ts +16 -0
  100. package/types/models/TenantModel.d.ts +16 -0
  101. package/types/models/UserApiKeyModel.d.ts +16 -0
  102. package/types/models/UserApiKeyModel.d.ts.map +1 -0
  103. package/types/models/UserGroupModel.d.ts +16 -0
  104. package/types/models/UserModel.d.ts +16 -0
  105. package/types/permissions/IdentityPermissions.d.ts +27 -0
  106. package/types/permissions/IdentityPermissions.d.ts.map +1 -0
  107. package/types/rbac/Rbac.d.ts +15 -0
  108. package/types/rbac/Rbac.d.ts.map +1 -1
  109. package/types/repository/mongo/RoleMongoRepository.d.ts +14 -0
  110. package/types/repository/mongo/TenantMongoRepository.d.ts +14 -0
  111. package/types/repository/mongo/UserApiKeyMongoRepository.d.ts +14 -0
  112. package/types/repository/mongo/UserApiKeyMongoRepository.d.ts.map +1 -0
  113. package/types/repository/mongo/UserMongoRepository.d.ts +17 -0
  114. package/types/repository/sqlite/RoleSqliteRepository.d.ts +22 -0
  115. package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +1 -1
  116. package/types/repository/sqlite/TenantSqliteRepository.d.ts +19 -0
  117. package/types/repository/sqlite/TenantSqliteRepository.d.ts.map +1 -1
  118. package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts +19 -0
  119. package/types/repository/sqlite/UserApiKeySqliteRepository.d.ts.map +1 -0
  120. package/types/repository/sqlite/UserSqliteRepository.d.ts +25 -0
  121. package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -1
  122. package/types/routes/RoleRoutes.d.ts +4 -0
  123. package/types/routes/TenantRoutes.d.ts +4 -0
  124. package/types/routes/UserApiKeyRoutes.d.ts +4 -0
  125. package/types/routes/UserApiKeyRoutes.d.ts.map +1 -0
  126. package/types/routes/UserAvatarRoutes.d.ts +4 -0
  127. package/types/routes/UserRoutes.d.ts +4 -0
  128. package/types/routes/UserRoutes.d.ts.map +1 -1
  129. package/types/services/PermissionService.d.ts +9 -0
  130. package/types/services/PermissionService.d.ts.map +1 -0
  131. package/types/services/RoleService.d.ts +16 -0
  132. package/types/services/TenantService.d.ts +16 -0
  133. package/types/services/TenantService.d.ts.map +1 -1
  134. package/types/services/UserApiKeyService.d.ts +15 -0
  135. package/types/services/UserApiKeyService.d.ts.map +1 -0
  136. package/types/services/UserService.d.ts +21 -0
  137. package/types/services/UserService.d.ts.map +1 -1
  138. package/types/setup/CreateOrUpdateRole.d.ts +5 -0
  139. package/types/setup/CreateUserIfNotExist.d.ts +5 -0
  140. package/types/setup/LoadIdentityConfigFromEnv.d.ts +4 -0
  141. package/types/setup/LoadIdentityConfigFromEnv.d.ts.map +1 -1
  142. package/types/setup/LoadPermissions.d.ts +4 -0
  143. package/types/setup/LoadPermissions.d.ts.map +1 -0
  144. package/types/setup/RecoveryUserPassword.d.ts +4 -0
  145. package/types/utils/AuthUtils.d.ts +18 -0
  146. package/types/utils/AuthUtils.d.ts.map +1 -1
  147. package/types/zod/RoleZod.d.ts +10 -0
  148. package/types/zod/RoleZod.d.ts.map +1 -0
  149. package/types/zod/TenantZod.d.ts +10 -0
  150. package/types/zod/TenantZod.d.ts.map +1 -0
  151. package/types/zod/UserApiKeyZod.d.ts +16 -0
  152. package/types/zod/UserApiKeyZod.d.ts.map +1 -0
  153. package/types/zod/UserZod.d.ts +53 -0
  154. package/types/zod/UserZod.d.ts.map +1 -0
  155. package/src/utils/DbSetupUtils.ts +0 -41
  156. package/types/utils/DbSetupUtils.d.ts.map +0 -1
@@ -0,0 +1,9 @@
1
+ import { array, object, string } from "zod";
2
+ const userApiKeySchema = object({
3
+ name: string({ required_error: "validation.required" })
4
+ .min(1, "validation.required"),
5
+ ipv4: array(string().ip({ version: "v4", message: 'validation.invalidIpv4' })),
6
+ ipv6: array(string().ip({ version: "v6", message: 'validation.invalidIpv6' })),
7
+ });
8
+ export default userApiKeySchema;
9
+ export { userApiKeySchema };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.0.31",
6
+ "version": "0.1.2",
7
7
  "description": "Identity module for user management, authentication and authorization.",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
@@ -16,7 +16,8 @@
16
16
  "tsc": "tsc -b tsconfig.json",
17
17
  "test": "node --import tsx --test test/**/*",
18
18
  "testMongoRepositoryRole": "node --import tsx --test test/repository/mongo/role*",
19
- "testMongoRepositoryUser": "node --import tsx --test test/repository/mongo/user*",
19
+ "testMongoRepositoryUser": "node --import tsx --test test/repository/mongo/user-mongo*",
20
+ "testMongoRepositoryUserApiKey": "node --import tsx --test test/repository/mongo/user-apikey-mongo*",
20
21
  "testSqliteRepositoryUser": "node --import tsx --test test/repository/sqlite/user*",
21
22
  "testSqliteRepositoryRole": "node --import tsx --test test/repository/sqlite/role*",
22
23
  "testServiceRole": "node --import tsx --test test/service/role*",
@@ -26,9 +27,9 @@
26
27
  "author": "Cristian Incarnato & Drax Team",
27
28
  "license": "ISC",
28
29
  "dependencies": {
29
- "@drax/common-back": "^0.0.31",
30
- "@drax/common-share": "^0.0.31",
31
- "@drax/identity-share": "^0.0.31",
30
+ "@drax/common-back": "^0.1.0",
31
+ "@drax/common-share": "^0.1.0",
32
+ "@drax/identity-share": "^0.1.0",
32
33
  "bcryptjs": "^2.4.3",
33
34
  "express-jwt": "^8.4.1",
34
35
  "graphql": "^16.8.2",
@@ -59,5 +60,5 @@
59
60
  "debug": "0"
60
61
  }
61
62
  },
62
- "gitHead": "14a8c465526ef0edc3179be38fb0aaa081a4ebc4"
63
+ "gitHead": "79fef47b0aa97b4c46f057396dcafeb132ed1258"
63
64
  }
@@ -1,13 +1,14 @@
1
1
  enum IdentityConfig {
2
2
 
3
- DbEngine = "DRAX_DB_ENGINE",
4
- SqliteDbFile = "DRAX_SQLITE_FILE",
5
- MongoDbUri = "DRAX_MONGO_URI",
3
+
6
4
 
7
5
  JwtSecret = "DRAX_JWT_SECRET",
8
6
  JwtExpiration = "DRAX_JWT_EXPIRATION",
9
7
  JwtIssuer = "DRAX_JWT_ISSUER",
10
8
 
9
+ ApiKeySecret = "DRAX_APIKEY_SECRET",
10
+ ApiKeyCacheTTL = "DRAX_APIKEY_CACHE_TTL",
11
+
11
12
  RbacCacheTTL = "DRAX_RBAC_CACHE_TTL",
12
13
 
13
14
  AvatarDir = "DRAX_AVATAR_DIR",
@@ -1,26 +1,26 @@
1
- import {DraxConfig} from "@drax/common-back"
1
+ import {DraxConfig, CommonConfig, COMMON} from "@drax/common-back"
2
2
  import RoleService from "../services/RoleService.js";
3
3
  import RoleMongoRepository from "../repository/mongo/RoleMongoRepository.js";
4
4
  import RoleSqliteRepository from "../repository/sqlite/RoleSqliteRepository.js";
5
- import {DbSetupUtils, DbEngine} from "../utils/DbSetupUtils.js";
6
5
  import type {IRoleRepository} from "../interfaces/IRoleRepository";
7
6
 
8
7
  let roleService: RoleService
9
8
 
10
- const RoleServiceFactory = (verbose: boolean = false) : RoleService => {
9
+ const RoleServiceFactory = (verbose: boolean = false): RoleService => {
11
10
 
12
- if(!roleService){
11
+ if (!roleService) {
13
12
  let roleRepository: IRoleRepository
14
13
 
15
- switch (DbSetupUtils.getDbEngine()) {
16
- case DbEngine.Mongo:
17
- console.log("RoleServiceFactory DB ENGINE MONGODB")
14
+ switch (DraxConfig.getOrLoad(CommonConfig.DbEngine)) {
15
+ case COMMON.DB_ENGINES.MONGODB:
18
16
  roleRepository = new RoleMongoRepository()
19
17
  break;
20
- case DbEngine.Sqlite:
21
- console.log("RoleServiceFactory DB ENGINE SQLITE")
22
- roleRepository = new RoleSqliteRepository(DbSetupUtils.getDbConfig(), verbose)
18
+ case COMMON.DB_ENGINES.SQLITE:
19
+ const dbFile = DraxConfig.getOrLoad(CommonConfig.SqliteDbFile)
20
+ roleRepository = new RoleSqliteRepository(dbFile, verbose)
23
21
  break;
22
+ default:
23
+ throw new Error("DraxConfig.DB_ENGINE must be one of " + Object.values(COMMON.DB_ENGINES).join(", "));
24
24
  }
25
25
 
26
26
  roleService = new RoleService(roleRepository)
@@ -29,4 +29,4 @@ const RoleServiceFactory = (verbose: boolean = false) : RoleService => {
29
29
  return roleService
30
30
  }
31
31
 
32
- export default RoleServiceFactory
32
+ export default RoleServiceFactory
@@ -1,26 +1,26 @@
1
- import {DraxConfig} from "@drax/common-back"
1
+ import {COMMON, CommonConfig, DraxConfig} from "@drax/common-back"
2
2
  import TenantService from "../services/TenantService.js";
3
3
  import TenantMongoRepository from "../repository/mongo/TenantMongoRepository.js";
4
4
  import TenantSqliteRepository from "../repository/sqlite/TenantSqliteRepository.js";
5
- import {DbSetupUtils, DbEngine} from "../utils/DbSetupUtils.js";
6
5
  import type {ITenantRepository} from "../interfaces/ITenantRepository";
7
6
 
8
7
  let tenantService: TenantService
9
8
 
10
- const TenantServiceFactory = (verbose: boolean = false) : TenantService => {
9
+ const TenantServiceFactory = (verbose: boolean = false): TenantService => {
11
10
 
12
- if(!tenantService){
11
+ if (!tenantService) {
13
12
  let tenantRepository: ITenantRepository
14
13
 
15
- switch (DbSetupUtils.getDbEngine()) {
16
- case DbEngine.Mongo:
17
- console.log("TenantServiceFactory DB ENGINE MONGODB")
14
+ switch (DraxConfig.getOrLoad(CommonConfig.DbEngine)) {
15
+ case COMMON.DB_ENGINES.MONGODB:
18
16
  tenantRepository = new TenantMongoRepository()
19
17
  break;
20
- case DbEngine.Sqlite:
21
- console.log("TenantServiceFactory DB ENGINE SQLITE")
22
- tenantRepository = new TenantSqliteRepository(DbSetupUtils.getDbConfig(), verbose)
18
+ case COMMON.DB_ENGINES.SQLITE:
19
+ const dbFile = DraxConfig.getOrLoad(CommonConfig.SqliteDbFile)
20
+ tenantRepository = new TenantSqliteRepository(dbFile, verbose)
23
21
  break;
22
+ default:
23
+ throw new Error("DraxConfig.DB_ENGINE must be one of " + Object.values(COMMON.DB_ENGINES).join(", "));
24
24
  }
25
25
 
26
26
  tenantService = new TenantService(tenantRepository)
@@ -29,4 +29,4 @@ const TenantServiceFactory = (verbose: boolean = false) : TenantService => {
29
29
  return tenantService
30
30
  }
31
31
 
32
- export default TenantServiceFactory
32
+ export default TenantServiceFactory
@@ -0,0 +1,30 @@
1
+ import UserApiKeyMongoRepository from "../repository/mongo/UserApiKeyMongoRepository.js";
2
+ import UserApiKeyService from "../services/UserApiKeyService.js";
3
+ import UserApiKeySqliteRepository from "../repository/sqlite/UserApiKeySqliteRepository.js";
4
+ import {IUserApiKeyRepository} from "../interfaces/IUserApiKeyRepository";
5
+ import {COMMON, CommonConfig, DraxConfig} from "@drax/common-back";
6
+
7
+ let userService: UserApiKeyService
8
+
9
+ const UserApiKeyServiceFactory = (verbose: boolean = false): UserApiKeyService => {
10
+ if (!userService) {
11
+ let userRepository: IUserApiKeyRepository
12
+ switch (DraxConfig.getOrLoad(CommonConfig.DbEngine)) {
13
+ case COMMON.DB_ENGINES.MONGODB:
14
+ userRepository = new UserApiKeyMongoRepository()
15
+ break;
16
+ case COMMON.DB_ENGINES.SQLITE:
17
+ const dbFile = DraxConfig.getOrLoad(CommonConfig.SqliteDbFile)
18
+ userRepository = new UserApiKeySqliteRepository(dbFile, verbose)
19
+ break;
20
+ default:
21
+ throw new Error("DraxConfig.DB_ENGINE must be one of " + Object.values(COMMON.DB_ENGINES).join(", "));
22
+ }
23
+
24
+ userService = new UserApiKeyService(userRepository)
25
+ }
26
+
27
+ return userService
28
+ }
29
+
30
+ export default UserApiKeyServiceFactory
@@ -1,23 +1,24 @@
1
1
  import UserMongoRepository from "../repository/mongo/UserMongoRepository.js";
2
2
  import UserService from "../services/UserService.js";
3
3
  import UserSqliteRepository from "../repository/sqlite/UserSqliteRepository.js";
4
- import {DbEngine, DbSetupUtils} from "../utils/DbSetupUtils.js";
5
4
  import {IUserRepository} from "../interfaces/IUserRepository";
5
+ import {COMMON, CommonConfig, DraxConfig} from "@drax/common-back";
6
6
 
7
7
  let userService: UserService
8
8
 
9
9
  const UserServiceFactory = (verbose:boolean = false) : UserService => {
10
10
  if(!userService){
11
11
  let userRepository: IUserRepository
12
- switch (DbSetupUtils.getDbEngine()) {
13
- case DbEngine.Mongo:
14
- console.log("UserServiceFactory DB ENGINE MONGODB")
12
+ switch (DraxConfig.getOrLoad(CommonConfig.DbEngine)) {
13
+ case COMMON.DB_ENGINES.MONGODB:
15
14
  userRepository = new UserMongoRepository()
16
15
  break;
17
- case DbEngine.Sqlite:
18
- console.log("UserServiceFactory DB ENGINE SQLITE")
19
- userRepository = new UserSqliteRepository(DbSetupUtils.getDbConfig(),verbose)
16
+ case COMMON.DB_ENGINES.SQLITE:
17
+ const dbFile = DraxConfig.getOrLoad(CommonConfig.SqliteDbFile)
18
+ userRepository = new UserSqliteRepository(dbFile,verbose)
20
19
  break;
20
+ default:
21
+ throw new Error("DraxConfig.DB_ENGINE must be one of " + Object.values(COMMON.DB_ENGINES).join(", "));
21
22
  }
22
23
 
23
24
  userService = new UserService(userRepository)
@@ -2,7 +2,6 @@ import TenantServiceFactory from "../../factory/TenantServiceFactory.js";
2
2
  import {IdentityPermissions} from "../../permissions/IdentityPermissions.js";
3
3
  import {ValidationError, ValidationErrorToGraphQLError} from "@drax/common-back";
4
4
  import {GraphQLError} from "graphql";
5
- import {PermissionService} from "../../services/PermissionService.js";
6
5
  import UnauthorizedError from "../../errors/UnauthorizedError.js";
7
6
 
8
7
 
@@ -0,0 +1,94 @@
1
+ import UserApiKeyServiceFactory from "../../factory/UserApiKeyServiceFactory.js";
2
+ import {IdentityPermissions} from "../../permissions/IdentityPermissions.js";
3
+ import {ValidationError, ValidationErrorToGraphQLError} from "@drax/common-back";
4
+ import {GraphQLError} from "graphql";
5
+ import UnauthorizedError from "../../errors/UnauthorizedError.js";
6
+ import * as crypto from "node:crypto";
7
+
8
+
9
+ export default {
10
+ Query: {
11
+ paginateUserApiKey: async (_, {options= {page:1, limit:5, orderBy:"", orderDesc:false, search:"", filters: []} }, {rbac, authUser}) => {
12
+ try {
13
+ rbac.assertAuthenticated()
14
+
15
+
16
+ rbac.assertOrPermissions([
17
+ IdentityPermissions.ViewUserApiKey,
18
+ IdentityPermissions.ViewMyUserApiKey
19
+ ])
20
+
21
+ if(!Array.isArray(options.filters)){
22
+ options.filters = []
23
+ }
24
+
25
+ if(!rbac.hasPermission(IdentityPermissions.ViewUserApiKey)){
26
+ options.filters.push({field: "user", operator: "eq", value: rbac.authUser.id})
27
+ }
28
+
29
+ const userApiKeyService = UserApiKeyServiceFactory()
30
+ return await userApiKeyService.paginate(options)
31
+ } catch (e) {
32
+ console.error("paginateUserApiKey",e)
33
+ if (e instanceof UnauthorizedError) {
34
+ throw new GraphQLError(e.message)
35
+ }
36
+ throw new GraphQLError('error.server')
37
+ }
38
+ }
39
+ },
40
+ Mutation: {
41
+ createUserApiKey: async (_, {input}, {rbac}) => {
42
+ try {
43
+ rbac.assertPermission(IdentityPermissions.CreateUserApiKey)
44
+ input.user = rbac.authUser.id
45
+ input.secret = crypto.randomUUID()
46
+ const userApiKeyService = UserApiKeyServiceFactory(true)
47
+ return await userApiKeyService.create(input)
48
+ } catch (e) {
49
+ console.error("createUserApiKey",e)
50
+ if (e instanceof ValidationError) {
51
+ throw ValidationErrorToGraphQLError(e)
52
+ }
53
+ if (e instanceof UnauthorizedError) {
54
+ throw new GraphQLError(e.message)
55
+ }
56
+ throw new GraphQLError('error.server')
57
+ }
58
+
59
+ },
60
+ updateUserApiKey: async (_, {id, input}, {rbac}) => {
61
+ try {
62
+ rbac.assertPermission(IdentityPermissions.UpdateUserApiKey)
63
+ const userApiKeyService = UserApiKeyServiceFactory()
64
+ return await userApiKeyService.update(id, input)
65
+ } catch (e) {
66
+ console.error("updateUserApiKey",e)
67
+ if (e instanceof ValidationError) {
68
+ throw ValidationErrorToGraphQLError(e)
69
+ }
70
+ if (e instanceof UnauthorizedError) {
71
+ throw new GraphQLError(e.message)
72
+ }
73
+ throw new GraphQLError('error.server')
74
+ }
75
+ },
76
+ deleteUserApiKey: async (_, {id}, {rbac}) => {
77
+ try {
78
+ rbac.assertPermission(IdentityPermissions.DeleteUserApiKey)
79
+ const userApiKeyService = UserApiKeyServiceFactory()
80
+ return await userApiKeyService.delete(id)
81
+ } catch (e) {
82
+ console.error("deleteUserApiKey",e)
83
+ if (e instanceof ValidationError) {
84
+ throw ValidationErrorToGraphQLError(e)
85
+ }
86
+ if (e instanceof UnauthorizedError) {
87
+ throw new GraphQLError(e.message)
88
+ }
89
+ throw new GraphQLError('error.server')
90
+ }
91
+
92
+ }
93
+ }
94
+ }
@@ -20,7 +20,7 @@ export default {
20
20
  if (authUser) {
21
21
  let userService = UserServiceFactory()
22
22
  let user = await userService.findById(authUser.id)
23
- delete user.password
23
+ user.password = undefined
24
24
  return user
25
25
  }
26
26
  throw new UnauthorizedError()
@@ -34,7 +34,9 @@ export default {
34
34
  try {
35
35
  rbac.assertPermission(IdentityPermissions.ViewUser)
36
36
  let userService = UserServiceFactory()
37
- return await userService.findById(id)
37
+ let user = await userService.findById(id)
38
+ user.password = undefined
39
+ return user
38
40
  } catch (e) {
39
41
  if (e instanceof UnauthorizedError) {
40
42
  throw new GraphQLError(e.message)
@@ -47,6 +49,11 @@ export default {
47
49
  try {
48
50
  rbac.assertPermission(IdentityPermissions.ViewUser)
49
51
  let userService = UserServiceFactory()
52
+
53
+ if(!options.filters){
54
+ options.filters = []
55
+ }
56
+
50
57
  if (rbac.getAuthUser.tenantId) {
51
58
  options.filters.push({field: 'tenant', operator: '$eq', value: rbac.getAuthUser.tenantId})
52
59
  }
@@ -0,0 +1,33 @@
1
+ type UserApiKey {
2
+ id: ID!
3
+ name: String
4
+ secret: String
5
+ ipv4: [String]
6
+ ipv6: [String]
7
+ user: User
8
+ createdAt: Date
9
+ updatedAt: Date
10
+ }
11
+
12
+ type UserApiKeyPaginated{
13
+ total: Int
14
+ page: Int
15
+ limit: Int
16
+ items: [UserApiKey]
17
+ }
18
+
19
+ type Query{
20
+ paginateUserApiKey(options: PaginateOptions): UserApiKeyPaginated
21
+ }
22
+
23
+ input UserApiKeyInput{
24
+ name: String
25
+ ipv4: [String]
26
+ ipv6: [String]
27
+ }
28
+
29
+ type Mutation{
30
+ createUserApiKey(input: UserApiKeyInput): UserApiKey
31
+ updateUserApiKey(id: ID!, input: UserApiKeyInput): UserApiKey
32
+ deleteUserApiKey(id: ID!): Boolean
33
+ }
package/src/index.ts CHANGED
@@ -2,18 +2,24 @@ import GraphqlMerge from "./graphql/index.js"
2
2
  import UserServiceFactory from "./factory/UserServiceFactory.js";
3
3
  import RoleServiceFactory from "./factory/RoleServiceFactory.js";
4
4
  import TenantServiceFactory from "./factory/TenantServiceFactory.js";
5
+
5
6
  import RoleService from "./services/RoleService.js";
6
7
  import UserService from "./services/UserService.js";
7
8
  import TenantService from "./services/TenantService.js";
8
9
  import PermissionService from "./services/PermissionService.js";
10
+
9
11
  import Rbac from "./rbac/Rbac.js";
12
+
10
13
  import {UserRoutes} from "./routes/UserRoutes.js";
11
14
  import {UserAvatarRoutes} from "./routes/UserAvatarRoutes.js";
12
15
  import {RoleRoutes} from "./routes/RoleRoutes.js";
13
16
  import {TenantRoutes} from "./routes/TenantRoutes.js";
17
+ import {UserApiKeyRoutes} from "./routes/UserApiKeyRoutes.js";
18
+
14
19
  import AuthUtils from "./utils/AuthUtils.js";
15
20
  import {jwtMiddleware} from "./middleware/jwtMiddleware.js";
16
21
  import {rbacMiddleware} from "./middleware/rbacMiddleware.js";
22
+ import {apiKeyMiddleware} from "./middleware/apiKeyMiddleware.js";
17
23
 
18
24
  import IdentityPermissions from "./permissions/IdentityPermissions.js";
19
25
  import IdentityConfig from "./config/IdentityConfig.js";
@@ -29,6 +35,7 @@ import RecoveryUserPassword from "./setup/RecoveryUserPassword.js";
29
35
  import type {IRoleRepository} from "./interfaces/IRoleRepository";
30
36
  import type {ITenantRepository} from "./interfaces/ITenantRepository";
31
37
  import type {IUserRepository} from "./interfaces/IUserRepository";
38
+ import type {IUserApiKeyRepository} from "./interfaces/IUserApiKeyRepository";
32
39
 
33
40
 
34
41
  const graphqlMergeResult = await GraphqlMerge()
@@ -40,6 +47,7 @@ export type {
40
47
  IRoleRepository,
41
48
  ITenantRepository,
42
49
  IUserRepository,
50
+ IUserApiKeyRepository
43
51
  }
44
52
 
45
53
  export {
@@ -64,12 +72,14 @@ export {
64
72
  RoleRoutes,
65
73
  TenantRoutes,
66
74
  UserAvatarRoutes,
75
+ UserApiKeyRoutes,
67
76
 
68
77
  AuthUtils,
69
78
 
70
79
  //API MIDDLEWARE
71
80
  jwtMiddleware,
72
81
  rbacMiddleware,
82
+ apiKeyMiddleware,
73
83
 
74
84
  //Permissions
75
85
  IdentityPermissions,
@@ -0,0 +1,8 @@
1
+ import {IUserApiKey, IUserApiKeyBase} from '@drax/identity-share'
2
+ import {IDraxCrud} from "@drax/common-share";
3
+
4
+ interface IUserApiKeyRepository extends IDraxCrud<IUserApiKey, IUserApiKeyBase, IUserApiKeyBase>{
5
+ findBySecret(username: string): Promise<IUserApiKey | null>;
6
+ }
7
+
8
+ export {IUserApiKeyRepository}
@@ -0,0 +1,35 @@
1
+ import {IUserApiKey} from "@drax/identity-share";
2
+ import {DraxCache, DraxConfig} from "@drax/common-back";
3
+ import UserApiKeyServiceFactory from "../factory/UserApiKeyServiceFactory.js";
4
+ import IdentityConfig from "../config/IdentityConfig.js";
5
+
6
+ const cacheTTL = DraxConfig.getOrLoad(IdentityConfig.ApiKeyCacheTTL) ? parseInt(DraxConfig.getOrLoad(IdentityConfig.ApiKeyCacheTTL)) : 10000;
7
+ const draxCache = new DraxCache<IUserApiKey>(cacheTTL);
8
+
9
+
10
+ async function userApiKeyLoader(k):Promise<IUserApiKey | null> {
11
+ const userApiKeyService = UserApiKeyServiceFactory()
12
+ const userApiKey: IUserApiKey = await userApiKeyService.findBySecret(k)
13
+ return userApiKey
14
+ }
15
+
16
+ async function apiKeyMiddleware (request, reply) {
17
+ try{
18
+ const apiKey = request.headers['x-api-key']
19
+ if(apiKey){
20
+ const userApiKey = await draxCache.getOrLoad(apiKey, userApiKeyLoader)
21
+ if(userApiKey && userApiKey.user){
22
+ request.authUser = userApiKey.user
23
+ request.authUser.roleId = userApiKey.user.role.id
24
+ request.authUser.tenantId = userApiKey.user.tenant.id
25
+ }
26
+ }
27
+ return
28
+ }catch (e) {
29
+ console.error(e)
30
+ reply.code(500).send({ error: 'APIKEY ERROR' });
31
+ }
32
+ }
33
+
34
+ export default apiKeyMiddleware;
35
+ export {apiKeyMiddleware}
@@ -16,10 +16,9 @@ async function roleLoader(k):Promise<IRole | null> {
16
16
 
17
17
  async function rbacMiddleware (request, reply) {
18
18
  try{
19
- //console.log("rbacMiddleware authUser",request.authUser)
20
19
  if(request.authUser as IJwtUser){
21
20
  const authUser = request.authUser
22
- const cacheKey= authUser.roleId
21
+ const cacheKey = authUser.roleId
23
22
  const role = await draxCache.getOrLoad(cacheKey, roleLoader)
24
23
  const rbac = new Rbac(authUser,role)
25
24
  request.rbac = rbac
@@ -0,0 +1,59 @@
1
+ import {mongoose, MongooseSoftDelete} from '@drax/common-back';
2
+ import {IUserApiKey} from "@drax/identity-share";
3
+ import uniqueValidator from 'mongoose-unique-validator';
4
+ import mongoosePaginate from 'mongoose-paginate-v2'
5
+ import {PaginateModel} from "mongoose";
6
+
7
+ // Defining user Mongoose Schema
8
+ const UserApiKeySchema = new mongoose.Schema<IUserApiKey>({
9
+ name: {
10
+ type: String,
11
+ unique: false,
12
+ required: true,
13
+ index: false,
14
+ },
15
+ secret: {
16
+ type: String,
17
+ unique: false,
18
+ required: true,
19
+ index: true,
20
+ },
21
+ user: {
22
+ type: mongoose.Schema.Types.ObjectId,
23
+ ref: 'User',
24
+ required: true,
25
+ },
26
+ ipv4: [{
27
+ type: String,
28
+ unique: false,
29
+ required: false,
30
+ index: false,
31
+ }],
32
+ ipv6: [{
33
+ type: String,
34
+ unique: false,
35
+ required: false,
36
+ index: false,
37
+ }],
38
+ }, {timestamps: true});
39
+
40
+ UserApiKeySchema.set('toJSON', {getters: true});
41
+
42
+ UserApiKeySchema.plugin(uniqueValidator, {message: 'validation.unique'});
43
+
44
+ UserApiKeySchema.plugin(MongooseSoftDelete);
45
+ UserApiKeySchema.plugin(mongoosePaginate);
46
+
47
+ const MODEL_NAME = 'UserApiKey';
48
+ const COLLECTION_NAME = 'userApiKeys';
49
+
50
+ const UserApiKeyModel = mongoose.model<IUserApiKey,PaginateModel<IUserApiKey>>(MODEL_NAME, UserApiKeySchema,COLLECTION_NAME);
51
+
52
+
53
+ export {
54
+ UserApiKeySchema,
55
+ UserApiKeyModel
56
+ }
57
+
58
+ export default UserApiKeyModel
59
+
@@ -7,6 +7,13 @@ enum IdentityPermissions {
7
7
  ViewUser = "user:view",
8
8
  ManageUser = "user:manage",
9
9
 
10
+ CreateUserApiKey = "userApiKey:create",
11
+ UpdateUserApiKey = "userApiKey:update",
12
+ DeleteUserApiKey = "userApiKey:delete",
13
+ ViewUserApiKey = "userApiKey:view",
14
+ ViewMyUserApiKey = "userApiKey:myView",
15
+ ManageUserApiKey = "userApiKey:manage",
16
+
10
17
  CreateRole = "role:create",
11
18
  UpdateRole = "role:update",
12
19
  DeleteRole = "role:delete",
package/src/rbac/Rbac.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import {IJwtUser, IRole} from "@drax/identity-share";
2
2
  import UnauthorizedError from "../errors/UnauthorizedError.js";
3
3
 
4
- class Rbac{
4
+ class Rbac {
5
5
  private role: IRole;
6
6
  private authUser: IJwtUser;
7
7
 
@@ -27,11 +27,22 @@ class Rbac{
27
27
  }
28
28
 
29
29
  assertPermission(requiredPermission: string) {
30
- if(!this.hasPermission(requiredPermission)){
30
+ if (!this.hasPermission(requiredPermission)) {
31
31
  throw new UnauthorizedError()
32
32
  }
33
33
  }
34
34
 
35
+ assertOrPermissions(requiredPermissions: string[]) {
36
+
37
+ for(let requiredPermission of requiredPermissions){
38
+ if (this.hasPermission(requiredPermission)) {
39
+ return true
40
+ }
41
+ }
42
+
43
+ throw new UnauthorizedError()
44
+ }
45
+
35
46
  assertAuthenticated() {
36
47
  if (!this.authUser) {
37
48
  throw new UnauthorizedError()