From 68f474bb8fba245ea47ad77da573519311d42458 Mon Sep 17 00:00:00 2001 From: Ethan Szeto Date: Tue, 12 Sep 2023 00:04:52 -0400 Subject: [PATCH] Lesson 5 --- app.js | 7 + auth/authorization.js | 23 +++ controllers/error.controller.js | 26 +++ controllers/user.controller.js | 103 +++++++++- css/index.css | 45 ----- css/style.css | 66 +++++++ db_accessor/user.accessor.js | 38 ++++ login.html | 12 -- package-lock.json | 335 ++++++++++++++++++++++++++++++-- package.json | 4 + routes/pages.route.js | 24 ++- views/index.ejs | 15 +- views/login_page.ejs | 36 ++++ views/profile.ejs | 28 +++ views/sign_up.ejs | 45 +++++ 15 files changed, 728 insertions(+), 79 deletions(-) create mode 100644 auth/authorization.js create mode 100644 controllers/error.controller.js create mode 100644 css/style.css delete mode 100644 login.html create mode 100644 views/login_page.ejs create mode 100644 views/profile.ejs create mode 100644 views/sign_up.ejs diff --git a/app.js b/app.js index bd8ad72..823a18b 100644 --- a/app.js +++ b/app.js @@ -2,14 +2,21 @@ import express from "express"; import cors from "cors"; import helmet from "helmet"; import route from "./routes/pages.route.js"; +import bodyParser from "body-parser"; +import cookieParser from "cookie-parser"; +import path from "path"; const app = express(); app.set("view engine", "ejs"); +app.set("views", path.resolve() + "/views"); app.use(cors()); app.use(helmet()); app.use(express.json()); +app.use(cookieParser()) +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); app.use("/", route); diff --git a/auth/authorization.js b/auth/authorization.js new file mode 100644 index 0000000..168cc63 --- /dev/null +++ b/auth/authorization.js @@ -0,0 +1,23 @@ +import dotenv from "dotenv"; +import jwt from "jsonwebtoken"; + +const authorize = (req, res, next) => { + dotenv.config(); + if(req.cookies.token) { + const payload = jwt.verify(req.cookies.token, process.env.TOKEN_KEY); + if(payload) { + req.user = payload; + next(); + } else { + //Forbidden - tampered token + req.error = 403; + next(); + } + } else { + //Unauthorized - not logged in + req.error = 401; + next(); + } +} + +export default authorize; \ No newline at end of file diff --git a/controllers/error.controller.js b/controllers/error.controller.js new file mode 100644 index 0000000..5a1a4c3 --- /dev/null +++ b/controllers/error.controller.js @@ -0,0 +1,26 @@ +const errorHandler = (req, res) => { + if(req.error) { + switch(req.error) { + case 400: + res.cookie("error", "Bad Request. Try again.", {maxAge: 1000}); + res.redirect("/login-page"); + break; + case 401: + res.cookie("error", "Login to have full access.", {maxAge: 1000}); + res.redirect("/login-page"); + break; + case 403: + res.cookie("error", "Forbidden. Log out and try again.", {maxAge: 1000}); + res.redirect("/login-page"); + break; + default: + res.cookie("error", "There was an error.", {maxAge: 1000}); + res.redirect("/"); + break; + } + } else { + res.redirect("/"); + } +} + +export default errorHandler; \ No newline at end of file diff --git a/controllers/user.controller.js b/controllers/user.controller.js index 933ac16..7c124c7 100644 --- a/controllers/user.controller.js +++ b/controllers/user.controller.js @@ -1,9 +1,110 @@ import UserAccessor from "../db_accessor/user.accessor.js"; +import bcrypt from "bcryptjs"; +import jwt from "jsonwebtoken"; export default class UserController { static async getAllUsers(req, res) { const users = await UserAccessor.getAllUsers(); - console.log(users); res.render("index", { users: users } ); } + + static async followUser(req, res, next) { + if(!req.error) { + const toFollow = req.body.follow; + const username = req.user.username; + const following = req.user.following; + + if(!following.some((follower) => {follower === toFollow}) && toFollow != username) { + await UserAccessor.addFollower(username, toFollow); + } + + res.redirect('/'); + } else { + return next(); + } + } + + static getProfile(req, res, next) { + if(!req.error) { + const user = req.user; + res.render('profile', + { + name: user.username, + email: user.email, + bio: user.bio, + followers: user.followers, + following: user.following, + }); + } else { + return next(); + } + } + + static getLogout(req, res) { + res.clearCookie("token"); + res.redirect('/'); + console.log("Signed out"); + } + + static getLoginPage(req, res) { + if(req.cookies.token) { + res.redirect('/profile'); + } else { + res.render('login_page', {error: req.cookies.error}); + } + } + + static getSignUpPage(req, res) { + if(req.cookies.token) { + res.redirect('/profile'); + } else { + res.render('sign_up'); + } + } + + static async postLogin(req, res, next) { + try { + if(!req.cookies.token) { + const user = await UserAccessor.getUser(req.body.username); + if(user) { + const result = await bcrypt.compare(req.body.password, user.password); + if(result) { + const token = jwt.sign( + { + username: user.username, + email: user.email, + bio: user.bio, + followers: user.followers, + following: user.following + }, + process.env.TOKEN_KEY + ); + res.cookie('token', token, {httpOnly: true, maxAge: 60 * 60 * 1000}); + res.redirect('/profile'); + } else { + req.error = 400; + next(); + } + } else { + req.error = 400; + next(); + } + } else { + res.redirect('/profile'); + } + } catch(e) { + req.error = 400; + next(); + } + } + + static async postSignUp(req, res, next) { + try { + req.body.password = await bcrypt.hash(req.body.password, 10); + await UserAccessor.createUser(req.body); + res.redirect("/login-page"); + } catch (e) { + return next(); + } + } } \ No newline at end of file diff --git a/css/index.css b/css/index.css index 804c716..bee95ac 100644 --- a/css/index.css +++ b/css/index.css @@ -1,21 +1,9 @@ -body { - background-color: #000000; - color: #eeeeee; - font-family: 'Trebuchet MS', sans-serif; -} - .profile-container { justify-items: center; display: grid; grid-template-columns: 300px 300px 300px; column-gap: 20px; row-gap: 20px; - background-color: #0e142e; - padding: 20px 40px 30px 40px; - border-radius: 20px; - position: absolute; - left: 50%; - transform: translate(-50%); } .profile-block { @@ -25,37 +13,4 @@ body { width: 250px; border-radius: 20px; margin-top: 10px; -} - -.btn { - min-width: 130px; - height: 40px; - color: #ffffff; - padding: 5px 10px; - font-weight: bold; - cursor: pointer; - transition: all 0.3s ease; - position: relative; - display: inline-block; - outline: none; - border-radius: 5px; - border: 2px solid #3c51b0; - background: #3c51b0; -} - -.btn:hover { - background: #b4bef0; - color: #2c51b0; -} - -.hr { - width: 50%; -} - -#header { - text-align: center; -} - -#description { - text-align: center; } \ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..4ddf7a6 --- /dev/null +++ b/css/style.css @@ -0,0 +1,66 @@ +body { + background-color: #000000; + color: #eeeeee; + font-family: 'Trebuchet MS', sans-serif; +} + +.btn { + min-width: 130px; + height: 40px; + color: #ffffff; + padding: 5px 10px; + font-weight: bold; + cursor: pointer; + transition: all 0.3s ease; + position: relative; + display: inline-block; + outline: none; + border-radius: 5px; + border: 2px solid #3c51b0; + background: #3c51b0; +} + +.btn:hover { + background: #b4bef0; + color: #2c51b0; +} + +.hr { + width: 50%; +} + +.header { + text-align: center; +} + +.text-input { + background-color: #000000; + color: #ffffff; +} + +.input-break { + display: block; + content: ""; + margin-top: 20px; +} + +.page-content { + min-width: 25%; + text-align: center; + background-color: #0e142e; + padding: 20px 40px 30px 40px; + border-radius: 20px; + position: absolute; + left: 50%; + transform: translate(-50%); +} + +.description { + text-align: center; +} + +.page-buttons { + position: fixed; + top: 10px; + right: 10px; +} \ No newline at end of file diff --git a/db_accessor/user.accessor.js b/db_accessor/user.accessor.js index c505fb8..1f0b0a1 100644 --- a/db_accessor/user.accessor.js +++ b/db_accessor/user.accessor.js @@ -14,4 +14,42 @@ export default class UserAccessor { throw e; } } + + static async getUser(username) { + try { + await Connection.open("users"); + const user = await User.findOne({ username: username }); + return user; + } catch (e) { + throw e; + } + } + + static async createUser(userDoc) { + try { + await Connection.open("users"); + const user = await User.create(userDoc); + return user; + } catch (e) { + throw e; + } + } + + static async addFollower(userWhoFollowed, userToFollow) { + try { + const follower = await UserAccessor.getUser(userWhoFollowed); + const followee = await UserAccessor.getUser(userToFollow); + + const followerList = follower.following; + followerList.push(userToFollow); + + const followeeList = followee.followers; + followeeList.push(userWhoFollowed); + + await User.findOneAndUpdate({ username: userWhoFollowed }, { following: followerList }); + await User.findOneAndUpdate({ username: userToFollow }, { followers: followeeList }); + } catch (e) { + throw e; + } + } } \ No newline at end of file diff --git a/login.html b/login.html deleted file mode 100644 index 50a2c92..0000000 --- a/login.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Login Page - - -

Login Page!

-

This is a description

- - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e081234..b210b2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,15 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "bcryptjs": "^2.4.3", + "body-parser": "^1.20.2", + "cookie-parser": "^1.4.6", "cors": "^2.8.5", "dotenv": "^16.3.1", "ejs": "^3.1.9", "express": "^4.18.2", "helmet": "^7.0.0", + "jsonwebtoken": "^9.0.2", "mongodb": "^6.0.0", "mongoose": "^7.5.0", "nodemon": "^3.0.1" @@ -104,6 +108,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "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", @@ -113,12 +122,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -126,7 +135,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -163,6 +172,11 @@ "node": ">=14.20.1" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -291,6 +305,26 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -344,6 +378,14 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -425,6 +467,43 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -692,6 +771,51 @@ "node": ">=10" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kareem": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", @@ -700,6 +824,41 @@ "node": ">=12.0.0" } }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1120,9 +1279,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -1489,18 +1648,23 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "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==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1508,7 +1672,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } @@ -1535,6 +1699,11 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz", "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==" }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1624,6 +1793,22 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, + "cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + } + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1661,6 +1846,14 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1725,6 +1918,38 @@ "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + } } }, "filelist": { @@ -1920,11 +2145,89 @@ "minimatch": "^3.1.2" } }, + "jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kareem": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2186,9 +2489,9 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", "http-errors": "2.0.0", diff --git a/package.json b/package.json index 4ab0260..283d7f0 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,15 @@ }, "homepage": "https://github.com/Northeastern-Science-Magazine/example-website#readme", "dependencies": { + "bcryptjs": "^2.4.3", + "body-parser": "^1.20.2", + "cookie-parser": "^1.4.6", "cors": "^2.8.5", "dotenv": "^16.3.1", "ejs": "^3.1.9", "express": "^4.18.2", "helmet": "^7.0.0", + "jsonwebtoken": "^9.0.2", "mongodb": "^6.0.0", "mongoose": "^7.5.0", "nodemon": "^3.0.1" diff --git a/routes/pages.route.js b/routes/pages.route.js index 94fa2c4..5c520df 100644 --- a/routes/pages.route.js +++ b/routes/pages.route.js @@ -1,6 +1,8 @@ import express from "express"; import path from "path"; import UserController from "../controllers/user.controller.js"; +import authorize from "../auth/authorization.js"; +import errorHandler from "../controllers/error.controller.js"; const router = express.Router(); @@ -10,8 +12,26 @@ router.route("/login").get((req, res) => { res.sendFile(path.resolve() + "/login.html"); }); -router.route('/css/index.css').get((req, res) => { +router.route("/css/index.css").get((req, res) => { res.sendFile(path.resolve() + "/css/index.css"); -}) +}); + +router.route("/css/style.css").get((req, res) => { + res.sendFile(path.resolve() + "/css/style.css"); +}); + +router.route("/follow").post(authorize, UserController.followUser, errorHandler); + +router.route("/profile").get(authorize, UserController.getProfile, errorHandler); + +router.route("/login-page") +.get(UserController.getLoginPage) +.post(UserController.postLogin, errorHandler); + +router.route("/sign-up") +.get(UserController.getSignUpPage) +.post(UserController.postSignUp, errorHandler); + +router.route("/logout").get(UserController.getLogout); export default router; \ No newline at end of file diff --git a/views/index.ejs b/views/index.ejs index 78a66bd..b321655 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -3,14 +3,15 @@ + Network Builder -

Welcome to Network Builder

-

Meet friends online with similar interests!

+

Welcome to Network Builder

+

Meet friends online with similar interests!


-
+
<% users.forEach((user) => { %>
@@ -27,5 +28,13 @@
<% }); %>
+ \ No newline at end of file diff --git a/views/login_page.ejs b/views/login_page.ejs new file mode 100644 index 0000000..83a529b --- /dev/null +++ b/views/login_page.ejs @@ -0,0 +1,36 @@ + + + + + + + + Login Page + + +

Login

+
+
+ <% if( error ){ %> +

<%= error %>

+ <% } %> + + + +
+ + +
+ + +
+ + + \ No newline at end of file diff --git a/views/profile.ejs b/views/profile.ejs new file mode 100644 index 0000000..454fe69 --- /dev/null +++ b/views/profile.ejs @@ -0,0 +1,28 @@ + + + + + + + + + Profile + + +

Profile

+
+
+

Username: <%= name %>

+

Email: <%= email %>

+

Bio: <%= bio %>

+

Followers: <%= followers %>

+

Following: <%= following %>

+ + + + + + +
+ + diff --git a/views/sign_up.ejs b/views/sign_up.ejs new file mode 100644 index 0000000..0dd8fae --- /dev/null +++ b/views/sign_up.ejs @@ -0,0 +1,45 @@ + + + + + + + + Sign Up! + + + +

Create an Account!

+

Sign up to network with others!

+
+
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ + + \ No newline at end of file