From 87cad63425be6ec937831a5108965a76032e0171 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Mon, 5 May 2025 13:17:30 -0700 Subject: [PATCH 1/2] update/return status codes --- app.js | 27 ++++++++++++++++++------ package-lock.json | 54 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/app.js b/app.js index 2fc8319..46233f1 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,7 @@ const express = require('express'); const path = require('path'); const session = require("express-session"); +const MongoStore = require("connect-mongo"); require('dotenv').config(); const app = express(); @@ -11,10 +12,13 @@ app.set('views',path.join(__dirname, 'src/views')); app.use(express.urlencoded({ extended: true })); app.use("/static", express.static("./src/public")); +/*** Sessions ***/ app.use(session({ - secret: process.env.secret, + secret: config.express_secret, + store: MongoStore.create({ mongoUrl: `${mongoURI}/${config.mongo_database}`, crypto: { secret: config.mongo_secret } }), resave: true, saveUninitialized: false, + cookie: { maxAge: 60000 }, })); /*** Database ***/ @@ -31,63 +35,74 @@ async function initDatabase() { users = await getCollection(db, "users"); } - initDatabase().then(() => { require("./src/auth/authentication")(app, users); }); -/* -ROUTINGS -*/ +/*** ROUTINGS ***/ app.get('/', (req, res) => { if (!req.session.errMessage) req.session.errMessage = ""; res.render('index'); + return res.status(200); }); app.get('/landing', (req, res) => { res.render('landing'); + return res.status(200); }); app.get('/signup', (req, res) => { res.render('signup', { errMessage: req.session.errMessage }); + return res.status(200); }); app.get('/login', (req, res) => { + if (req.session.authenticated) { + + } res.render('login', { errMessage: req.session.errMessage }); + return res.status(200); }); app.get('/home', (req, res) => { res.render('home'); + return res.status(200); }); app.get('/assets', (req, res) => { res.render('assets'); + return res.status(200); }); app.get('/plans', (req, res) => { res.render('plans'); + return res.status(200); }); app.get('/more', (req, res) => { res.render('more'); + return res.status(200); }); app.get('/profile', (req, res) => { res.render('profiles'); + return res.status(200); }); app.get('/settings', (req, res) => { res.render('settings'); + return res.status(200); }); app.get('/aboutUs', (req, res) => { res.render('aboutUs'); + return res.status(200); }); app.get('/*splat', (req, res) => { - res.status(404); res.send('404 Not Found'); + return res.status(404); }); app.listen(port, () => { diff --git a/package-lock.json b/package-lock.json index cbe1757..54d9320 100755 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "bcrypt": "^5.1.1", + "connect-mongo": "^5.1.0", "dotenv": "^16.5.0", "ejs": "^3.1.10", "express": "^5.1.0", @@ -190,6 +191,18 @@ "node": ">=10" } }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -229,6 +242,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -423,6 +442,23 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/connect-mongo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-5.1.0.tgz", + "integrity": "sha512-xT0vxQLqyqoUTxPLzlP9a/u+vir0zNkhiy9uAdHjSCcUUf7TS5b55Icw8lVyYFxfemP3Mf9gdwUOgeF3cxCAhw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.1", + "kruptein": "^3.0.0" + }, + "engines": { + "node": ">=12.9.0" + }, + "peerDependencies": { + "express-session": "^1.17.1", + "mongodb": ">= 5.1.0 < 7" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -1138,6 +1174,18 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/kruptein": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.7.tgz", + "integrity": "sha512-vTftnEjfbqFHLqxDUMQCj6gBo5lKqjV4f0JsM8rk8rM3xmvFZ2eSy4YALdaye7E+cDKnEj7eAjFR3vwh8a4PgQ==", + "license": "MIT", + "dependencies": { + "asn1.js": "^5.4.1" + }, + "engines": { + "node": ">8" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -1219,6 +1267,12 @@ "node": ">= 0.6" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", diff --git a/package.json b/package.json index ce02060..4f1048f 100755 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "homepage": "https://github.com/JoaquinPar/2800-202510-BBY14#readme", "dependencies": { "bcrypt": "^5.1.1", + "connect-mongo": "^5.1.0", "dotenv": "^16.5.0", "ejs": "^3.1.10", "express": "^5.1.0", From fe7152b03bb7e34a2088d64d5c370ae908835f2b Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Mon, 5 May 2025 14:16:50 -0700 Subject: [PATCH 2/2] update/create middleware --- app.js | 84 +++++++++++++++----------------------- src/auth/authentication.js | 48 ++++++++++++++-------- src/auth/middleware.js | 22 ++++++++++ src/router/user.js | 35 ++++++++++++++++ src/util/statuses.js | 7 ++++ 5 files changed, 127 insertions(+), 69 deletions(-) create mode 100644 src/auth/middleware.js create mode 100644 src/router/user.js create mode 100644 src/util/statuses.js diff --git a/app.js b/app.js index 46233f1..f95b832 100644 --- a/app.js +++ b/app.js @@ -1,34 +1,36 @@ +const status = require("./src/util/statuses"); +const MongoStore = require("connect-mongo"); +const session = require("express-session"); const express = require('express'); const path = require('path'); -const session = require("express-session"); -const MongoStore = require("connect-mongo"); require('dotenv').config(); const app = express(); const port = process.env.PORT || 3000; +const mongoURI = process.env.mongoURI || "mongodb://localhost:27017/"; +const database = process.env.database || "knoldus"; // Database name +const secret = process.env.secret || "123-secret-xyz"; + +/*** Sessions ***/ +app.use(session({ + secret: secret, + store: MongoStore.create({ mongoUrl: `${mongoURI}${database}`, crypto: { secret: secret } }), + resave: true, + saveUninitialized: false, + cookie: { maxAge: 60000 }, +})); + app.set('view engine', 'ejs'); app.set('views',path.join(__dirname, 'src/views')); app.use(express.urlencoded({ extended: true })); app.use("/static", express.static("./src/public")); -/*** Sessions ***/ -app.use(session({ - secret: config.express_secret, - store: MongoStore.create({ mongoUrl: `${mongoURI}/${config.mongo_database}`, crypto: { secret: config.mongo_secret } }), - resave: true, - saveUninitialized: false, - cookie: { maxAge: 60000 }, -})); - /*** Database ***/ const { connectMongo, getCollection } = require("./src/database/connection"); let users; async function initDatabase() { - const mongoURI = process.env.mongoURI || "mongodb://localhost:27017/"; - const database = process.env.database || "knoldus"; // Database name - const db = await connectMongo(mongoURI, database); // For any collection, init here @@ -36,7 +38,14 @@ async function initDatabase() { } initDatabase().then(() => { - require("./src/auth/authentication")(app, users); + // Import authentication handler + app.use(require("./src/auth/authentication")(users)); + + // Import middleware + const middleware = require("./src/auth/middleware")(users); + + // Apply middleware to protected user routes + app.use(require("./src/router/user")(middleware)); }); /*** ROUTINGS ***/ @@ -44,65 +53,36 @@ initDatabase().then(() => { app.get('/', (req, res) => { if (!req.session.errMessage) req.session.errMessage = ""; res.render('index'); - return res.status(200); + return res.status(status.Ok); }); app.get('/landing', (req, res) => { res.render('landing'); - return res.status(200); + return res.status(status.Ok); }); app.get('/signup', (req, res) => { res.render('signup', { errMessage: req.session.errMessage }); - return res.status(200); + return res.status(status.Ok); }); app.get('/login', (req, res) => { if (req.session.authenticated) { - + res.redirect("/home"); + return res.status(status.Ok); } res.render('login', { errMessage: req.session.errMessage }); - return res.status(200); -}); - -app.get('/home', (req, res) => { - res.render('home'); - return res.status(200); -}); - -app.get('/assets', (req, res) => { - res.render('assets'); - return res.status(200); -}); - -app.get('/plans', (req, res) => { - res.render('plans'); - return res.status(200); -}); - -app.get('/more', (req, res) => { - res.render('more'); - return res.status(200); -}); - -app.get('/profile', (req, res) => { - res.render('profiles'); - return res.status(200); -}); - -app.get('/settings', (req, res) => { - res.render('settings'); - return res.status(200); + return res.status(status.Ok); }); app.get('/aboutUs', (req, res) => { res.render('aboutUs'); - return res.status(200); + return res.status(status.Ok); }); app.get('/*splat', (req, res) => { res.send('404 Not Found'); - return res.status(404); + return res.status(status.NotFound); }); app.listen(port, () => { diff --git a/src/auth/authentication.js b/src/auth/authentication.js index 01015fa..2a2e9ed 100644 --- a/src/auth/authentication.js +++ b/src/auth/authentication.js @@ -1,9 +1,12 @@ -const joi = require("joi"); +const status = require("../util/statuses"); const bcrypt = require('bcrypt'); +const joi = require("joi"); const salt = 12; -module.exports = (app, users) => { - app.post("/login", async (req, res) => { +module.exports = (users) => { + const router = require("express").Router(); + + router.post("/login", async (req, res) => { const credentialSchema = joi.object({ email: joi.string().email().required(), password: joi.string().max(20).required(), @@ -13,32 +16,33 @@ module.exports = (app, users) => { if (valid.err) { req.session.errMessage = "Invalid input"; - res.status(400); + res.status(status.BadRequest); return res.redirect("/login"); } users.findOne({ "email": req.body.email }).then((user) => { if (!user) { req.session.errMessage = "User not found"; - res.status(404); - return res.redirect("/login"); + res.status(status.NotFound); + return res.redirect("/login"); } if (!bcrypt.compare(req.body.password, user.password)) { req.session.errMessage = "Incorrect password"; - res.status(401); + res.status(status.Unauthorized); return res.redirect("/login"); } - // ignorin sessions for now just have basic login for demo - // TODO: actually add sessions + req.session.authenticated = true; + req.session.email = req.body.email; req.session.errMessage = ""; res.redirect("/home"); + return res.status(status.Ok); }); }); - app.post("/signup", async (req, res) => { + router.post("/signup", async (req, res) => { const userSchema = joi.object({ email: joi.string().email().required(), // name: joi.string().alphanum().max(20).required(), @@ -50,13 +54,13 @@ module.exports = (app, users) => { if (valid.err) { req.session.errMessage = "Invalid input", - res.status(400); + res.status(status.BadRequest); return res.redirect("/signup"); } if (req.body.password != req.body.repassword) { req.session.errMessage = "Passwords must match"; - res.status(400); + res.status(status.BadRequest); return res.redirect("/signup"); } @@ -68,15 +72,25 @@ module.exports = (app, users) => { password: hashedPassword, }).then((results, err) => { if (err) { - res.status(500); + res.status(status.InternalServerError); console.error(err); return res.send("Internal server error"); } - // TODO: Add session handling here and auto redirect to home and be authenticated - req.session.errMessage = "Please login to view that resource"; - res.status(200); - return res.redirect("/login"); + req.session.authenticated = true; + req.session.email = req.body.email; + + req.session.errMessage = ""; + res.status(status.Ok); + return res.redirect("/home"); }); }); + + router.get("/logout", (req, res) => { + req.session.destroy(); + // res.status(status.Unauthorized); + return res.redirect('/login'); + }); + + return router; } diff --git a/src/auth/middleware.js b/src/auth/middleware.js new file mode 100644 index 0000000..071a8a2 --- /dev/null +++ b/src/auth/middleware.js @@ -0,0 +1,22 @@ +const status = require("../util/statuses"); + +module.exports = (users) => { + return async (req, res, next) => { + if (!req.session.authenticated || !req.session.email) { + req.session.errMessage = "Please login to view that resource"; + res.redirect("/login"); + return res.status(status.Unauthorized); + } + + let user = await users.findOne({ "email": req.session.email }).then((user) => user); + + if (!user) { + req.session.errMessage = "User not found"; + res.redirect("/login"); + return res.status(status.Unauthorized); + } + + req.user = user; + next(); + } +}; diff --git a/src/router/user.js b/src/router/user.js new file mode 100644 index 0000000..5570874 --- /dev/null +++ b/src/router/user.js @@ -0,0 +1,35 @@ +module.exports = (middleware) => { + const router = require("express").Router(); + + router.get('/home', middleware, async (req, res) => { + res.render('home', { user: req.user }); + return res.status(status.Ok); + }); + + router.get('/assets', middleware, (req, res) => { + res.render('assets', { user: req.user }); + return res.status(status.Ok); + }); + + router.get('/plans', middleware, (req, res) => { + res.render('plans', { user: req.user }); + return res.status(status.Ok); + }); + + router.get('/more', middleware, (req, res) => { + res.render('more', { user: req.user }); + return res.status(status.Ok); + }); + + router.get('/profile', middleware, (req, res) => { + res.render('profiles', { user: req.user }); + return res.status(status.Ok); + }); + + router.get('/settings', middleware, (req, res) => { + res.render('settings', { user: req.user }); + return res.status(status.Ok); + }); + + return router; +}; diff --git a/src/util/statuses.js b/src/util/statuses.js new file mode 100644 index 0000000..d06ffba --- /dev/null +++ b/src/util/statuses.js @@ -0,0 +1,7 @@ +module.exports = { + Ok: 200, + BadRequest: 400, + Unauthorized: 401, + NotFound: 404, + InternalServerError: 500, +};