beech-api 3.8.0 → 3.9.0-beta.8-rc

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,5 +1,9 @@
1
+ const fs = require("fs");
1
2
  const { FindOne } = require("../../../lib/src/user");
2
3
  const { findPassportPk } = require("./poolEntity");
4
+ const passport_config_file = appRoot + "/passport.config.js";
5
+ const md5 = require("md5");
6
+ const secret = require("../../../lib/src/salt").salt;
3
7
 
4
8
  function TwoFactor(user, reqBody, guard_field, cb) {
5
9
  try {
@@ -8,6 +12,22 @@ function TwoFactor(user, reqBody, guard_field, cb) {
8
12
  cb(true, err);
9
13
  } else {
10
14
  if(userId.length) {
15
+ if (fs.existsSync(passport_config_file)) {
16
+ passport_config = require(passport_config_file);
17
+ } else {
18
+ cb(true, {
19
+ code: 500,
20
+ status: "INTERNAL_SERVER_ERR",
21
+ error: {
22
+ code: 404,
23
+ status: "ERROR_FILE_NOT_EXISTS",
24
+ message: "The file passport.config.js not exists!",
25
+ }
26
+ });
27
+ return;
28
+ }
29
+ let usrField = passport_config.model.username_field || "username";
30
+ let pwdField = passport_config.model.password_field || "password"
11
31
  // filter without base user, pass
12
32
  let without_base = Object.keys(reqBody).map((k) => {
13
33
  return guard_field.filter((e) => e == k)[0];
@@ -19,7 +39,8 @@ function TwoFactor(user, reqBody, guard_field, cb) {
19
39
  // check length match ?
20
40
  if(x.length == guard_field.length) {
21
41
  let z = {};
22
- z[userId[0]] = user.id;
42
+ z[usrField] = reqBody[usrField];
43
+ z[pwdField] = md5(reqBody[pwdField] + secret);
23
44
  x.map((guard) => {
24
45
  z[guard] = reqBody[guard];
25
46
  });
@@ -34,7 +34,19 @@ function getAppKey(cb) {
34
34
 
35
35
  function HashIt(txt, app_key, iteration = 10000, len = 10, cb) {
36
36
  const crypIt = new Cryptr(secret.toString().concat(app_key.toString()), { encoding: "base64url", pbkdf2Iterations: iteration, saltLength: len, });
37
- cb(crypIt.encrypt(txt.concat(md5(secret).toString().slice(0,len+1))));
37
+ let result = "";
38
+ let loop = 0;
39
+ const maxLoop = 10;
40
+ do {
41
+ const payload = txt.concat(md5(secret).toString().slice(0, len + 1));
42
+ result = crypIt.encrypt(payload);
43
+ loop++;
44
+ if (loop >= maxLoop) {
45
+ console.log("\n FAIL  Hash loop limit exceeded, Try again.");
46
+ return;
47
+ }
48
+ } while (/[+-]/.test(result)); // reject -, +
49
+ cb(result);
38
50
  }
39
51
 
40
52
  function DeHashIt(txtHashed, iteration = 10000, len = 10, cb) {
@@ -43,7 +55,7 @@ function DeHashIt(txtHashed, iteration = 10000, len = 10, cb) {
43
55
  if(err) {
44
56
  cb(err, null);
45
57
  } else {
46
- const crypIt = new Cryptr(secret.toString().concat(app_key.toString()), { encoding: "base64url", pbkdf2Iterations: iteration, saltLength: len, });
58
+ const crypIt = new Cryptr(secret.toString().concat(app_key.toString()), { encoding: "base64", pbkdf2Iterations: iteration, saltLength: len, });
47
59
  let decryped = crypIt.decrypt(txtHashed);
48
60
  cb(false, decryped.concat(md5(secret).toString()));
49
61
  }
@@ -1,34 +1,60 @@
1
- function findPassportPk(pool_base, pool, passportTable, passportConfigField, cb) {
1
+ async function findPassportPk(pool_base, pool, passportTable, passportConfigField, cb) {
2
2
  try {
3
- if(passportConfigField.length) {
4
- cb(null, passportConfigField);
5
- } else {
6
- if(pool_base == "basic") {
7
- // pool base is Basic
8
- pool.query("SHOW KEYS FROM " + passportTable + " WHERE Key_name = 'PRIMARY'", (err, pk) => {
9
- if(err) {
10
- throw "Authentication table: " + err;
3
+ let finalPassportField = [];
4
+ // Push and Replace it
5
+ const pushOrReplace = (arr, value) => {
6
+ arr = arr.filter(v => !value.includes(v));
7
+ arr = [...value, ...arr];
8
+ return arr;
9
+ }
10
+ // Check pool engine
11
+ if(pool_base == "basic") {
12
+ // pool base is Basic
13
+ pool.query("SHOW KEYS FROM " + passportTable + " WHERE Key_name = 'PRIMARY'", (err, pk) => {
14
+ if(err) {
15
+ throw "Authentication table: " + err;
16
+ } else {
17
+ if(passportConfigField.length) {
18
+ finalPassportField = pushOrReplace(passportConfigField, [pk[0].Column_name]);
19
+ cb(null, finalPassportField);
11
20
  } else {
12
21
  cb(null, [pk[0].Column_name]);
13
22
  }
14
- });
15
- } else if (pool_base == "sequelize") {
16
- // pool base is Sequelize
17
- pool.query("SHOW KEYS FROM " + passportTable + " WHERE Key_name = 'PRIMARY'", { type: QueryTypes.SELECT }).then((pk) => {
18
- cb(null, [pk[0].Column_name]);
19
- }).catch((err) => {
20
- throw "Authentication table: " + err;
21
- });
22
- } else {
23
- throw "The Base pool error. UNKNOWN pool_base = '"+ pool_base +"'";
23
+ }
24
+ });
25
+ } else if (pool_base == "sequelize") {
26
+ // pool base is Sequelize
27
+ // Find table primaryKey
28
+ try {
29
+ const tableInfo = await pool.getQueryInterface().describeTable(String(passportTable));
30
+ const primaryKeys = Object.entries(tableInfo).filter(([columnName, columnInfo]) => columnInfo.primaryKey).map(([columnName]) => columnName);
31
+ if(primaryKeys.length) {
32
+ if(passportConfigField.length) {
33
+ finalPassportField = pushOrReplace(passportConfigField, primaryKeys);
34
+ cb(null, finalPassportField);
35
+ } else {
36
+ cb(null, primaryKeys);
37
+ }
38
+ } else {
39
+ if(passportConfigField.length) {
40
+ finalPassportField = pushOrReplace(passportConfigField, [Object.keys(tableInfo)[0]]);
41
+ cb(null, finalPassportField);
42
+ } else {
43
+ cb(null, [Object.keys(tableInfo)[0]]);
44
+ }
45
+ }
46
+ } catch (error) {
47
+ throw `Query Interface ${error}`;
24
48
  }
49
+ } else {
50
+ throw "The Base pool error. UNKNOWN pool_base = '"+ pool_base +"'";
25
51
  }
26
52
  } catch (error) {
27
53
  cb(error, null);
28
54
  }
29
55
  }
30
56
 
31
- function checkAuthFields(pool_base, pool, passportTable, passportConfigField, cb) {
57
+ async function checkAuthFields(pool_base, pool, passportTable, passportConfigField, cb) {
32
58
  try {
33
59
  if(passportConfigField.length) {
34
60
  if(pool_base == "basic") {
@@ -42,18 +68,36 @@ function checkAuthFields(pool_base, pool, passportTable, passportConfigField, cb
42
68
  });
43
69
  } else if (pool_base == "sequelize") {
44
70
  // pool base is Sequelize
45
- pool.query("SELECT "+ passportConfigField.join(",") +" FROM " + passportTable + " LIMIT 1", { type: QueryTypes.SELECT }).then((result) => {
46
- cb(null, [result]);
47
- }).catch((err) => {
48
- cb(`Authentication table: '${passportTable}' ${err}`, null);
49
- });
71
+ // Check assing fields exists
72
+ const checkColumnsExist = async (tableName, fields = []) => {
73
+ const queryInterface = pool.getQueryInterface();
74
+ try {
75
+ const tableDescription = await queryInterface.describeTable(tableName);
76
+ const result = {};
77
+ for (const column of fields) {
78
+ result[column] = tableDescription.hasOwnProperty(column);
79
+ }
80
+ return result;
81
+ } catch (error) {
82
+ throw `Query Interface ${error}`;
83
+ }
84
+ }
85
+ const openFields = await checkColumnsExist(passportTable, passportConfigField);
86
+ const assignFieldsIsWhitelist = Object.values(openFields).includes(false) ? false : true;
87
+ if(assignFieldsIsWhitelist) {
88
+ cb(null, openFields);
89
+ } else {
90
+ cb(`Authentication table fields error: '${passportTable}' => [${passportConfigField}]`, null);
91
+ }
50
92
  } else {
51
93
  cb("The Base pool error. UNKNOWN pool_base = '"+ pool_base +"'", null);
52
94
  }
95
+ } else {
96
+ cb(null, []);
53
97
  }
54
98
  } catch (error) {
55
99
  cb(error, null);
56
100
  }
57
101
  }
58
102
 
59
- module.exports = { findPassportPk, checkAuthFields }
103
+ module.exports = { findPassportPk, checkAuthFields };
@@ -164,9 +164,11 @@ init = async (jsfiles) => {
164
164
  Promise.all([testConnectToDB]).then(async (x) => {
165
165
  if (x[0]) {
166
166
  await (pool_base == "basic" ? new Promise((resolve) => resolve(mySqlDbConnect.connect())) : new Promise((resolve) => resolve(SequelizeDbConnect.connect())));
167
- await authPassport.init().then(async (x) => {
168
- if (x[0]) {
169
- throw x[0];
167
+ await authPassport.init().then(async (p) => {
168
+ if (p[0]) {
169
+ console.log("\n Init failed ", p[0]);
170
+ return;
171
+ //throw p[0];
170
172
  } else {
171
173
  await new Promise((resolve) => resolve(fileWalk.fileWalk(jsfiles)));
172
174
  await (pool_base == "basic" ? new Promise((resolve) => resolve()) : new Promise((resolve) => resolve(Base())));
@@ -176,6 +178,9 @@ init = async (jsfiles) => {
176
178
  });
177
179
  });
178
180
  }
181
+ }).catch((err) => {
182
+ console.log(" Catch init failed ", err);
183
+ throw err;
179
184
  });
180
185
  }
181
186
  });
@@ -1,8 +1,9 @@
1
1
  const passport = require("passport");
2
2
 
3
3
  const checkRoleMiddleware = (options) => {
4
- return function (req, res, next) {
4
+ return (req, res, next) => {
5
5
  if(!Array.isArray(options)) {
6
+ // Perfectly with options is not type Array
6
7
  return next();
7
8
  } else {
8
9
  passport.authenticate("jwt", {
@@ -10,7 +11,7 @@ const checkRoleMiddleware = (options) => {
10
11
  }, (err, user, info) => {
11
12
  // error check
12
13
  if (err) {
13
- console.log(err, info);
14
+ //console.log(err, info);
14
15
  return res.status(403).json({
15
16
  code: 403,
16
17
  status: "FORBIDDEN",
@@ -20,49 +21,66 @@ const checkRoleMiddleware = (options) => {
20
21
  },
21
22
  });
22
23
  } else {
23
- let isPerfectly = true;
24
- options.forEach((element, key) => {
25
- let checkVal = Object.values(element).flat();
26
- let checkKey = Object.keys(element);
27
- if(user && user[checkKey]) {
28
- if(checkVal.includes(user[checkKey])) {
29
- if(options.length -1 === key) {
30
- if(isPerfectly) {
31
- // Perfectly
32
- return next();
33
- }
34
- }
35
- } else {
36
- if(isPerfectly) {
37
- res.status(403).json({
38
- code: 403,
39
- status: "FORBIDDEN",
40
- message: "Forbidden: Insufficient role",
41
- });
42
- }
43
- isPerfectly = false;
44
- }
24
+ if(!options.length) {
25
+ // Perfectly with no options
26
+ return next();
27
+ } else {
28
+ const allowed = options.some(rule => {
29
+ Object.entries(rule).every(([key, condition]) => {
30
+ return matchCondition(user?.[key], condition, user);
31
+ })
32
+ });
33
+ if (allowed) {
34
+ return next();
45
35
  } else {
46
- if(isPerfectly) {
47
- res.status(403).json({
48
- code: 403,
49
- status: "FORBIDDEN",
50
- message: `No ${checkKey} assigned to token.`,
51
- });
52
- }
53
- isPerfectly = false;
36
+ res.status(403).json({
37
+ code: 403,
38
+ status: "FORBIDDEN",
39
+ message: "Forbidden: Insufficient role",
40
+ info: {
41
+ status: "ROLE_NOT_ALLOWED",
42
+ error: "Insufficient role or User token does not have sufficient role.",
43
+ },
44
+ });
54
45
  }
55
- });
46
+ }
56
47
  }
57
48
  })(req, res, next);
58
49
  }
59
50
  }
60
51
  }
61
52
 
53
+ const operators = {
54
+ $eq: (userValue, expected) => userValue === expected,
55
+ $ne: (userValue, expected) => userValue !== expected,
56
+ $in: (userValue, expected) => Array.isArray(expected) && expected.includes(userValue),
57
+ $not: (userValue, expected) => Array.isArray(expected) && !expected.includes(userValue),
58
+ $regex: (userValue, expected) =>
59
+ typeof userValue === 'string' && expected instanceof RegExp
60
+ ? expected.test(userValue)
61
+ : false,
62
+ $fn: (userValue, fn, user) => typeof fn === 'function' && fn(userValue, user),
63
+ };
64
+
65
+ const matchCondition = (userValue, condition, user) => {
66
+ // primitive -> eq
67
+ if (typeof condition !== 'object' || condition instanceof RegExp || Array.isArray(condition)) {
68
+ return Array.isArray(condition)
69
+ ? operators.$in(userValue, condition)
70
+ : operators.$eq(userValue, condition);
71
+ }
72
+ // operator object
73
+ return Object.entries(condition).every(([op, expected]) => {
74
+ const handler = operators[op];
75
+ if (!handler) return false;
76
+ return handler(userValue, expected, user);
77
+ });
78
+ };
79
+
62
80
  const checkRoleMiddlewareWithDefaultProject = (options) => {
63
81
  return function (req, res, next) {
64
82
  return checkRoleMiddleware(options)(req, res, next);
65
83
  }
66
84
  }
67
85
 
68
- module.exports = { checkRoleMiddleware, checkRoleMiddlewareWithDefaultProject }
86
+ module.exports = { checkRoleMiddleware, checkRoleMiddlewareWithDefaultProject };
@@ -14,12 +14,13 @@ function avg(req, res, next) {
14
14
  });
15
15
  // promise all
16
16
  Promise.all([checkPassport]).then((final) => {
17
- let item = final[0];
18
- let passport_config = item[1];
19
17
  /**
20
18
  * item[0] : Boolean = passport file found.
21
- * item[1] : Object = passport object.
19
+ * item[1] : Object = passport object. (for check on/off)
22
20
  */
21
+ let item = final[0];
22
+ let passport_config = item[1];
23
+ // check passport file exists ?, when not exists go to next
23
24
  if(item[0]) {
24
25
  if ((passport_config.model.guard.advanced_guard) ? passport_config.model.guard.advanced_guard.allow : false) {
25
26
  let advanced_guard_entity = req.headers[passport_config.model.guard.advanced_guard.entity || "timing"];
@@ -47,7 +48,7 @@ function avg(req, res, next) {
47
48
  message: "Bad request.",
48
49
  info: {
49
50
  status: "BAD_VALUE",
50
- message: "Bad with wrong Advance guard."
51
+ message: "Bad with wrong Advance guard key."
51
52
  },
52
53
  });
53
54
  }
@@ -3,8 +3,6 @@ const fs = require("fs");
3
3
  const passport_config_file = "/passport.config.js";
4
4
  const auth = require("../auth/Credentials");
5
5
  const { TwoFactor } = require("../helpers/2fa");
6
- const { avgDeHashIt } = require(__dirname + "/../helpers/math");
7
- const moment = require("moment");
8
6
 
9
7
  module.exports = {
10
8
  expressStart() {