Skip to content

Commit 31fce2b

Browse files
Version 4.14.0 (Security)
- Update packages - Create .env vars instead of available constants in code - Add support for public and private routes
1 parent 81e13ff commit 31fce2b

File tree

15 files changed

+116
-56
lines changed

15 files changed

+116
-56
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules
22
*.log
3-
package-lock.json
3+
package-lock.json
4+
.env

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,20 @@ This application is hosted on Heroku and serve a bunch of AJAX requests to give
9797
## Configuring the API locally
9898

9999
- Download or clone the project access the project folder with the terminal and execute the CLI <code>npm install</code>
100-
- To change database change on constants the databaseUrl
100+
- Create your .env file with the following configuration
101+
- WORKERS: How many workers you need
102+
- AUTO_SCALE: When enabled will create workers by CPU Eg.: CPU \* WORKERS
103+
- DATABASE_URL: Your database URL
104+
- AUTH_ROUNDS and AUTH_SECRET: Those are used for authentication and verification
105+
106+
```
107+
WORKERS=1
108+
AUTO_SCALE=true
109+
DATABASE_URL=mongodb+srv://<user>:<password>@cluster0.mongodb.net/?retryWrites=true&w=majority
110+
AUTH_ROUNDS=15
111+
AUTH_SECRET=docssecret
112+
```
113+
101114
- Run the server <code>npm start</code>
102115
- Access in your browser <a href="http://localhost:3000/projects">http://localhost:3000/projects</a>
103116

@@ -111,6 +124,6 @@ This application is hosted on Heroku and serve a bunch of AJAX requests to give
111124

112125
By: <a href="http://renanlopes.com">Renan Lopes</a>
113126

114-
[heroku.com]: https://www.heroku.com
115-
[mlab.com]: https://mlab.com
127+
[vercel.com]: https://www.vercel.com
128+
[mongodb.com]: https://www.mongodb.com/atlas/database
116129
[github.com]: https://www.github.com

package.json

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
{
22
"name": "node_api",
3-
"version": "3.2.0",
3+
"version": "4.14.0",
44
"description": "Node API is production ready and open source project in Node, Express, MongoDB",
55
"scripts": {
66
"start": "node server.js"
77
},
88
"author": "Renan Lopes",
99
"license": "MIT",
1010
"dependencies": {
11-
"bcrypt": "4.0.1",
12-
"body-parser": "1.19.0",
11+
"bcrypt": "^5.1.1",
12+
"body-parser": "^1.20.2",
1313
"consign": "^0.1.6",
1414
"cors": "^2.8.3",
15+
"dotenv": "^16.4.1",
1516
"express": "^4.14.0",
16-
"jsonwebtoken": "^8.5.1",
17-
"mongoose": "5.9.11",
18-
"nodemailer": "6.4.6",
17+
"jsonwebtoken": "^9.0.2",
18+
"mongoose": "^5.13.22",
19+
"nodemailer": "^6.9.9",
1920
"swagger-jsdoc": "^4.3.2",
2021
"swagger-ui-express": "^4.1.6"
2122
},
2223
"engines": {
23-
"node": "14.1.0"
24+
"node": "20.x"
2425
}
2526
}

server.js

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,39 @@ const mongoose = require("mongoose");
22
const expressServer = require("./src/config/express");
33
const cluster = require("cluster");
44
const OS = require("os");
5-
const { databaseUrl } = require("./src/app/Constants/database");
6-
7-
const PORT = process.env.PORT || 8080;
5+
require("dotenv").config();
86

97
class App {
10-
constructor(workers, autoScale = true) {
11-
this.buildCluster(workers, autoScale);
8+
port;
9+
databaseUrl;
10+
11+
constructor() {
12+
this.validateEnvVars();
13+
14+
this.port = process.env.PORT || 8080;
15+
this.databaseUrl = process.env.DATABASE_URL;
16+
17+
this.buildCluster();
1218
}
1319

20+
validateEnvVars = () => {
21+
const errorMessage = "Required Environment Variable:";
22+
23+
if (!process.env.DATABASE_URL) {
24+
throw new Error(`${errorMessage} DATABASE_URL`);
25+
}
26+
27+
if (!process.env.AUTH_ROUNDS) {
28+
throw new Error(`${errorMessage} AUTH_ROUNDS`);
29+
}
30+
31+
if (!process.env.AUTH_SECRET) {
32+
throw new Error(`${errorMessage} AUTH_SECRET`);
33+
}
34+
};
35+
1436
database = () => {
15-
mongoose.connect(databaseUrl, {
37+
mongoose.connect(this.databaseUrl, {
1638
useCreateIndex: true,
1739
useNewUrlParser: true,
1840
useUnifiedTopology: true,
@@ -34,13 +56,15 @@ class App {
3456
});
3557
};
3658

37-
buildCluster = (workers, autoScale) => {
38-
if (autoScale) {
59+
buildCluster = () => {
60+
let workers = Number(process.env.WORKERS ?? 1);
61+
62+
if (process.env.AUTO_SCALE === "true") {
3963
workers = this.autoScale(workers);
4064
}
4165

4266
if (cluster.isMaster) {
43-
console.log("Cluster Master Online");
67+
console.log("Master Cluster Online");
4468

4569
for (let i = 0; i < workers; i += 1) {
4670
console.log(`Creating instances ${workers}`);
@@ -52,25 +76,18 @@ class App {
5276
cluster.fork();
5377
});
5478
} else {
55-
expressServer.listen(PORT, () => {
79+
expressServer.listen(this.port, () => {
5680
this.database();
57-
console.log(`Server running on port ${PORT}`);
81+
console.log(`Server running on port ${this.port}`);
5882
});
5983
}
6084
};
6185

6286
autoScale = (workersByCpu) => {
6387
const cpus = OS.cpus().length;
64-
const workers = cpus / workersByCpu;
88+
const workers = cpus * workersByCpu;
6589
return workers;
6690
};
6791
}
6892

69-
/**
70-
* Application Start
71-
*
72-
* @param number number of workers
73-
* @param boolean auto scale will use the number of workers by each CPU
74-
*/
75-
76-
new App(1, false);
93+
new App();

src/app/Constants/auth.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/app/Constants/database.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/app/Controllers/AuthController.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ const mongoose = require("mongoose");
22
const bcrypt = require("bcrypt");
33
const jwt = require("jsonwebtoken");
44
const model = mongoose.model("User");
5-
const { secret } = require("../Constants/auth");
65

76
class AuthController {
87
login = async (req, res) => {
@@ -13,7 +12,7 @@ class AuthController {
1312
let token;
1413
if (!match) {
1514
res.status(401).send({ error: "error", message: "Password mismatch" });
16-
token = jwt.sign({ user_id: user._id }, secret, {
15+
token = jwt.sign({ user_id: user._id }, process.env.AUTH_SECRET, {
1716
expiresIn: "3h",
1817
});
1918
}
@@ -37,7 +36,7 @@ class AuthController {
3736
const token = req.get("Authorization");
3837
if (token) {
3938
try {
40-
let decoded = jwt.verify(token, secret);
39+
let decoded = jwt.verify(token, process.env.AUTH_SECRET);
4140
req.user = decoded;
4241
next();
4342
} catch (error) {

src/app/Controllers/UserController.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
const mongoose = require("mongoose");
22
const bcrypt = require("bcrypt");
3-
const { rounds } = require("../Constants/auth");
43
const model = mongoose.model("User");
54

65
const MailerService = require("../Services/Mail");
76

87
class UserController {
9-
hashPassword = password => {
10-
const saltRounds = bcrypt.genSaltSync(rounds);
8+
hashPassword = (password) => {
9+
const saltRounds = bcrypt.genSaltSync(process.env.AUTH_ROUNDS);
1110
const hashedPassword = bcrypt.hashSync(password, saltRounds);
1211

1312
return hashedPassword;
1413
};
1514

16-
sendWelcomeEmail = email => {
15+
sendWelcomeEmail = (email) => {
1716
const content = MailerService.welcomeMailContent(email);
1817
MailerService.sendMail(content);
1918
};
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
module.exports = src => {
1+
module.exports = (src) => {
22
const { AuthController, UserController } = src.app.Controllers;
33

44
src.post("/login", AuthController.login);
55
src.post("/users/create", UserController.createUser);
66
// Private Routes
7-
// src.use("/*", AuthController.verifyToken);
7+
src.use("/*", AuthController.verifyToken);
88
};

src/config/express.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ app.get("/docs", swaggerUi.setup(specs, { explorer: true }));
2020
consign({ cwd: process.cwd() + "/src" })
2121
.include("app/Models")
2222
.then("app/Controllers")
23+
.then("routes/public")
2324
.then("app/Middleware/AuthMiddleware.js")
24-
.then("routes")
25+
.then("routes/private")
2526
.into(app);
2627

2728
module.exports = app;

0 commit comments

Comments
 (0)