aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2022-06-03 14:36:30 +0530
committerBobby <[email protected]>2022-06-03 14:36:30 +0530
commit06e4ecd95bfd2817e56af83dbe9af1b6eba283bf (patch)
treea2ec28bbab430e634b5c964d9e8c56e636e46062
parent1958098bdabf10f6b8ac9ea5851e08172dd8e10c (diff)
downloadthatcomputerscientist-06e4ecd95bfd2817e56af83dbe9af1b6eba283bf.tar.xz
thatcomputerscientist-06e4ecd95bfd2817e56af83dbe9af1b6eba283bf.zip
complete login functionality
-rw-r--r--package-lock.json237
-rw-r--r--package.json5
-rw-r--r--public/css/main.css4
-rw-r--r--routes/api/admin.js136
-rw-r--r--routes/api/user.js133
-rw-r--r--routes/auth.routes.js61
-rw-r--r--routes/basic.routes.js34
-rw-r--r--routes/index.js2
-rw-r--r--server.js11
-rw-r--r--views/partials/sidebar.ejs10
10 files changed, 476 insertions, 157 deletions
diff --git a/package-lock.json b/package-lock.json
index 3ce51b02..e7379cf0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,13 +12,16 @@
"@prisma/client": "^3.14.0",
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.0",
+ "connect-flash": "^0.1.1",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
"ejs": "^3.1.8",
"express": "^4.18.1",
+ "express-session": "^1.17.3",
"jsonwebtoken": "^8.5.1",
- "mysql2": "^2.3.3"
+ "mysql2": "^2.3.3",
+ "node-fetch": "^3.2.5"
},
"devDependencies": {
"nodemon": "^2.0.16"
@@ -422,6 +425,14 @@
"node": ">=8"
}
},
+ "node_modules/connect-flash": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
+ "integrity": "sha512-2rcfELQt/ZMP+SM/pG8PyhJRaLKp+6Hk2IUBNkEit09X+vwn3QsAL3ZbYtxUn7NVPzbMTSLRDhqe0B/eh30RYA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -495,6 +506,14 @@
"node": ">=8"
}
},
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
+ "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -694,6 +713,54 @@
"node": ">= 0.10.0"
}
},
+ "node_modules/express-session": {
+ "version": "1.17.3",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz",
+ "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==",
+ "dependencies": {
+ "cookie": "0.4.2",
+ "cookie-signature": "1.0.6",
+ "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.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fetch-blob": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz",
+ "integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
"node_modules/filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
@@ -750,6 +817,17 @@
"node": ">= 0.8"
}
},
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -1433,6 +1511,41 @@
"node": ">= 0.6"
}
},
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.5.tgz",
+ "integrity": "sha512-u7zCHdJp8JXBwF09mMfo2CL6kp37TslDl1KP3hRGTlCInBtag+UO3LGVy+NF0VzvnL3PVMpA2hXh1EtECFnyhQ==",
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
"node_modules/nodemon": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz",
@@ -1558,6 +1671,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",
@@ -1711,6 +1832,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",
@@ -2059,6 +2188,17 @@
"is-typedarray": "^1.0.0"
}
},
+ "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",
@@ -2156,6 +2296,14 @@
"node": ">= 0.8"
}
},
+ "node_modules/web-streams-polyfill": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/widest-line": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
@@ -2516,6 +2664,11 @@
"xdg-basedir": "^4.0.0"
}
},
+ "connect-flash": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
+ "integrity": "sha512-2rcfELQt/ZMP+SM/pG8PyhJRaLKp+6Hk2IUBNkEit09X+vwn3QsAL3ZbYtxUn7NVPzbMTSLRDhqe0B/eh30RYA=="
+ },
"content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -2570,6 +2723,11 @@
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
"dev": true
},
+ "data-uri-to-buffer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
+ "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA=="
+ },
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -2729,6 +2887,37 @@
"vary": "~1.1.2"
}
},
+ "express-session": {
+ "version": "1.17.3",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz",
+ "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==",
+ "requires": {
+ "cookie": "0.4.2",
+ "cookie-signature": "1.0.6",
+ "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"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
+ }
+ }
+ },
+ "fetch-blob": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz",
+ "integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==",
+ "requires": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ }
+ },
"filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
@@ -2778,6 +2967,14 @@
"unpipe": "~1.0.0"
}
},
+ "formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "requires": {
+ "fetch-blob": "^3.1.2"
+ }
+ },
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -3305,6 +3502,21 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
},
+ "node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
+ },
+ "node-fetch": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.5.tgz",
+ "integrity": "sha512-u7zCHdJp8JXBwF09mMfo2CL6kp37TslDl1KP3hRGTlCInBtag+UO3LGVy+NF0VzvnL3PVMpA2hXh1EtECFnyhQ==",
+ "requires": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ }
+ },
"nodemon": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz",
@@ -3394,6 +3606,11 @@
"ee-first": "1.1.1"
}
},
+ "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=="
+ },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3508,6 +3725,11 @@
"side-channel": "^1.0.4"
}
},
+ "random-bytes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+ "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ=="
+ },
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -3773,6 +3995,14 @@
"is-typedarray": "^1.0.0"
}
},
+ "uid-safe": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+ "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+ "requires": {
+ "random-bytes": "~1.0.0"
+ }
+ },
"undefsafe": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
@@ -3845,6 +4075,11 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
+ "web-streams-polyfill": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
+ },
"widest-line": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
diff --git a/package.json b/package.json
index 31e0c4d3..625c1555 100644
--- a/package.json
+++ b/package.json
@@ -21,13 +21,16 @@
"@prisma/client": "^3.14.0",
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.0",
+ "connect-flash": "^0.1.1",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
"ejs": "^3.1.8",
"express": "^4.18.1",
+ "express-session": "^1.17.3",
"jsonwebtoken": "^8.5.1",
- "mysql2": "^2.3.3"
+ "mysql2": "^2.3.3",
+ "node-fetch": "^3.2.5"
},
"devDependencies": {
"nodemon": "^2.0.16"
diff --git a/public/css/main.css b/public/css/main.css
index 747fb352..c48c383d 100644
--- a/public/css/main.css
+++ b/public/css/main.css
@@ -73,3 +73,7 @@ nav > ul > li {
margin-top: 0;
margin-bottom: 10px;
}
+
+.error {
+ color: red;
+}
diff --git a/routes/api/admin.js b/routes/api/admin.js
index 080c6906..dd5d2744 100644
--- a/routes/api/admin.js
+++ b/routes/api/admin.js
@@ -1,82 +1,86 @@
const router = require("express").Router();
-const mysql = require('mysql2');
-const bcrypt = require('bcryptjs');
-const validateAuthorization = require('../../functions/validate');
+const mysql = require("mysql2");
+const bcrypt = require("bcryptjs");
+const validateAuthorization = require("../../functions/validate");
require("dotenv").config();
const connectionURL = process.env.DATABASE_URL;
router.get("/", (req, res) => {
- const validationHeader = req.headers.auth;
- if (validateAuthorization(validationHeader)) {
- res.status(200).json({
- message: "Welcome to the Admin API!"
- });
- } else {
- res.status(401).json({
- message: "Unauthorized"
- });
- }
+ const validationHeader = req.headers.auth;
+ if (validateAuthorization(validationHeader)) {
+ res.status(200).json({
+ message: "Welcome to the Admin API!",
+ });
+ } else {
+ res.status(401).json({
+ message: "Unauthorized",
+ });
+ }
});
router.post("/create", (req, res) => {
- // Creates an admin user
- const validationHeader = req.headers.auth;
- if (validateAuthorization(validationHeader)) {
- const connection = mysql.createConnection(connectionURL);
- connection.connect();
- const sql = "INSERT INTO Users (username, password, admin) VALUES (?, ?, ?)";
- const username = req.body.username;
- const password = req.body.password;
- const hashedPassword = bcrypt.hashSync(password, 10);
- const admin = 1;
- connection.query(sql, [username, hashedPassword, admin], (err, results, fields) => {
- if (err) {
- res.status(500).json({
- message: "Error creating user",
- error: err
- });
- } else {
- res.status(201).json({
- message: "User created"
- });
- }
- });
- connection.end();
- } else {
- res.status(401).json({
- message: "Unauthorized"
- });
- }
+ // Creates an admin user
+ const validationHeader = req.headers.auth;
+ if (validateAuthorization(validationHeader)) {
+ const connection = mysql.createConnection(connectionURL);
+ connection.connect();
+ const sql =
+ "INSERT INTO Users (username, password, admin) VALUES (?, ?, ?)";
+ const username = req.body.username;
+ const password = req.body.password;
+ const hashedPassword = bcrypt.hashSync(password, 10);
+ const admin = 1;
+ connection.query(
+ sql,
+ [username, hashedPassword, admin],
+ (err, results, fields) => {
+ if (err) {
+ res.status(500).json({
+ message: "Error creating user",
+ error: err,
+ });
+ } else {
+ res.status(201).json({
+ message: "User created",
+ });
+ }
+ }
+ );
+ connection.end();
+ } else {
+ res.status(401).json({
+ message: "Unauthorized",
+ });
+ }
});
-router.post('/delete', (req, res) => {
- // Deletes an admin user
- const validationHeader = req.headers.auth;
- if (validateAuthorization(validationHeader)) {
- const connection = mysql.createConnection(connectionURL);
- connection.connect();
- const sql = "DELETE FROM Users WHERE username = ?";
- const username = req.body.username;
- connection.query(sql, [username], (err, results, fields) => {
- if (err) {
- res.status(500).json({
- message: "Error deleting user",
- error: err
- });
- } else {
- res.status(200).json({
- message: "User deleted"
- });
- }
+router.post("/delete", (req, res) => {
+ // Deletes an admin user
+ const validationHeader = req.headers.auth;
+ if (validateAuthorization(validationHeader)) {
+ const connection = mysql.createConnection(connectionURL);
+ connection.connect();
+ const sql = "DELETE FROM Users WHERE username = ?";
+ const username = req.body.username;
+ connection.query(sql, [username], (err, results, fields) => {
+ if (err) {
+ res.status(500).json({
+ message: "Error deleting user",
+ error: err,
});
- connection.end();
- } else {
- res.status(401).json({
- message: "Unauthorized"
+ } else {
+ res.status(200).json({
+ message: "User deleted",
});
- }
+ }
+ });
+ connection.end();
+ } else {
+ res.status(401).json({
+ message: "Unauthorized",
+ });
+ }
});
-
module.exports = router;
diff --git a/routes/api/user.js b/routes/api/user.js
index 5424619f..8874d2e5 100644
--- a/routes/api/user.js
+++ b/routes/api/user.js
@@ -1,77 +1,82 @@
const router = require("express").Router();
-const mysql = require('mysql2');
-const bcrypt = require('bcryptjs');
-const jwt = require('jsonwebtoken');
+const mysql = require("mysql2");
+const bcrypt = require("bcryptjs");
+const jwt = require("jsonwebtoken");
require("dotenv").config();
const connectionURL = process.env.DATABASE_URL;
const validationString = process.env.AUTHORIZATION_STRING;
-router.post('/login', (req, res) => {
- // Log in as user
- const username = req.body.username;
- const password = req.body.password;
- const connection = mysql.createConnection(connectionURL);
- connection.connect();
- const sql = "SELECT * FROM Users WHERE username = ?";
- connection.query(sql, [username], (err, results, fields) => {
- if (err) {
- res.status(500).json({
- message: "Error logging in",
- error: err
- });
+router.post("/login", (req, res) => {
+ // Log in as user
+ const username = req.body.username;
+ const password = req.body.password;
+ const connection = mysql.createConnection(connectionURL);
+ connection.connect();
+ const sql = "SELECT * FROM Users WHERE username = ?";
+ connection.query(sql, [username], (err, results, fields) => {
+ if (err) {
+ res.status(500).json({
+ message: "Error logging in",
+ error: err,
+ });
+ } else {
+ if (results.length > 0) {
+ const user = results[0];
+ if (bcrypt.compareSync(password, user.password)) {
+ const token = jwt.sign(
+ {
+ username: user.username,
+ admin: user.admin,
+ },
+ validationString
+ );
+ res.status(200).json({
+ message: "Logged in",
+ token: token,
+ });
} else {
- if (results.length > 0) {
- const user = results[0];
- if (bcrypt.compareSync(password, user.password)) {
- const token = jwt.sign({
- username: user.username,
- admin: user.admin
- }, validationString);
- res.status(200).json({
- message: "Logged in",
- token: token
- });
- } else {
- res.status(401).json({
- message: "Incorrect password"
- });
- }
- } else {
- res.status(401).json({
- message: "User not found"
- });
- }
+ res.status(401).json({
+ message: "Incorrect password",
+ });
}
- });
- connection.end();
+ } else {
+ res.status(401).json({
+ message: "User not found",
+ });
+ }
+ }
+ });
+ connection.end();
});
-router.post('/create', (req, res) => {
- // Creates a regular user
- const username = req.body.username;
- const password = req.body.password;
- const connection = mysql.createConnection(connectionURL);
- connection.connect();
- const sql = "INSERT INTO Users (username, password, admin) VALUES (?, ?, ?)";
- const hashedPassword = bcrypt.hashSync(password, 10);
- const admin = 0;
- connection.query(sql, [username, hashedPassword, admin], (err, results, fields) => {
- if (err) {
- res.status(500).json({
- message: "Error creating user",
- error: err
- });
- } else {
- res.status(201).json({
- message: "User created"
- });
- }
- });
- connection.end();
+router.post("/create", (req, res) => {
+ // Creates a regular user
+ const username = req.body.username;
+ const password = req.body.password;
+ const connection = mysql.createConnection(connectionURL);
+ connection.connect();
+ const sql = "INSERT INTO Users (username, password, admin) VALUES (?, ?, ?)";
+ const hashedPassword = bcrypt.hashSync(password, 10);
+ const admin = 0;
+ connection.query(
+ sql,
+ [username, hashedPassword, admin],
+ (err, results, fields) => {
+ if (err) {
+ res.status(500).json({
+ message: "Error creating user",
+ error: err,
+ });
+ } else {
+ res.status(201).json({
+ message: "User created",
+ });
+ }
+ }
+ );
+ connection.end();
});
-
-
-module.exports = router; \ No newline at end of file
+module.exports = router;
diff --git a/routes/auth.routes.js b/routes/auth.routes.js
new file mode 100644
index 00000000..da1f339f
--- /dev/null
+++ b/routes/auth.routes.js
@@ -0,0 +1,61 @@
+const router = require("express").Router();
+const jwt = require("jsonwebtoken");
+const mysql = require('mysql2');
+const bcrypt = require('bcryptjs');
+
+require("dotenv").config();
+const validationString = process.env.AUTHORIZATION_STRING;
+const connectionURL = process.env.DATABASE_URL;
+
+router.get('/logout', (req, res) => {
+ res.clearCookie("token");
+ res.redirect(req.get('referer'));
+})
+
+router.post('/login', (req, res) => {
+ // Log in as user
+ const username = req.body.username;
+ const password = req.body.password;
+ const connection = mysql.createConnection(connectionURL);
+ connection.connect();
+ const sql = "SELECT * FROM Users WHERE username = ?";
+ connection.query(sql, [username], (err, results, fields) => {
+ if (err) {
+ res.status(500).json({
+ message: "Error logging in",
+ error: err
+ });
+ } else {
+ if (results.length > 0) {
+ const user = results[0];
+ if (bcrypt.compareSync(password, user.password)) {
+ // expires in 30 days
+ const token = jwt.sign({
+ username: user.username,
+ admin: user.admin
+ }, validationString, {
+ expiresIn: '30d'
+ });
+ // set cookie
+ res.cookie('token', token, {
+ maxAge: 30 * 24 * 60 * 60 * 1000,
+ httpOnly: true
+ });
+ res.redirect(req.get('referer'));
+ } else {
+ // incorrect password, redirect to referer with error
+ req.flash('error', 'Incorrect password');
+ res.redirect(req.get('referer'));
+ }
+ } else {
+ // user not found, redirect to referer with error
+ req.flash('error', 'User not found');
+ res.redirect(req.get('referer'));
+ }
+ }
+ });
+ connection.end();
+});
+
+
+module.exports = router; \ No newline at end of file
diff --git a/routes/basic.routes.js b/routes/basic.routes.js
index 4049a974..143db16d 100644
--- a/routes/basic.routes.js
+++ b/routes/basic.routes.js
@@ -5,26 +5,20 @@ require("dotenv").config();
const validationString = process.env.AUTHORIZATION_STRING;
router.get("/", (req, res) => {
- if (req.cookies.token) {
- jwt.verify(req.cookies.token, validationString, (err, decoded) => {
- if (err) {
- res.clearCookie("token");
- res.render("index", {
- title: 'Home'
- });
- } else {
- res.render('index', {
- title: 'Home',
- username: decoded.username
- })
- }
- });
- } else {
- res.render('index', {
- title: 'Home'
- });
- }
+ res.locals.messages = req.flash();
+ jwt.verify(req.cookies.token, validationString, (err, decoded) => {
+ if (err) {
+ res.clearCookie("token");
+ res.render("index", {
+ title: "Home"
+ });
+ } else {
+ res.render("index", {
+ title: "Home",
+ username: decoded.username
+ });
+ }
+ });
});
module.exports = router;
-
diff --git a/routes/index.js b/routes/index.js
index ac3048f4..ad5506f0 100644
--- a/routes/index.js
+++ b/routes/index.js
@@ -1,8 +1,10 @@
const router = require("express").Router();
const home = require('./basic.routes');
+const auth = require('./auth.routes');
const api = require('./api');
router.use('/', home);
+router.use('/auth', auth);
router.use('/api', api);
module.exports = router;
diff --git a/server.js b/server.js
index 93298d79..5946aba5 100644
--- a/server.js
+++ b/server.js
@@ -2,13 +2,22 @@ const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const cookieParser = require('cookie-parser');
+const flash = require('connect-flash');
+const expressSession = require('express-session');
const app = express();
const port = process.env.PORT || 3000;
+require("dotenv").config();
// Middleware
app.use(cors());
-app.use(bodyParser.json());
+app.use(express.json());
app.use(cookieParser());
+app.use(express.urlencoded({ extended: true }));
+app.use(expressSession({
+ cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 },
+ secret: process.env.AUTHORIZATION_STRING,
+}));
+app.use(flash());
// Set Template Engine
app.set("view engine", "ejs");
diff --git a/views/partials/sidebar.ejs b/views/partials/sidebar.ejs
index 55b1412b..376a5552 100644
--- a/views/partials/sidebar.ejs
+++ b/views/partials/sidebar.ejs
@@ -3,21 +3,23 @@
<h1>That Computer Scientist</h1>
<!-- Login Box -->
</a>
- <% if (username) { %>
+ <% if (locals.username) { %>
<div class="login-box">
<p>Welcome, <%= username %>!</p>
- <a href="/logout">Logout</a>
+ <a href="/auth/logout">Logout</a>
</div>
<% } else { %>
- <form method="post" onsubmit="event.preventDefault();">
+ <form method="post" action="/auth/login">
<fieldset>
<legend>Login Area</legend>
<label for="username">Username</label>
<input type="text" id="username" name="username" placeholder="Username" autocomplete="off">
<label for="password">Password</label>
<input type="password" id="password" name="password" placeholder="Password">
+ <% if (locals.messages) { %>
+ <p class="error"><%= messages.error %></p>
+ <% } %>
<input type="submit" value="Login">
- <a href="/register">Register</a>
</fieldset>
</form>
<% } %>