beech-api 3.2.11 → 3.4.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.
@@ -78,9 +78,26 @@ class Generator {
78
78
  resolve("\n Faltal  commnad it's not available.");
79
79
  }
80
80
  }
81
- } else if (this.option == 'kill') {
82
- /* require('./app')
83
- console.log(_SERVER) */
81
+ } else if (this.option == 'passport') {
82
+ if (this.argument == "init") {
83
+ this.makePassportInit()
84
+ .then(make => resolve(make))
85
+ .catch(err => reject(err));
86
+ } else {
87
+ resolve("\n Warning  Using `passport init` for initiate passport-jwt.");
88
+ }
89
+ } else if (this.option == "key:generate") {
90
+ this.generateKeyConfigFile()
91
+ .then(resGenKey => resolve(resGenKey))
92
+ .catch(err => reject(err));;
93
+ } else if (this.option == "add-on") {
94
+ if (this.argument == "init") {
95
+ this.makeAddOnInit()
96
+ .then(make => resolve(make))
97
+ .catch(err => reject(err));
98
+ } else {
99
+ resolve("\n Warning  Using `add-on init` for initiate add-on.");
100
+ }
84
101
  } else {
85
102
  resolve("\n Faltal  commnad it's not available.");
86
103
  }
@@ -201,7 +218,7 @@ class Generator {
201
218
  });
202
219
  }
203
220
 
204
- async makeFolder(path) {
221
+ makeFolder(path) {
205
222
  /**
206
223
  * @param path path to make
207
224
  *
@@ -224,7 +241,45 @@ class Generator {
224
241
  });
225
242
  }
226
243
 
227
- async copy(path, to) {
244
+ makePassportInit() {
245
+ return new Promise((resolve, reject) => {
246
+ try {
247
+ let passport_config_file = __dirname + '/../configure/passport.config.js';
248
+ let passport_config_paste_point = "./passport.config.js";
249
+ if (!this.fs.existsSync(passport_config_paste_point)) {
250
+ this.copy(passport_config_file, passport_config_paste_point)
251
+ .then(resolve("\n Passed  The `passport-jwt` is initialized."))
252
+ .catch(err => console.log(err));
253
+ } else {
254
+ resolve("\n Warning  The `passport-jwt` already is initialized.");
255
+ }
256
+ } catch (error) {
257
+ reject(error);
258
+ }
259
+ });
260
+ }
261
+
262
+ makeAddOnInit() {
263
+ return new Promise((resolve, reject) => {
264
+ try {
265
+ let tmpEndpointsPath = __dirname + '/add-on';
266
+ let add_on_paste_point = "Add-on.js";
267
+ let folder_add_on = "./src/";
268
+ if (!this.fs.existsSync(folder_add_on + add_on_paste_point)) {
269
+ this.makeFolder(folder_add_on)
270
+ .then(this.copy.bind(this, tmpEndpointsPath, folder_add_on + add_on_paste_point))
271
+ .then(resolve("\n Passed  The `add-on` is initialized."))
272
+ .catch(err => console.log(err));
273
+ } else {
274
+ resolve("\n Warning  The `add-on` already is initialized.");
275
+ }
276
+ } catch (error) {
277
+ reject(error);
278
+ }
279
+ });
280
+ }
281
+
282
+ copy(path, to) {
228
283
  /**
229
284
  * @param path old path file
230
285
  * @param to save to new path file
@@ -248,7 +303,7 @@ class Generator {
248
303
  });
249
304
  }
250
305
 
251
- async contentReplace(pathFile, textCondition) {
306
+ contentReplace(pathFile, textCondition) {
252
307
  return new Promise((resolve, reject) => {
253
308
  try {
254
309
  let endpoint = textCondition.endpoint;
@@ -283,7 +338,7 @@ class Generator {
283
338
  });
284
339
  }
285
340
 
286
- async modelContentReplace(pathFile, textCondition) {
341
+ modelContentReplace(pathFile, textCondition) {
287
342
  return new Promise((resolve, reject) => {
288
343
  try {
289
344
  let modelName = textCondition.modelName;
@@ -312,6 +367,58 @@ class Generator {
312
367
  });
313
368
  }
314
369
 
370
+ appKeyGenerator(length) {
371
+ return new Promise((resolve, reject) => {
372
+ try {
373
+ let md5 = require("md5");
374
+ let secret = require(__dirname + "/../../../lib/salt").salt;
375
+ let result = '';
376
+ let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
377
+ let charactersLength = characters.length;
378
+ for ( var i = 0; i < length; i++ ) {
379
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
380
+ }
381
+ resolve(md5(result + secret));
382
+ } catch (error) {
383
+ reject(error);
384
+ }
385
+ });
386
+ }
387
+
388
+ generateKeyConfigFile() {
389
+ return new Promise((resolve, reject) => {
390
+ try {
391
+ this.fs.readFile("app.config.js", 'utf8', (err, data) => {
392
+ if (err) {
393
+ throw err;
394
+ } else {
395
+ // edit or add property
396
+ let buffer = Buffer.from(data);
397
+ let buf2str = buffer.toString();
398
+ let buf2json = JSON.parse(JSON.stringify(buf2str));
399
+ let buf2eval = eval(buf2json);
400
+ let oldSecret = buf2eval.main_config.app_secret;
401
+ // generate new key secret
402
+ this.appKeyGenerator(8).then(newAppSecret => {
403
+ // content replace
404
+ let text = data.replace(new RegExp(oldSecret, 'g'), newAppSecret);
405
+ // writing the file
406
+ this.fs.writeFile("app.config.js", text, 'utf8', (err) => {
407
+ if (err) {
408
+ throw err;
409
+ } else {
410
+ resolve("\n Passed  App secret it's new generated.");
411
+ }
412
+ });
413
+ });
414
+ }
415
+ });
416
+ } catch (error) {
417
+ reject(error);
418
+ }
419
+ });
420
+ }
421
+
315
422
  help() {
316
423
  return new Promise((resolve, reject) => {
317
424
  try {
@@ -8,23 +8,9 @@
8
8
  "test": "node ./node_modules/jest/bin/jest __tests__ -o --watch --config"
9
9
  },
10
10
  "dependencies": {
11
- "app-root-path": "^3.0.0",
12
- "axios": "^0.18.1",
13
- "beech-api": "^3.2.11",
14
- "cookie-parser": "1.4.3",
15
- "cors": "^2.8.1",
16
- "express": "4.16.3",
17
- "express-validator": "2.21.0",
18
- "fs": "0.0.1-security",
19
- "module-alias": "^2.2.2",
20
- "mysql": "^2.18.1",
21
- "mysql2": "^2.1.0",
22
- "nodemon": "^2.0.2",
23
- "sequelize": "^5.21.6",
24
- "walk": "^2.3.14"
11
+ "beech-api": "^3.2.11"
25
12
  },
26
13
  "devDependencies": {
27
- "jest": "^25.2.7",
28
- "sequelize-cli": "^5.5.1"
14
+ "jest": "^25.2.7"
29
15
  }
30
16
  }
@@ -1,3 +1,4 @@
1
+ const fs = require("fs");
1
2
  const appRoot = require("app-root-path");
2
3
  const moduleAlias = require("module-alias");
3
4
  moduleAlias.addAlias("@", appRoot + "/src");
@@ -8,18 +9,25 @@ global.endpoint = _express_.Router();
8
9
  global._mysql_ = require("mysql");
9
10
  const cookieParser = require("cookie-parser");
10
11
  const bodyParser = require("body-parser");
12
+ const expressSession = require("express-session");
11
13
  const expressValidator = require("express-validator");
12
14
  const globalVariable = require(appRoot + "/global.config.js");
13
15
  globalVariable.init();
14
16
  // Local environments
15
17
  global._config_ = require(appRoot + "/app.config");
16
18
  const dbConnect = require("./databases/mysql.connection");
19
+ dbConnect.mySqlConnection();
17
20
  const httpExpress = require("./services/http.express");
18
21
  const fileWalk = require("./file-walk/file-walk");
19
22
  // View engine
20
23
  _app_.use(bodyParser.json());
21
24
  _app_.use(bodyParser.urlencoded({ extended: true }));
22
25
  _app_.use(cookieParser());
26
+ _app_.use(expressSession({
27
+ secret: 'keyboard cat',
28
+ resave: true,
29
+ saveUninitialized: true
30
+ }));
23
31
  _app_.use(expressValidator());
24
32
  _app_.use(cors({ origin: true, credentials: true }));
25
33
  // Allow Origin
@@ -30,28 +38,41 @@ _app_.all("/", (req, res, next) => {
30
38
  res.header("Content-Type", "application/json; charset=utf-8");
31
39
  next();
32
40
  });
41
+ // passport initialization
42
+ const authPassport = require("./auth/Passport");
43
+ const passport = require("passport");
44
+ _app_.use(passport.initialize());
45
+ _app_.use(passport.session());
46
+ passport.serializeUser((user, done) =>{
47
+ done(null, user);
48
+ });
49
+ passport.deserializeUser((user, done) => {
50
+ done(null, user);
51
+ });
33
52
  // Read folder in ./src/endpoints/*
34
53
  const walk = require("walk");
35
- let jsfiles = []
54
+ let jsfiles = [];
36
55
  let walker = walk.walk(appRoot + "/src/endpoints", { followLinks: false });
37
56
  walker.on("file", (root, stat, next) => {
38
57
  jsfiles.push(root + "/" + stat.name);
58
+ // check add-on file exists ?
59
+ if (fs.existsSync(root + "/../Add-on.js")) {
60
+ if (_config_.addOn) {
61
+ jsfiles.push(root + "/../Add-on.js");
62
+ }
63
+ }
39
64
  next();
40
65
  });
66
+ // Walking
41
67
  walker.on("end", () => {
42
68
  init(jsfiles);
43
69
  });
44
- // define server variable
45
- global._SERVER;
46
70
  // Initialize the application
47
- init = (jsfiles) => {
71
+ init = async (jsfiles) => {
48
72
  try {
49
- httpExpress.expressStart()
50
- .then(dbConnect.mySqlConnection.bind(this))
51
- .then(fileWalk.fileWalk.bind(this, jsfiles))
52
- .catch(error => {
53
- throw error;
54
- });
73
+ await httpExpress.expressStart();
74
+ await authPassport.init();
75
+ await fileWalk.fileWalk(jsfiles);
55
76
  } catch (error) {
56
77
  throw error;
57
78
  }
@@ -1,61 +1,218 @@
1
1
  const appRoot = require("app-root-path");
2
2
  const package = require(appRoot + '/package.json');
3
- // Server start using by Express
4
- exports.expressStart = () => {
5
- return new Promise((resolve, reject) => {
6
- try {
7
- // Create express server
8
- const ExpressServer = _app_.listen(_config_.main_config.app_port, () => {
9
- console.log('\n Passed  Service is started at:\n - Local: http://' + _config_.main_config.app_host + ':' + ExpressServer.address().port, '\n - Network: ' + _config_.main_config.client_host + '\n');
10
- this.badRequest()
11
- .then(this.wrongRequest())
12
- .catch(err => {
13
- throw err;
3
+ const fs = require("fs");
4
+ const passport_config_file = "/passport.config.js";
5
+ const auth = require("../auth/Credentials");
6
+
7
+ module.exports = {
8
+ expressStart() {
9
+ return new Promise((resolve, reject) => {
10
+ try {
11
+ // Create express server
12
+ const ExpressServer = _app_.listen(_config_.main_config.app_port, async () => {
13
+ await console.log('\n Passed  Service is started at:\n - Local: http://' + _config_.main_config.app_host + ':' + ExpressServer.address().port, '\n - Network: ' + _config_.main_config.client_host + '');
14
+ await this.authentication();
15
+ await this.badRequest()
16
+ .then(resolve(ExpressServer))
17
+ .catch(err => {
18
+ reject(err);
19
+ });
20
+ });
21
+ } catch (error) {
22
+ reject(error);
23
+ }
24
+ });
25
+ },
26
+ // Bad request
27
+ badRequest() {
28
+ return new Promise((resolve, reject) => {
29
+ try {
30
+ // base get request
31
+ _app_.get('/', (req, res) => {
32
+ res.status(200).json({
33
+ code: 200,
34
+ status: "SUCCESS",
35
+ message: `Welcome to ${package.name} (version ${package.version})`
14
36
  });
15
- resolve(ExpressServer);
16
- });
17
- } catch (error) {
18
- reject(error);
19
- }
20
- });
21
- }
22
- // Express server get variable
23
- exports.getExpressServer = (serve) => {
24
- return new Promise((resolve, reject) => {
25
- try {
26
- resolve(serve);
27
- } catch (error) {
28
- reject(error);
29
- }
30
- });
31
- }
32
- // Bad request
33
- exports.badRequest = () => {
34
- return new Promise((resolve, reject) => {
37
+ resolve(200);
38
+ });
39
+ // request 404 not found
40
+ _app_.use((req, res, next) => {
41
+ res.status(404).json({
42
+ code: 404,
43
+ status: "error",
44
+ error: "404_NOT_FOUND"
45
+ });
46
+ resolve(404);
47
+ next();
48
+ });
49
+ } catch (error) {
50
+ reject(error);
51
+ }
52
+ });
53
+ },
54
+ // Authentication request
55
+ authentication() {
35
56
  try {
36
- _app_.get('/', (req, res) => {
37
- let data = {};
38
- data.code = 200;
39
- data.message = `Welcome to ${package.name} (version ${package.version})`;
40
- res.json(data);
41
- resolve(data);
57
+ // require jwt & passport
58
+ if (fs.existsSync(appRoot + passport_config_file)) {
59
+ var passport_config = require(appRoot + passport_config_file);
60
+ var jwt = require('jsonwebtoken');
61
+ var passport = require('passport');
62
+ var Beech = require("../../../lib/beech");
63
+ if (!passport_config.jwt_allow) {
64
+ // jwt is false
65
+ console.log(" - JWT: OFF");
66
+ return;
67
+ }
68
+ // jwt is true
69
+ console.log(" - JWT: ON");
70
+ } else {
71
+ return;
72
+ }
73
+ // declare authentication endpoint name
74
+ const auth_endpoint = (passport_config.auth_endpoint) ? (passport_config.auth_endpoint[0] === "/" ? passport_config.auth_endpoint : "/" + passport_config.auth_endpoint) : "/authentication";
75
+ // authentication endpoints
76
+ _app_.post(auth_endpoint, (req, res, next) => {
77
+ passport.authenticate('local', { session: false }, (err, user, opt) => {
78
+ if (err) {
79
+ res.status(502).json({
80
+ code: 502,
81
+ error: 'BAD_GATEWAY',
82
+ message: err
83
+ });
84
+ }
85
+ if (user) {
86
+ const accessToken = jwt.sign(user, passport_config.secret, {
87
+ expiresIn: passport_config.token_expired
88
+ });
89
+ if (passport_config.app_secret_allow) {
90
+ if (req.body.app_secret) {
91
+ if (_config_.main_config.app_secret == req.body.app_secret) {
92
+ res.status(200).json({
93
+ code: 200,
94
+ status: "AUTHORIZED",
95
+ message: "success.",
96
+ user,
97
+ accessToken
98
+ });
99
+ } else {
100
+ res.status(401).json({ code: 401, message: "Unauthorized." });
101
+ }
102
+ } else {
103
+ res.status(422).json({ code: 422, message: "Unprocessable Entity." });
104
+ }
105
+ } else {
106
+ res.status(200).json({
107
+ code: 200,
108
+ status: "AUTHORIZED",
109
+ message: "success.",
110
+ user,
111
+ accessToken
112
+ });
113
+ }
114
+ } else if (opt) {
115
+ res.status(422).json({ code: 422, message: "Unprocessable Entity." });
116
+ } else {
117
+ res.status(401).json({ code: 401, message: "Unauthorized." });
118
+ }
119
+ })(req, res, next);
42
120
  });
43
- } catch (error) {
44
- reject(error);
45
- }
46
- });
47
- }
48
- // Default route if request went wrong
49
- exports.wrongRequest = () => {
50
- return new Promise((resolve, reject) => {
51
- try {
52
- _app_.use((req, res, next) => {
53
- res.status(404).send({ code: 404, message: '404 Not found, cannot request to ' + req.url });
54
- resolve(404);
55
- next();
121
+ // create users endpoints
122
+ _app_.post(auth_endpoint + '/users', (req, res) => {
123
+ Beech.store(req.body, (err, result) => {
124
+ if (err) {
125
+ res.status(500).json({ code: 500, status: "CREATE_FAILED", error: err });
126
+ } else {
127
+ res.status(201).json({ code: 201, status: "CREATE_SUCCESS", result });
128
+ }
129
+ });
130
+ });
131
+ // patch users endpoints
132
+ _app_.patch(auth_endpoint + '/users/:id', auth.credentials, (req, res) => {
133
+ // require some fields with body params
134
+ Beech.update(req.body, req.params.id, (err, result) => {
135
+ if (err) {
136
+ res.status(500).json({ code: 500, status: "UPDATE_FAILED", error: err });
137
+ } else {
138
+ res.status(200).json({ code: 200, status: "UPDATE_SUCCESS", result });
139
+ }
140
+ });
56
141
  });
142
+ /**
143
+ * Google Strategy
144
+ *
145
+ */
146
+ if (passport_config.strategy.google.allow) {
147
+ _app_.get(auth_endpoint + '/google', passport.authenticate('google', {
148
+ scope: [
149
+ 'https://www.googleapis.com/auth/userinfo.email',
150
+ 'https://www.googleapis.com/auth/plus.login'
151
+ ]
152
+ }));
153
+ // google auth callback
154
+ const googleCallback = (passport_config.strategy.google.callback_endpoint) ? (passport_config.strategy.google.callback_endpoint[0] === "/" ? passport_config.strategy.google.callback_endpoint : "/" + passport_config.strategy.google.callback_endpoint) : "/google/callback";
155
+ _app_.get(auth_endpoint + googleCallback, passport.authenticate('google'), (req, res) => {
156
+ if (typeof req.user.user !== 'undefined') {
157
+ // declare user for sign JWT
158
+ let user = JSON.parse(JSON.stringify(req.user.user));
159
+ const accessToken = jwt.sign(user, passport_config.secret, {
160
+ expiresIn: passport_config.token_expired
161
+ });
162
+ // response JWT
163
+ res.status(200).json({
164
+ code: 200,
165
+ status: "AUTHORIZED",
166
+ message: "success.",
167
+ user: req.user,
168
+ accessToken
169
+ });
170
+ } else {
171
+ let condUser = {};
172
+ condUser[(passport_config.strategy.google.google_id_field) ? passport_config.strategy.google.google_id_field : "google_id"] = req.user.google.id;
173
+ Beech.findOne(passport_config.model.table || "users", condUser, (err, result) => {
174
+ if (err) {
175
+ res.status(500).json({
176
+ code: 500,
177
+ status: "INTERNAL_SERVER_ERR",
178
+ message: "Internal server error.",
179
+ error: err
180
+ });
181
+ } else {
182
+ let user = JSON.parse(JSON.stringify(result[0]));
183
+ const accessToken = jwt.sign(user, passport_config.secret, {
184
+ expiresIn: passport_config.token_expired
185
+ });
186
+ // response JWT
187
+ res.status(201).json({
188
+ code: 201,
189
+ status: "AUTHORIZED",
190
+ message: "success.",
191
+ user: {
192
+ google: req.user.google,
193
+ user
194
+ },
195
+ accessToken
196
+ });
197
+ }
198
+ });
199
+ }
200
+ });
201
+ }
202
+ /**
203
+ * Facebook strategy
204
+ *
205
+ */
206
+ if (passport_config.strategy.facebook.allow) {
207
+ _app_.get(auth_endpoint + '/facebook', passport.authenticate('facebook', { scope: ['email', 'pages_show_list'] }));
208
+ // facebook callback
209
+ const facebookCallback = (passport_config.strategy.facebook.callback_endpoint) ? (passport_config.strategy.facebook.callback_endpoint[0] === "/" ? passport_config.strategy.facebook.callback_endpoint : "/" + passport_config.strategy.facebook.callback_endpoint) : "/facebook/callback";
210
+ _app_.get(auth_endpoint + facebookCallback, passport.authenticate('facebook', (err, res) => {
211
+ console.log(err, res)
212
+ }));
213
+ }
57
214
  } catch (error) {
58
- reject(error);
215
+ throw error;
59
216
  }
60
- });
61
- }
217
+ }
218
+ }
@@ -0,0 +1,72 @@
1
+ const appRoot = require("app-root-path");
2
+ const passport_config = require(appRoot + "/passport.config.js");
3
+ const md5 = require("md5");
4
+ const secret = require("./salt").salt;
5
+
6
+ module.exports = {
7
+ findOne(table, fieldCondArr, cb) {
8
+ try {
9
+ let cond = '1';
10
+ let passportFields = (passport_config.model.fields.length) ? passport_config.model.fields : ["id", "name", "email"];
11
+ // Generate condition
12
+ Object.keys(fieldCondArr).forEach(key => {
13
+ cond += ' AND ' + key + '=' + fieldCondArr[key]
14
+ });
15
+ // raw SQL
16
+ let sql = 'SELECT ?? FROM ?? WHERE ' + cond;
17
+ const pool = eval("mysql." + passport_config.model.name);
18
+ pool.query(sql, [passportFields, table], (err, row) => {
19
+ cb(err, row);
20
+ });
21
+ } catch (error) {
22
+ cb(error, null);
23
+ }
24
+ },
25
+ store(fields, cb) {
26
+ try {
27
+ let keys = [];
28
+ let values = [passport_config.model.table || "users"];
29
+ let escaped = [];
30
+ let passwordField = String(passport_config.model.password_field || "password");
31
+ // asign password hash
32
+ fields[passwordField] = md5(fields[passwordField] + secret);
33
+ // sql generate
34
+ Object.keys(fields).forEach(key => {
35
+ keys.push(key);
36
+ values.push(fields[key]);
37
+ escaped.push('?');
38
+ });
39
+ let sql = 'INSERT INTO ?? (' + keys.join() + ') VALUES (' + escaped.join() + ')';
40
+ const pool = eval("mysql." + passport_config.model.name);
41
+ pool.query(sql, values, (err, result) => {
42
+ cb(err, result);
43
+ });
44
+ } catch (error) {
45
+ cb(error, null);
46
+ }
47
+ },
48
+ update(someFields, id, cb) {
49
+ try {
50
+ let keys = [];
51
+ let values = [passport_config.model.table || "users"];
52
+ let passwordField = String(passport_config.model.password_field || "password");
53
+ // check password body for asign hash
54
+ if (someFields[passwordField]) {
55
+ someFields[passwordField] = md5(someFields[passwordField] + secret);
56
+ }
57
+ // sql generate
58
+ Object.keys(someFields).forEach(key => {
59
+ keys.push(`${key}=?`);
60
+ values.push(someFields[key]);
61
+ });
62
+ values.push(id);
63
+ let sql = 'UPDATE ?? SET ' + keys.join() + ' WHERE id = ?';
64
+ const pool = eval("mysql." + passport_config.model.name);
65
+ pool.query(sql, values, (err, result) => {
66
+ cb(err, result);
67
+ });
68
+ } catch (error) {
69
+ cb(error, null);
70
+ }
71
+ },
72
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ salt: ["?p9E1oXV8My9akelVzsf3"]
3
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "application",
3
+ "version": "0.1.0",
4
+ "description": "The project is powered by Beech API framework",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "start": "nodemon ./node_modules/beech-api/packages/cli/beech",
8
+ "test": "node ./node_modules/jest/bin/jest __tests__ -o --watch --config"
9
+ },
10
+ "dependencies": {
11
+ "beech-api": "^3.2.11"
12
+ },
13
+ "devDependencies": {
14
+ "jest": "^25.2.7",
15
+ "sequelize-cli": "^5.5.1"
16
+ }
17
+ }