diff --git a/.env b/.env index c0c68b1ca0..b7e990f91b 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -PORT=3000 \ No newline at end of file +PORT=3000 +SESSION_SECRET='keyboard cat' \ No newline at end of file diff --git a/app.js b/app.js index 2ecc9f2220..5c49e97b42 100644 --- a/app.js +++ b/app.js @@ -9,6 +9,7 @@ require('./db'); // https://www.npmjs.com/package/express const express = require('express'); + // Handles the handlebars // https://www.npmjs.com/package/hbs const hbs = require('hbs'); @@ -27,6 +28,10 @@ app.locals.title = `${capitalized(projectName)}- Generated with Ironlauncher`; // đ Start handling routes here const index = require('./routes/index'); app.use('/', index); +const userPage = require('./routes/user.routes'); +app.use('/user', userPage); +const protectedPages = require('./routes/protected.routes'); +app.use('/auth', protectedPages); // â To handle errors. Routes that don't exist or errors that you handle in specific routes require('./error-handling')(app); diff --git a/config/index.js b/config/index.js index 4d9ff5c193..e53b2169eb 100644 --- a/config/index.js +++ b/config/index.js @@ -17,6 +17,18 @@ const favicon = require("serve-favicon"); // https://www.npmjs.com/package/path const path = require("path"); +// âšī¸ Session middleware for authentication +// https://www.npmjs.com/package/express-session +const session = require("express-session"); + +// âšī¸ MongoStore in order to save the user session in the database +// https://www.npmjs.com/package/connect-mongo +const MongoStore = require("connect-mongo"); + +// Connects the mongo uri to maintain the same naming structure +const MONGO_URI = + process.env.MONGODB_URI || "mongodb://127.0.0.1:27017/lab-express-basic-auth"; + // Middleware configuration module.exports = (app) => { // In development environment the app logs @@ -31,9 +43,23 @@ module.exports = (app) => { app.set("views", path.join(__dirname, "..", "views")); // Sets the view engine to handlebars app.set("view engine", "hbs"); - // Handles access to the public folder + // AHandles access to the public folder app.use(express.static(path.join(__dirname, "..", "public"))); // Handles access to the favicon - app.use(favicon(path.join(__dirname, "..", "public", "images", "favicon.ico"))); + app.use( + favicon(path.join(__dirname, "..", "public", "images", "favicon.ico")) + ); + + // âšī¸ Middleware that adds a "req.session" information and later to check that you are who you say you are đ + app.use( + session({ + secret: process.env.SESSION_SECRET || "super hyper secret key", + resave: false, + saveUninitialized: false, + store: MongoStore.create({ + mongoUrl: MONGO_URI, + }), + }) + ); }; diff --git a/middleware/isLoggedIn.js b/middleware/isLoggedIn.js new file mode 100644 index 0000000000..a095734515 --- /dev/null +++ b/middleware/isLoggedIn.js @@ -0,0 +1,8 @@ +module.exports = (req, res, next) => { + // checks if the user is logged in when trying to access a specific page + if (!req.session.currentUser) { + return res.redirect("/user/login"); + } + + next(); +}; diff --git a/middleware/isLoggedOut.js b/middleware/isLoggedOut.js new file mode 100644 index 0000000000..caf42c09c1 --- /dev/null +++ b/middleware/isLoggedOut.js @@ -0,0 +1,8 @@ +module.exports = (req, res, next) => { + // if an already logged in user tries to access the login page it + // redirects the user to the home page + if (req.session.currentUser) { + return res.redirect("/auth/main"); + } + next(); +}; diff --git a/models/User.model.js b/models/User.model.js index 9cdd3a3ce4..31b965e8b9 100644 --- a/models/User.model.js +++ b/models/User.model.js @@ -4,9 +4,12 @@ const { Schema, model } = require("mongoose"); const userSchema = new Schema({ username: { type: String, - unique: true + unique: true, }, - password: String + password: { + type: String, + required: true, + } }); const User = model("User", userSchema); diff --git a/package.json b/package.json index 19489d9695..4f918a0152 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,12 @@ "dev": "nodemon server.js" }, "dependencies": { + "bcryptjs": "^2.4.3", + "connect-mongo": "^5.1.0", "cookie-parser": "^1.4.5", "dotenv": "^8.2.0", "express": "^4.17.1", + "express-session": "^1.18.0", "hbs": "^4.1.1", "mongoose": "^6.1.2", "morgan": "^1.10.0", diff --git a/public/images/697b023b-64a5-49a0-8059-27b963453fb1.gif b/public/images/697b023b-64a5-49a0-8059-27b963453fb1.gif new file mode 100644 index 0000000000..c45965afb2 Binary files /dev/null and b/public/images/697b023b-64a5-49a0-8059-27b963453fb1.gif differ diff --git a/public/images/OIP.jpg b/public/images/OIP.jpg new file mode 100644 index 0000000000..c35ac7a701 Binary files /dev/null and b/public/images/OIP.jpg differ diff --git a/routes/protected.routes.js b/routes/protected.routes.js new file mode 100644 index 0000000000..5342351a08 --- /dev/null +++ b/routes/protected.routes.js @@ -0,0 +1,17 @@ +const router = require("express").Router(); +const User = require("../models/User.model"); + +const isLoggedOut = require("../middleware/isLoggedOut"); +const isLoggedIn = require("../middleware/isLoggedIn"); + +router.get("/main", isLoggedIn, (req, res, next) => { + res.render("../views/protected/main.hbs"); + }); + + router.get("/private", isLoggedIn, (req, res, next) => { + res.render('../views/protected/private.hbs'); + }); + + + module.exports = router; + \ No newline at end of file diff --git a/routes/user.routes.js b/routes/user.routes.js new file mode 100644 index 0000000000..32686da24a --- /dev/null +++ b/routes/user.routes.js @@ -0,0 +1,52 @@ +const router = require("express").Router(); +const User = require("../models/User.model"); +const bcrypt = require("bcryptjs"); + +const isLoggedOut = require("../middleware/isLoggedOut"); +const isLoggedIn = require("../middleware/isLoggedIn"); + +/* GET home page */ +router.get("/create", (req, res, next) => { + res.render("../views/users/create-user.hbs"); +}); + +router.post("/create", async (req, res, next) => { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(req.body.password, salt); + User.create({ username: req.body.username, password: hash }).then(() => { + res.redirect("/"); + }); +}); + +router.get("/login", isLoggedOut ,(req, res, next) => { + res.render('../views/users/log-in.hbs'); +}); + +router.post('/login', async (req, res, next) => { + User.findOne({username: req.body.username}).then(async (user) => { + const isLoggedIn = await bcrypt.compare(req.body.password, user.password) + if(isLoggedIn){ + console.log('Your account exists'); + + req.session.currentUser = user.toObject(); + delete req.session.currentUser.password; + + res.redirect('/auth/main') + }else{ + console.log('Your account doesnt exist'); + } + }) +}) + +router.get("/logout", isLoggedIn, (req, res) => { + req.session.destroy((err) => { + if (err) { + res.status(500).render("auth/logout", { errorMessage: err.message }); + return; + } + + res.redirect("/user/login"); + }); +}); + +module.exports = router; diff --git a/views/index.hbs b/views/index.hbs index 1f308fdb35..d3ca09728f 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -1,2 +1,4 @@
Welcome to {{title}}
+Create a User +Log In diff --git a/views/layout.hbs b/views/layout.hbs index 73199c166b..8b60ab98b7 100644 --- a/views/layout.hbs +++ b/views/layout.hbs @@ -7,6 +7,7 @@
+Go Back
\ No newline at end of file
diff --git a/views/protected/private.hbs b/views/protected/private.hbs
new file mode 100644
index 0000000000..003891d1c5
--- /dev/null
+++ b/views/protected/private.hbs
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/views/users/create-user.hbs b/views/users/create-user.hbs
new file mode 100644
index 0000000000..8b07508061
--- /dev/null
+++ b/views/users/create-user.hbs
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/views/users/log-in.hbs b/views/users/log-in.hbs
new file mode 100644
index 0000000000..011b6bf36d
--- /dev/null
+++ b/views/users/log-in.hbs
@@ -0,0 +1,9 @@
+
\ No newline at end of file