diff --git a/modules/data-service-auth.js b/modules/data-service-auth.js index 49b7e7a6..18bbdf9e 100644 --- a/modules/data-service-auth.js +++ b/modules/data-service-auth.js @@ -20,6 +20,10 @@ async function isUserIdExists(userId) { return !!result; } +async function getUserByEmail(email) { + const result = await client.db(dbName).collection(userCollection).findOne({email: email}) +} + async function hashPassword(password){ return await bcrypt.hash(password, saltRounds) } @@ -27,4 +31,5 @@ async function hashPassword(password){ export { createUser, isUserIdExists, + getUserByEmail, }; diff --git a/modules/database.js b/modules/database.js index fb1226a6..b9c60e03 100644 --- a/modules/database.js +++ b/modules/database.js @@ -1,3 +1,5 @@ +import express from "express"; +import path from "path"; import { MongoClient } from "mongodb"; import dotenv from "dotenv"; dotenv.config(); @@ -8,6 +10,15 @@ const dbName = "timesheet_app"; const collectionName = "hoursRecords"; const userCollection = "users" +const authenticateUser = (req, res, next) => { + if(req.session.user) { + next() + } + else { + res.status(401).json({message: 'Unauthorized'}); + } +} + // Function to connect to the MongoDB server async function connectToDatabase() { try { @@ -29,4 +40,6 @@ async function listDatabases(client) { }); } -export { client, dbName, collectionName, userCollection, listDatabases, connectToDatabase }; \ No newline at end of file + + +export { client, dbName, collectionName, userCollection, listDatabases, connectToDatabase, authenticateUser }; \ No newline at end of file diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 0477f098..2b1f0027 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -168,11 +168,6 @@ "node": ">= 10.0.0" } }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -483,6 +478,37 @@ "node": ">= 0.10.0" } }, + "node_modules/express-session": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", + "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", + "dependencies": { + "cookie": "0.6.0", + "cookie-signature": "1.0.7", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1302,6 +1328,14 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1383,6 +1417,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1746,6 +1788,17 @@ "node": ">= 0.6" } }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", diff --git a/package-lock.json b/package-lock.json index ff7ce56d..d0b3d5be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,10 @@ "license": "ISC", "dependencies": { "bcrypt": "^5.1.1", - "bcryptjs": "^2.4.3", "date-fns": "^3.3.0", "dotenv": "^16.4.1", "express": "^4.18.2", + "express-session": "^1.18.0", "mongodb": "^6.3.0", "mongoose": "^8.1.0", "react": "^18.2.0", @@ -188,11 +188,6 @@ "node": ">= 10.0.0" } }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -503,6 +498,37 @@ "node": ">= 0.10.0" } }, + "node_modules/express-session": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", + "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", + "dependencies": { + "cookie": "0.6.0", + "cookie-signature": "1.0.7", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1322,6 +1348,14 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1403,6 +1437,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1766,6 +1808,17 @@ "node": ">= 0.6" } }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", diff --git a/package.json b/package.json index 365c08e9..b538fc45 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "date-fns": "^3.3.0", "dotenv": "^16.4.1", "express": "^4.18.2", + "express-session": "^1.18.0", "mongodb": "^6.3.0", "mongoose": "^8.1.0", "react": "^18.2.0", diff --git a/routes/root.js b/routes/root.js index 6ffa1086..3fb342ce 100644 --- a/routes/root.js +++ b/routes/root.js @@ -1,13 +1,16 @@ import express from "express"; import path from "path"; -import { client } from "../modules/database.js"; +import bcrypt from 'bcrypt' +import { client, authenticateUser } from "../modules/database.js"; import { timeIn, timeOut, deleteUserById, addNewUser } from "../modules/data-service.js"; -import { createUser } from "../modules/data-service-auth.js"; +import { createUser, getUserByEmail } from "../modules/data-service-auth.js"; const router = express.Router(); const currentDir = process.cwd(); + + // Route to handle creating a new user router.post("/create-user", async (req, res) => { const newUser = req.body; @@ -25,6 +28,37 @@ router.post("/create-user", async (req, res) => { } }); +router.post("/login", async (req, res) => { + const {email, password} = req.body; + + try { + const user = await getUserByEmail(email) + console.log(user) + + if(!user) { + res.status(401).json({message: 'Invalid email or password'}); + return; + } + + const passwordMatch = await bcrypt.compare(password, user.password); + + if(passwordMatch) { + req.session.user = { + id: user._id, + email: user.email, + } + res.status(200).json({message: 'Login successful'}); + } + else { + res.status(401).json({ message: 'Invalid email or password' }); + } + + } catch (error) { + console.error('Error during login:', error); + res.status(500).json({ message: 'Internal Server Error' }); + } +}) + router.delete("/delete/:userId", async (req, res) => { const userId = req.params.userId; @@ -40,16 +74,19 @@ router.delete("/delete/:userId", async (req, res) => { } }); -router.get("/time-in", (req, res) => { - res.sendFile(path.resolve(currentDir, 'views', 'time-in.html')); +router.get('/', (req, res) => { + res.sendFile(path.resolve(currentDir, 'views', 'index.html')); }); -router.get("/time-out", (req, res) => { - res.sendFile(path.resolve(currentDir, 'views', 'time-out.html')) +router.get('/shift-table', authenticateUser, (req, res) => { + res.sendFile(path.resolve(currentDir, 'views', 'shiftTable.html')) }) -router.get('/', (req, res) => { - res.sendFile(path.resolve(currentDir, 'views', 'index.html')); -}); +router.get('/shift-tracker', authenticateUser, (req, res) => { + res.sendFile(path.resolve(currentDir, 'views', 'shiftTracker.html')) +}) +router.get('/about-us', (req, res) => { + res.sendFile(path.resolve(currentDir, 'views', 'aboutUs.html')) +}) export default router; diff --git a/routes/time-in.js b/routes/time-in.js index 82d81723..deae203e 100644 --- a/routes/time-in.js +++ b/routes/time-in.js @@ -1,12 +1,12 @@ import express from "express"; import path from "path"; -import { client } from "../models/database.js"; +import { client, authenticateUser } from "../models/database.js"; import { timeIn } from "../models/data-service.js"; const router = express.Router(); const currentDir = process.cwd(); -router.post("/time-in", async (req, res) => { +router.post("/time-in", authenticateUser, async (req, res) => { const userId = req.body.userId; try { @@ -19,7 +19,7 @@ router.post("/time-in", async (req, res) => { }); -router.get("/time-in", (req, res) => { +router.get("/time-in", authenticateUser, (req, res) => { res.sendFile(path.resolve(currentDir, 'views', 'time-in.html')); }); diff --git a/routes/time-out.js b/routes/time-out.js index 7cf7a5c1..d6a01f27 100644 --- a/routes/time-out.js +++ b/routes/time-out.js @@ -6,7 +6,7 @@ import { timeOut } from "../models/data-service.js"; const router = express.Router(); const currentDir = process.cwd(); -router.post("/time-out", async (req, res) => { +router.post("/time-out", authenticateUser, async (req, res) => { const userId = req.body.userId; try { @@ -18,7 +18,7 @@ router.post("/time-out", async (req, res) => { } }); -router.get("/time-out", (req, res) => { +router.get("/time-out", authenticateUser, (req, res) => { res.sendFile(path.resolve(currentDir, 'views', 'time-out.html')) }) diff --git a/server.js b/server.js index 09469547..40e314bc 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,5 @@ import express from "express"; +import session from "express-session"; import path from "path"; import router from "./routes/root.js"; import { client, connectToDatabase, listDatabases } from "./modules/database.js"; @@ -16,6 +17,15 @@ const currentDir = process.cwd(); app.use(express.static(path.join(currentDir, 'public'))) +const sessionSecret = 'htsagara'; + +//Set up session middleware +app.use(session({ + secret: sessionSecret, + resave: false, + saveUninitialized: true, +})) + // Call the connectToDatabase function to establish the connection connectToDatabase(); diff --git a/views/index.html b/views/index.html index 598d5f45..a2dcd73d 100644 --- a/views/index.html +++ b/views/index.html @@ -7,7 +7,7 @@ - + @@ -29,13 +29,13 @@

By CoffeeCollab