beech-api 3.7.23 → 3.8.0-beta.1-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.
- package/README.md +484 -127
- package/index.js +2 -2
- package/package.json +8 -1
- package/packages/cli/beech +2 -2
- package/packages/cli/bin/beech-app.js +10 -8
- package/packages/cli/bin/beech-service.js +1 -1
- package/packages/cli/core/auth/Credentials.js +139 -89
- package/packages/cli/core/auth/Passport.js +264 -164
- package/packages/cli/core/auth/_Request.js +1 -1
- package/packages/cli/core/configure/app.config-basic.js +2 -2
- package/packages/cli/core/configure/app.config-sequelize.js +2 -2
- package/packages/cli/core/configure/beech.config.js +1 -0
- package/packages/cli/core/configure/passport.config.js +33 -13
- package/packages/cli/core/databases/sequelize.js +3 -0
- package/packages/cli/core/databases/test.js +5 -3
- package/packages/cli/core/generator/_endpoints +5 -9
- package/packages/cli/core/generator/_endpoints_basic +11 -8
- package/packages/cli/core/generator/_help +1 -1
- package/packages/cli/core/generator/_models +5 -4
- package/packages/cli/core/generator/_models_basic +2 -2
- package/packages/cli/core/generator/_package +5 -1
- package/packages/cli/core/generator/{_add-on → _scheduler} +1 -1
- package/packages/cli/core/generator/_spec +15 -10
- package/packages/cli/core/generator/index.js +19 -44
- package/packages/cli/core/helpers/2fa.js +85 -0
- package/packages/cli/core/helpers/math.js +55 -7
- package/packages/cli/core/helpers/poolEntity.js +29 -1
- package/packages/cli/core/index.js +65 -34
- package/packages/cli/core/middleware/express/duplicateRequest.js +12 -0
- package/packages/cli/core/middleware/express/jwtCheckAllow.js +68 -0
- package/packages/cli/core/middleware/express/rateLimit.js +17 -0
- package/packages/cli/core/middleware/express/slowDown.js +2 -0
- package/packages/cli/core/middleware/index.js +6 -0
- package/packages/cli/core/middleware/origin/guard/advance.js +74 -0
- package/packages/cli/core/{origin → middleware/origin}/whitelist/cors.js +15 -12
- package/packages/cli/core/services/http.express.js +116 -72
- package/packages/lib/index.js +3 -1
- package/packages/lib/src/endpoint.js +523 -89
- package/packages/lib/src/guard.js +61 -0
- package/packages/lib/src/schema.js +57 -26
- package/packages/lib/src/specificExpress.js +7 -0
- package/packages/lib/src/user.js +94 -18
- package/packages/cli/core/origin/index.js +0 -2
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
global.appRoot = require("app-root-path");
|
|
2
|
+
const moment = require("moment");
|
|
2
3
|
const { performance } = require("perf_hooks");
|
|
3
4
|
const moduleAlias = require("module-alias");
|
|
4
5
|
moduleAlias.addAlias("@", appRoot + "/src");
|
|
5
6
|
const _express_ = require("express");
|
|
6
7
|
global._app_ = _express_();
|
|
8
|
+
// Compression
|
|
9
|
+
const compression = require("compression");
|
|
10
|
+
_app_.use(compression());
|
|
11
|
+
// Helmet
|
|
12
|
+
const helmet = require("helmet");
|
|
13
|
+
_app_.use(helmet());
|
|
14
|
+
// CORS
|
|
7
15
|
const cors = require("cors");
|
|
8
16
|
global.endpoint = _express_.Router();
|
|
9
17
|
const cookieParser = require("cookie-parser");
|
|
@@ -15,9 +23,15 @@ const globalVariable = require(appRoot + "/global.config.js");
|
|
|
15
23
|
globalVariable.init();
|
|
16
24
|
// Local environments
|
|
17
25
|
global._config_ = require(appRoot + "/app.config");
|
|
26
|
+
const _beech_ = require(appRoot + "/beech.config.js").defineConfig;
|
|
27
|
+
global._publicPath_ = _beech_.base;
|
|
18
28
|
const mySqlDbConnect = require("./databases/mysql");
|
|
19
29
|
const SequelizeDbConnect = require("./databases/sequelize");
|
|
20
|
-
//
|
|
30
|
+
// Rate Request middleware
|
|
31
|
+
const { Limiter, Duplicater } = require("./middleware/index");
|
|
32
|
+
endpoint.use(Limiter);
|
|
33
|
+
endpoint.use(Duplicater);
|
|
34
|
+
// Database test
|
|
21
35
|
const {
|
|
22
36
|
testConnectInProcess,
|
|
23
37
|
filterDbIsTrue,
|
|
@@ -28,36 +42,63 @@ const { QueryTypes, DataTypes, Op } = require("sequelize");
|
|
|
28
42
|
global.QueryTypes = QueryTypes;
|
|
29
43
|
global.DataTypes = DataTypes;
|
|
30
44
|
global.Op = Op;
|
|
31
|
-
//
|
|
45
|
+
// Allow whitelist cors
|
|
46
|
+
const { whitelist, sign, avg } = require("./middleware/index");
|
|
32
47
|
_app_.use(cors({ origin: true, credentials: true }));
|
|
33
|
-
|
|
48
|
+
_app_.use((req, res, next) => {
|
|
49
|
+
whitelist(async (lists, originSensitive) => {
|
|
50
|
+
sign(req, res, lists, originSensitive, (err) => {
|
|
51
|
+
if (!err) {
|
|
52
|
+
next();
|
|
53
|
+
} else {
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
34
59
|
// View engine
|
|
35
60
|
_app_.use(bodyParser.json());
|
|
36
61
|
_app_.use(bodyParser.urlencoded({ extended: true }));
|
|
37
62
|
_app_.use(methodOverride());
|
|
38
63
|
_app_.use(cookieParser());
|
|
39
|
-
_app_.use(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})
|
|
45
|
-
);
|
|
64
|
+
_app_.use(expressSession({
|
|
65
|
+
secret: "surprise you mother f*cker",
|
|
66
|
+
resave: true,
|
|
67
|
+
saveUninitialized: true,
|
|
68
|
+
}));
|
|
46
69
|
_app_.use(expressValidator());
|
|
47
70
|
// Dev. activity
|
|
71
|
+
global._requestTime_ = moment(new Date()).format("YYYY-MM-DD HH:mm:ss");
|
|
48
72
|
_app_.use((req, res, next) => {
|
|
49
|
-
console.log(
|
|
50
|
-
|
|
51
|
-
res.on(
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
console.log(`[${_requestTime_}] : Request ${req.method} ${req.originalUrl}`);
|
|
74
|
+
const t0 = performance.now();
|
|
75
|
+
res.on('finish', () => {
|
|
76
|
+
const responseTime = moment(new Date()).format("YYYY-MM-DD HH:mm:ss");
|
|
77
|
+
const t1 = performance.now();
|
|
78
|
+
const duration = (t1 - t0).toFixed(0);
|
|
79
|
+
console.log(`[${responseTime}] : Response ${res.statusCode} (${duration}ms)`);
|
|
54
80
|
});
|
|
55
81
|
next();
|
|
56
82
|
});
|
|
57
|
-
//
|
|
83
|
+
// Check Syntax error.
|
|
84
|
+
_app_.use((error, req, res, next) => {
|
|
85
|
+
if (error instanceof SyntaxError) {
|
|
86
|
+
res.status(400).json({
|
|
87
|
+
...error,
|
|
88
|
+
status: "BAD_REQUEST",
|
|
89
|
+
message: "Bad Request.",
|
|
90
|
+
body: error.body,
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
next();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// Advance Guard
|
|
97
|
+
_app_.use(avg);
|
|
98
|
+
// Engine import
|
|
58
99
|
const httpExpress = require("./services/http.express");
|
|
59
100
|
const fileWalk = require("./file-walk/file-walk");
|
|
60
|
-
//
|
|
101
|
+
// Passport initialization
|
|
61
102
|
const authPassport = require("./auth/Passport");
|
|
62
103
|
const passport = require("passport");
|
|
63
104
|
_app_.use(passport.initialize());
|
|
@@ -68,6 +109,8 @@ passport.serializeUser((user, done) => {
|
|
|
68
109
|
passport.deserializeUser((user, done) => {
|
|
69
110
|
done(null, user);
|
|
70
111
|
});
|
|
112
|
+
// Endpoint magic
|
|
113
|
+
const { Base } = require("../../lib/index");
|
|
71
114
|
// Read folder in ./src/endpoints/*
|
|
72
115
|
const walk = require("walk");
|
|
73
116
|
let jsfiles = [];
|
|
@@ -120,24 +163,13 @@ init = async (jsfiles) => {
|
|
|
120
163
|
});
|
|
121
164
|
Promise.all([testConnectToDB]).then(async (x) => {
|
|
122
165
|
if (x[0]) {
|
|
123
|
-
await (pool_base == "basic"
|
|
124
|
-
? new Promise((resolve) => resolve(mySqlDbConnect.connect()))
|
|
125
|
-
: new Promise((resolve) => resolve(SequelizeDbConnect.connect())));
|
|
126
|
-
await whitelist(async (lists, originSensitive) => {
|
|
127
|
-
await _app_.use((req, res, next) => {
|
|
128
|
-
sign(req, res, lists, originSensitive, (err) => {
|
|
129
|
-
if (!err) {
|
|
130
|
-
next();
|
|
131
|
-
} else {
|
|
132
|
-
throw err;
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
});
|
|
166
|
+
await (pool_base == "basic" ? new Promise((resolve) => resolve(mySqlDbConnect.connect())) : new Promise((resolve) => resolve(SequelizeDbConnect.connect())));
|
|
136
167
|
await authPassport.init().then(async (x) => {
|
|
137
168
|
if (x[0]) {
|
|
138
169
|
throw x[0];
|
|
139
170
|
} else {
|
|
140
171
|
await new Promise((resolve) => resolve(fileWalk.fileWalk(jsfiles)));
|
|
172
|
+
await (pool_base == "basic" ? new Promise((resolve) => resolve()) : new Promise((resolve) => resolve(Base())));
|
|
141
173
|
await new Promise((resolve) => {
|
|
142
174
|
httpExpress.expressStart().then((expss) => {
|
|
143
175
|
resolve(expss);
|
|
@@ -145,7 +177,6 @@ init = async (jsfiles) => {
|
|
|
145
177
|
});
|
|
146
178
|
}
|
|
147
179
|
});
|
|
148
|
-
});
|
|
149
180
|
}
|
|
150
181
|
});
|
|
151
182
|
} catch (error) {
|
|
@@ -153,5 +184,5 @@ init = async (jsfiles) => {
|
|
|
153
184
|
throw error;
|
|
154
185
|
}
|
|
155
186
|
};
|
|
156
|
-
//
|
|
157
|
-
_app_.use(endpoint);
|
|
187
|
+
// Use router
|
|
188
|
+
_app_.use(_publicPath_, endpoint);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const _beech_ = require(appRoot + "/beech.config.js");
|
|
2
|
+
const { duplicateRequest } = require("express-duplicate-request");
|
|
3
|
+
const nextDuplicater = (req, res, next) => {
|
|
4
|
+
next();
|
|
5
|
+
};
|
|
6
|
+
let configure = {
|
|
7
|
+
expiration: _beech_.defineConfig.server.duplicateRequest ? _beech_.defineConfig.server.duplicateRequest.expiration : 0,
|
|
8
|
+
};
|
|
9
|
+
configure = { ...configure, ..._beech_.defineConfig.server.duplicateRequest };
|
|
10
|
+
const Duplicater = configure.expiration ? duplicateRequest(configure) : nextDuplicater;
|
|
11
|
+
|
|
12
|
+
module.exports = { Duplicater, duplicateRequest };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const passport = require("passport");
|
|
2
|
+
|
|
3
|
+
const checkRoleMiddleware = (options) => {
|
|
4
|
+
return function (req, res, next) {
|
|
5
|
+
if(!Array.isArray(options)) {
|
|
6
|
+
return next();
|
|
7
|
+
} else {
|
|
8
|
+
passport.authenticate("jwt", {
|
|
9
|
+
session: false,
|
|
10
|
+
}, (err, user, info) => {
|
|
11
|
+
// error check
|
|
12
|
+
if (err) {
|
|
13
|
+
console.log(err, info);
|
|
14
|
+
return res.status(403).json({
|
|
15
|
+
code: 403,
|
|
16
|
+
status: "FORBIDDEN",
|
|
17
|
+
message: "Forbidden: Insufficient role",
|
|
18
|
+
info: {
|
|
19
|
+
error: err,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
} 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
|
+
}
|
|
45
|
+
} 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;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
})(req, res, next);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const checkRoleMiddlewareWithDefaultProject = (options) => {
|
|
63
|
+
return function (req, res, next) {
|
|
64
|
+
return checkRoleMiddleware(options)(req, res, next);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = { checkRoleMiddleware, checkRoleMiddlewareWithDefaultProject }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const _beech_ = require(appRoot + "/beech.config.js");
|
|
2
|
+
const rateLimit = require("express-rate-limit");
|
|
3
|
+
const tooManyMsg = {
|
|
4
|
+
code: 429,
|
|
5
|
+
status: "TOO_MANY_REQUEST",
|
|
6
|
+
message: "Too Many Requests.",
|
|
7
|
+
};
|
|
8
|
+
let configure = {
|
|
9
|
+
windowMs: (_beech_.defineConfig.server.rateLimit) ? _beech_.defineConfig.server.rateLimit.windowMs : 0,
|
|
10
|
+
standardHeaders: (_beech_.defineConfig.server.rateLimit) ? (_beech_.defineConfig.server.rateLimit.standardHeaders || "draft-7") : "draft-7",
|
|
11
|
+
legacyHeaders: (_beech_.defineConfig.server.rateLimit) ? (_beech_.defineConfig.server.rateLimit.legacyHeaders || false) : false,
|
|
12
|
+
message: (_beech_.defineConfig.server.rateLimit) ? (_beech_.defineConfig.server.rateLimit.message || tooManyMsg) : tooManyMsg,
|
|
13
|
+
};
|
|
14
|
+
configure = { ...configure, ..._beech_.defineConfig.server.rateLimit };
|
|
15
|
+
const Limiter = rateLimit(configure);
|
|
16
|
+
|
|
17
|
+
module.exports = { Limiter, rateLimit };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
const { whitelist, sign } = require("./origin/whitelist/cors");
|
|
2
|
+
const { avg } = require("./origin/guard/advance");
|
|
3
|
+
const { Limiter } = require("./express/rateLimit");
|
|
4
|
+
const { Duplicater } = require("./express/duplicateRequest");
|
|
5
|
+
|
|
6
|
+
module.exports = { whitelist, sign, Limiter, Duplicater, avg };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const passport_config_file = "/passport.config.js";
|
|
3
|
+
const { avgDeHashIt } = require(__dirname + "/../../../helpers/math");
|
|
4
|
+
const moment = require("moment");
|
|
5
|
+
|
|
6
|
+
function avg(req, res, next) {
|
|
7
|
+
// check passport file ?
|
|
8
|
+
const checkPassport = new Promise((resolve) => {
|
|
9
|
+
if (fs.existsSync(appRoot + "/passport.config.js")) {
|
|
10
|
+
resolve([true, require(appRoot + passport_config_file)]);
|
|
11
|
+
} else {
|
|
12
|
+
resolve([false, null]);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
// promise all
|
|
16
|
+
Promise.all([checkPassport]).then((final) => {
|
|
17
|
+
let item = final[0];
|
|
18
|
+
let passport_config = item[1];
|
|
19
|
+
/**
|
|
20
|
+
* item[0] : Boolean = passport file found.
|
|
21
|
+
* item[1] : Object = passport object.
|
|
22
|
+
*/
|
|
23
|
+
if(item[0]) {
|
|
24
|
+
if ((passport_config.model.guard.advanced_guard) ? passport_config.model.guard.advanced_guard.allow : false) {
|
|
25
|
+
let advanced_guard_entity = req.headers[passport_config.model.guard.advanced_guard.entity || "timing"];
|
|
26
|
+
if (advanced_guard_entity) {
|
|
27
|
+
if(advanced_guard_entity.length > 60) {
|
|
28
|
+
//logic check advanced guard
|
|
29
|
+
avgDeHashIt(advanced_guard_entity, (err, unixTime) => {
|
|
30
|
+
if (err) {
|
|
31
|
+
res.status(502).json({ code: 502, status: "BAD_GATEWAY", message: String(err) });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// prepare date & check it.
|
|
35
|
+
let unixTimeNow = moment(new Date()).unix();
|
|
36
|
+
let unixTiming = moment(new Date(unixTime * 1000)).add((passport_config.model.guard.advanced_guard.time_expired.minutes || 0), "minutes").add((passport_config.model.guard.advanced_guard.time_expired.seconds || 0), "seconds").unix();
|
|
37
|
+
if((String(unixTimeNow).length == String(unixTiming).length) && unixTimeNow < unixTiming) {
|
|
38
|
+
next();
|
|
39
|
+
} else {
|
|
40
|
+
res.status(408).json({ code: 408 , status: "REQUEST_TIMEOUT", message: "Request Timeout." });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
res.status(400).json({
|
|
45
|
+
code: 400,
|
|
46
|
+
status: 'BAD_REQUEST',
|
|
47
|
+
message: "Bad request.",
|
|
48
|
+
info: {
|
|
49
|
+
status: "BAD_VALUE",
|
|
50
|
+
message: "Bad with wrong Advance guard."
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
res.status(400).json({
|
|
56
|
+
code: 400,
|
|
57
|
+
status: 'BAD_REQUEST',
|
|
58
|
+
message: "Bad request.",
|
|
59
|
+
info: {
|
|
60
|
+
status: "BAD_ENTITY",
|
|
61
|
+
message: "Bad Advanced guard Entity."
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
next();
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
next();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = { avg };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
function whitelist(cb) {
|
|
4
4
|
var whitelists = [];
|
|
5
5
|
const getWhitelists = new Promise((resolve) => {
|
|
@@ -37,8 +37,8 @@ function sign(req, res, whitelist, originSensitive, cb) {
|
|
|
37
37
|
const origin = req.headers.origin;
|
|
38
38
|
let doYouSignSomeOrigin = false;
|
|
39
39
|
//var host = req.get("host");
|
|
40
|
-
console.log(
|
|
41
|
-
|
|
40
|
+
console.log(`[${_requestTime_}] : From origin: ${origin || 'http://localhost'}`);
|
|
41
|
+
// check whitelist length ?
|
|
42
42
|
if (whitelist.length > 0) {
|
|
43
43
|
whitelist.forEach((val, k) => {
|
|
44
44
|
if (origin) {
|
|
@@ -53,21 +53,19 @@ function sign(req, res, whitelist, originSensitive, cb) {
|
|
|
53
53
|
}
|
|
54
54
|
if (whitelist.length == k + 1) {
|
|
55
55
|
if (!doYouSignSomeOrigin) {
|
|
56
|
-
res
|
|
57
|
-
"Access-Control-Allow-Origin",
|
|
58
|
-
"http://localhost:" + _config_.main_config.app_port
|
|
59
|
-
);
|
|
56
|
+
setLocalHeader(res);
|
|
60
57
|
}
|
|
61
58
|
}
|
|
62
59
|
});
|
|
63
60
|
} else {
|
|
64
|
-
|
|
61
|
+
if(origin) {
|
|
62
|
+
res.setHeader("Access-Control-Allow-Origin", origin); // add origin when not sign origin: []|["*"]
|
|
63
|
+
} else {
|
|
64
|
+
setLocalHeader(res);
|
|
65
|
+
}
|
|
65
66
|
}
|
|
66
67
|
// Request methods you wish to allow
|
|
67
|
-
res.setHeader(
|
|
68
|
-
"Access-Control-Allow-Methods",
|
|
69
|
-
"GET, POST, OPTIONS, PUT, PATCH, DELETE"
|
|
70
|
-
);
|
|
68
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
|
|
71
69
|
// Request headers you wish to allow
|
|
72
70
|
res.setHeader(
|
|
73
71
|
"Access-Control-Allow-Headers",
|
|
@@ -88,4 +86,9 @@ function sign(req, res, whitelist, originSensitive, cb) {
|
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
88
|
|
|
89
|
+
function setLocalHeader(res) {
|
|
90
|
+
res.setHeader("Access-Control-Allow-Origin", "http://localhost:" + _config_.main_config.app_port);
|
|
91
|
+
res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:" + _config_.main_config.app_port);
|
|
92
|
+
}
|
|
93
|
+
|
|
91
94
|
module.exports = { whitelist, sign };
|