@drax/identity-back 0.46.0 → 0.47.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.
@@ -8,6 +8,7 @@ var IdentityConfig;
8
8
  IdentityConfig["RbacCacheTTL"] = "DRAX_RBAC_CACHE_TTL";
9
9
  IdentityConfig["AvatarDir"] = "DRAX_AVATAR_DIR";
10
10
  IdentityConfig["defaultRole"] = "DRAX_DEFAULT_ROLE";
11
+ IdentityConfig["VerifyIP"] = "DRAX_VERIFY_IP";
11
12
  })(IdentityConfig || (IdentityConfig = {}));
12
13
  export default IdentityConfig;
13
14
  export { IdentityConfig };
@@ -1,6 +1,7 @@
1
1
  import { DraxCache, DraxConfig } from "@drax/common-back";
2
2
  import UserApiKeyServiceFactory from "../factory/UserApiKeyServiceFactory.js";
3
3
  import IdentityConfig from "../config/IdentityConfig.js";
4
+ const verifyIp = DraxConfig.getOrLoad(IdentityConfig.VerifyIP) ? /true/i.test(DraxConfig.getOrLoad(IdentityConfig.VerifyIP)) : false;
4
5
  const cacheTTL = DraxConfig.getOrLoad(IdentityConfig.ApiKeyCacheTTL) ? parseInt(DraxConfig.getOrLoad(IdentityConfig.ApiKeyCacheTTL)) : 10000;
5
6
  const draxCache = new DraxCache(cacheTTL);
6
7
  async function userApiKeyLoader(k) {
@@ -27,6 +28,22 @@ async function apiKeyMiddleware(request, reply) {
27
28
  }
28
29
  if (apiKey) {
29
30
  const userApiKey = await draxCache.getOrLoad(apiKey, userApiKeyLoader);
31
+ if (verifyIp) {
32
+ if (userApiKey.ipv4 && userApiKey.ipv4.length > 0) {
33
+ const clientIp = request.ip;
34
+ if (!userApiKey.ipv4.includes(clientIp)) {
35
+ reply.code(401).send({ "statusCode": "401", error: 'IP not allowed', i18nMessage: 'error.ipNotAllowed', clientIp: clientIp, message: `Remote IP ${clientIp} is not allowed` });
36
+ return;
37
+ }
38
+ }
39
+ else if (userApiKey.ipv6 && userApiKey.ipv6.length > 0) {
40
+ const clientIp = request.ip;
41
+ if (!userApiKey.ipv6.includes(clientIp)) {
42
+ reply.code(401).send({ "statusCode": "401", error: 'IP not allowed', i18nMessage: 'error.ipNotAllowed', clientIp: clientIp, message: `Remote IP ${clientIp} is not allowed` });
43
+ return;
44
+ }
45
+ }
46
+ }
30
47
  if (userApiKey && userApiKey.user) {
31
48
  const authUser = {
32
49
  id: userApiKey.user._id.toString(),
@@ -32,12 +32,13 @@ class UserApiKeySqliteRepository extends AbstractSqliteRepository {
32
32
  if (item && item.createdBy) {
33
33
  item.createdBy = await this.findUserById(item.createdBy);
34
34
  }
35
- if (item && item.ipv4) {
36
- item.ipv4 = item.ipv4 != "" ? item.ipv4.split(',') : [];
35
+ if (item && item.hasOwnProperty('ipv4')) {
36
+ item.ipv4 = item.ipv4 ? item.ipv4.split(',') : [];
37
37
  }
38
- if (item && item.ipv6) {
39
- item.ipv6 = item.ipv6 != "" ? item.ipv6.split(',') : [];
38
+ if (item && item.hasOwnProperty('ipv6')) {
39
+ item.ipv6 = item.ipv6 ? item.ipv6.split(',') : [];
40
40
  }
41
+ return item;
41
42
  }
42
43
  async prepareData(userApiKeyData) {
43
44
  if (userApiKeyData.ipv4 && Array.isArray(userApiKeyData.ipv4) && userApiKeyData.ipv4.length > 0) {
@@ -52,6 +53,12 @@ class UserApiKeySqliteRepository extends AbstractSqliteRepository {
52
53
  else {
53
54
  userApiKeyData.ipv6 = "";
54
55
  }
56
+ if (userApiKeyData.user && userApiKeyData.user.hasOwnProperty('_id')) {
57
+ userApiKeyData.user = userApiKeyData.user._id;
58
+ }
59
+ if (userApiKeyData.createdBy && userApiKeyData.createdBy.hasOwnProperty('_id')) {
60
+ userApiKeyData.createdBy = userApiKeyData.createdBy._id;
61
+ }
55
62
  }
56
63
  async findBySecret(secret) {
57
64
  const userApiKey = this.db.prepare('SELECT * FROM user_api_keys WHERE secret = ?').get(secret);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.46.0",
6
+ "version": "0.47.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.46.0",
32
- "@drax/crud-back": "^0.46.0",
33
- "@drax/crud-share": "^0.46.0",
34
- "@drax/email-back": "^0.46.0",
35
- "@drax/identity-share": "^0.46.0",
31
+ "@drax/common-back": "^0.47.0",
32
+ "@drax/crud-back": "^0.47.0",
33
+ "@drax/crud-share": "^0.47.0",
34
+ "@drax/email-back": "^0.47.0",
35
+ "@drax/identity-share": "^0.47.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": "9625999c86d538dc3bee7c501acba6c51592ebca"
66
+ "gitHead": "65a17b06254404866deb9fb81daf42fbe3d2db3c"
67
67
  }
@@ -1,7 +1,5 @@
1
1
  enum IdentityConfig {
2
2
 
3
-
4
-
5
3
  JwtSecret = "DRAX_JWT_SECRET",
6
4
  JwtExpiration = "DRAX_JWT_EXPIRATION",
7
5
  JwtIssuer = "DRAX_JWT_ISSUER",
@@ -15,6 +13,7 @@ enum IdentityConfig {
15
13
 
16
14
  defaultRole = "DRAX_DEFAULT_ROLE",
17
15
 
16
+ VerifyIP = "DRAX_VERIFY_IP",
18
17
 
19
18
  }
20
19
 
@@ -3,58 +3,77 @@ import {DraxCache, DraxConfig} from "@drax/common-back";
3
3
  import UserApiKeyServiceFactory from "../factory/UserApiKeyServiceFactory.js";
4
4
  import IdentityConfig from "../config/IdentityConfig.js";
5
5
 
6
+ const verifyIp = DraxConfig.getOrLoad(IdentityConfig.VerifyIP) ? /true/i.test(DraxConfig.getOrLoad(IdentityConfig.VerifyIP)) : false;
6
7
  const cacheTTL = DraxConfig.getOrLoad(IdentityConfig.ApiKeyCacheTTL) ? parseInt(DraxConfig.getOrLoad(IdentityConfig.ApiKeyCacheTTL)) : 10000;
7
8
  const draxCache = new DraxCache<IUserApiKey>(cacheTTL);
8
9
 
9
10
 
10
- async function userApiKeyLoader(k):Promise<IUserApiKey | null> {
11
+ async function userApiKeyLoader(k): Promise<IUserApiKey | null> {
11
12
  const userApiKeyService = UserApiKeyServiceFactory()
12
13
  const userApiKey: IUserApiKey = await userApiKeyService.findBySecret(k)
13
14
  return userApiKey
14
15
  }
15
16
 
16
- async function apiKeyMiddleware (request, reply) {
17
- try{
18
- let apiKey: string
17
+ async function apiKeyMiddleware(request, reply) {
18
+ try {
19
+ let apiKey: string
19
20
 
20
- //Por header 'x-api-key'
21
- if(request.headers['x-api-key']){
22
- apiKey = request.headers['x-api-key']
23
- }
21
+ //Por header 'x-api-key'
22
+ if (request.headers['x-api-key']) {
23
+ apiKey = request.headers['x-api-key']
24
+ }
24
25
 
25
- //Por authorization 'ApiKey <uuid-key>'
26
- const apiKeyRegExp = /^ApiKey (.*)$/i;
27
- if(request.headers['authorization'] && apiKeyRegExp.test(request.headers['authorization'])){
28
- apiKey = request.headers?.authorization?.replace(/ApiKey /i, "")
29
- }
26
+ //Por authorization 'ApiKey <uuid-key>'
27
+ const apiKeyRegExp = /^ApiKey (.*)$/i;
28
+ if (request.headers['authorization'] && apiKeyRegExp.test(request.headers['authorization'])) {
29
+ apiKey = request.headers?.authorization?.replace(/ApiKey /i, "")
30
+ }
30
31
 
31
- //Por authorization '<uuid-key>'
32
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
33
- if(request.headers['authorization'] && uuidRegex.test(request.headers['authorization'])){
34
- apiKey = request.headers['authorization']
35
- }
32
+ //Por authorization '<uuid-key>'
33
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
34
+ if (request.headers['authorization'] && uuidRegex.test(request.headers['authorization'])) {
35
+ apiKey = request.headers['authorization']
36
+ }
36
37
 
37
- if(apiKey){
38
- const userApiKey : IUserApiKey = await draxCache.getOrLoad(apiKey, userApiKeyLoader)
39
- if(userApiKey && userApiKey.user){
40
- const authUser: IAuthUser = {
41
- id: userApiKey.user._id.toString(),
42
- username: userApiKey.user.username,
43
- roleId: userApiKey.user.role?._id?.toString(),
44
- roleName: userApiKey.user.role?.name,
45
- tenantId: userApiKey.user?.tenant?._id?.toString(),
46
- tenantName: userApiKey.user?.tenant?.name,
47
- apiKeyId: userApiKey?._id?.toString(),
48
- apiKeyName: userApiKey?.name
38
+ if (apiKey) {
39
+ const userApiKey: IUserApiKey = await draxCache.getOrLoad(apiKey, userApiKeyLoader)
40
+
41
+ if (verifyIp) {
42
+ if (userApiKey.ipv4 && userApiKey.ipv4.length > 0) {
43
+ const clientIp = request.ip
44
+ if (!userApiKey.ipv4.includes(clientIp)) {
45
+ reply.code(401).send({"statusCode": "401", error: 'IP not allowed', i18nMessage: 'error.ipNotAllowed', clientIp: clientIp, message: `Remote IP ${clientIp} is not allowed`});
46
+ return
47
+ }
48
+ } else if (userApiKey.ipv6 && userApiKey.ipv6.length > 0) {
49
+ const clientIp = request.ip
50
+ if (!userApiKey.ipv6.includes(clientIp)) {
51
+ reply.code(401).send({"statusCode": "401", error: 'IP not allowed', i18nMessage: 'error.ipNotAllowed', clientIp: clientIp, message: `Remote IP ${clientIp} is not allowed`});
52
+ return
49
53
  }
50
- request.authUser = authUser
51
54
  }
52
55
  }
53
- return
54
- }catch (e) {
55
- console.error(e)
56
- reply.code(500).send({ error: 'APIKEY ERROR' });
56
+
57
+
58
+ if (userApiKey && userApiKey.user) {
59
+ const authUser: IAuthUser = {
60
+ id: userApiKey.user._id.toString(),
61
+ username: userApiKey.user.username,
62
+ roleId: userApiKey.user.role?._id?.toString(),
63
+ roleName: userApiKey.user.role?.name,
64
+ tenantId: userApiKey.user?.tenant?._id?.toString(),
65
+ tenantName: userApiKey.user?.tenant?.name,
66
+ apiKeyId: userApiKey?._id?.toString(),
67
+ apiKeyName: userApiKey?.name
68
+ }
69
+ request.authUser = authUser
70
+ }
57
71
  }
72
+ return
73
+ } catch (e) {
74
+ console.error(e)
75
+ reply.code(500).send({error: 'APIKEY ERROR'});
76
+ }
58
77
  }
59
78
 
60
79
  export default apiKeyMiddleware;
@@ -40,6 +40,8 @@ class UserApiKeySqliteRepository extends AbstractSqliteRepository<IUserApiKey, I
40
40
  }
41
41
 
42
42
  async prepareItem(item: any): Promise<any> {
43
+
44
+
43
45
  if (item && item.user) {
44
46
  item.user = await this.findUserById(item.user)
45
47
  }
@@ -48,16 +50,19 @@ class UserApiKeySqliteRepository extends AbstractSqliteRepository<IUserApiKey, I
48
50
  item.createdBy = await this.findUserById(item.createdBy)
49
51
  }
50
52
 
51
- if (item && item.ipv4) {
52
- item.ipv4 = item.ipv4 != "" ? item.ipv4.split(',') : []
53
+ if (item && item.hasOwnProperty('ipv4')) {
54
+ item.ipv4 = item.ipv4 ? item.ipv4.split(',') : []
53
55
  }
54
56
 
55
- if (item && item.ipv6) {
56
- item.ipv6 = item.ipv6 != "" ? item.ipv6.split(',') : []
57
+ if (item && item.hasOwnProperty('ipv6')) {
58
+ item.ipv6 = item.ipv6 ? item.ipv6.split(',') : []
57
59
  }
60
+
61
+ return item;
58
62
  }
59
63
 
60
64
  async prepareData(userApiKeyData) {
65
+
61
66
  if (userApiKeyData.ipv4 && Array.isArray(userApiKeyData.ipv4) && userApiKeyData.ipv4.length > 0) {
62
67
  userApiKeyData.ipv4 = userApiKeyData.ipv4.join(',')
63
68
  } else {
@@ -69,6 +74,15 @@ class UserApiKeySqliteRepository extends AbstractSqliteRepository<IUserApiKey, I
69
74
  } else {
70
75
  userApiKeyData.ipv6 = ""
71
76
  }
77
+
78
+ if(userApiKeyData.user && userApiKeyData.user.hasOwnProperty('_id')) {
79
+ userApiKeyData.user = userApiKeyData.user._id
80
+ }
81
+
82
+ if(userApiKeyData.createdBy && userApiKeyData.createdBy.hasOwnProperty('_id')) {
83
+ userApiKeyData.createdBy = userApiKeyData.createdBy._id
84
+ }
85
+
72
86
  }
73
87
 
74
88