From 548eb040fc88909adf062c379dbd41df5ca42c3c Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 19:24:08 -0500 Subject: [PATCH 01/10] finished db find --- api/auth/auth-middleware.js | 1 + api/users/users-model.js | 8 +- package-lock.json | 188 ++++++++++++++++++++++++++++++++++++ package.json | 1 + 4 files changed, 197 insertions(+), 1 deletion(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index c603d37c7..466864e92 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -16,6 +16,7 @@ const restricted = (req, res, next) => { Put the decoded token in the req object, to make life easier for middlewares downstream! */ + next() } const only = role_name => (req, res, next) => { diff --git a/api/users/users-model.js b/api/users/users-model.js index 7a2064834..f181e7e0e 100644 --- a/api/users/users-model.js +++ b/api/users/users-model.js @@ -1,6 +1,12 @@ const db = require('../../data/db-config.js'); -function find() { +async function find() { + + const users = db('users as u') + .select('u.user_id', 'u.username', 'r.role_name') + .join('roles as r', 'r.role_id', 'u.role_id') + + return users /** You will need to join two tables. Resolves to an ARRAY with all users. diff --git a/package-lock.json b/package-lock.json index 4c7839920..cc7c65ff3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "cors": "^2.8.5", "express": "^4.17.1", "helmet": "^4.6.0", + "jsonwebtoken": "^8.5.1", "knex": "^0.95.11", "sqlite3": "^5.0.2" }, @@ -1739,6 +1740,11 @@ "node-int64": "^0.4.0" } }, + "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": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2396,6 +2402,14 @@ "safer-buffer": "^2.1.0" } }, + "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", @@ -4623,6 +4637,35 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "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": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4638,6 +4681,25 @@ "verror": "1.10.0" } }, + "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/jwt-decode": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", @@ -4769,12 +4831,47 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "node_modules/lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -8613,6 +8710,11 @@ "node-int64": "^0.4.0" } }, + "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": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -9122,6 +9224,14 @@ "safer-buffer": "^2.1.0" } }, + "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", @@ -10849,6 +10959,30 @@ "minimist": "^1.2.5" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "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": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -10861,6 +10995,25 @@ "verror": "1.10.0" } }, + "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" + } + }, "jwt-decode": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", @@ -10953,12 +11106,47 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", diff --git a/package.json b/package.json index 2252417b8..527c1ff6b 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "cors": "^2.8.5", "express": "^4.17.1", "helmet": "^4.6.0", + "jsonwebtoken": "^8.5.1", "knex": "^0.95.11", "sqlite3": "^5.0.2" }, From cdf23170758ffdb2cf7a55e00a16fb607e1ba385 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 19:37:33 -0500 Subject: [PATCH 02/10] wrote db find by --- api/auth/auth-middleware.js | 1 + api/users/users-model.js | 49 +++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index 466864e92..a9e63f3c5 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -30,6 +30,7 @@ const only = role_name => (req, res, next) => { Pull the decoded token from the req object, to avoid verifying it again! */ + next() } diff --git a/api/users/users-model.js b/api/users/users-model.js index f181e7e0e..e51c622e6 100644 --- a/api/users/users-model.js +++ b/api/users/users-model.js @@ -1,12 +1,11 @@ -const db = require('../../data/db-config.js'); +const db = require("../../data/db-config.js"); async function find() { + const users = db("users as u") + .select("u.user_id", "u.username", "r.role_name") + .join("roles as r", "r.role_id", "u.role_id"); - const users = db('users as u') - .select('u.user_id', 'u.username', 'r.role_name') - .join('roles as r', 'r.role_id', 'u.role_id') - - return users + return users; /** You will need to join two tables. Resolves to an ARRAY with all users. @@ -26,7 +25,14 @@ async function find() { */ } -function findBy(filter) { +async function findBy(filter) { + const user = await db("users as u") + .select("u.user_id", "u.username", "u.password", "r.role_name") + .join("roles as r", "r.role_id", "u.role_id") + .where(filter); + + return user; + /** You will need to join two tables. Resolves to an ARRAY with all users that match the filter condition. @@ -73,21 +79,26 @@ function findById(user_id) { "role_name": "team lead" } */ -async function add({ username, password, role_name }) { // done for you - let created_user_id - await db.transaction(async trx => { - let role_id_to_use - const [role] = await trx('roles').where('role_name', role_name) +async function add({ username, password, role_name }) { + // done for you + let created_user_id; + await db.transaction(async (trx) => { + let role_id_to_use; + const [role] = await trx("roles").where("role_name", role_name); if (role) { - role_id_to_use = role.role_id + role_id_to_use = role.role_id; } else { - const [role_id] = await trx('roles').insert({ role_name: role_name }) - role_id_to_use = role_id + const [role_id] = await trx("roles").insert({ role_name: role_name }); + role_id_to_use = role_id; } - const [user_id] = await trx('users').insert({ username, password, role_id: role_id_to_use }) - created_user_id = user_id - }) - return findById(created_user_id) + const [user_id] = await trx("users").insert({ + username, + password, + role_id: role_id_to_use, + }); + created_user_id = user_id; + }); + return findById(created_user_id); } module.exports = { From 1499f2ec5049bdcb861e0b202efc919e802764d4 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 19:51:46 -0500 Subject: [PATCH 03/10] findbyid is working --- api/users/users-model.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/api/users/users-model.js b/api/users/users-model.js index e51c622e6..3524a9d68 100644 --- a/api/users/users-model.js +++ b/api/users/users-model.js @@ -48,7 +48,14 @@ async function findBy(filter) { */ } -function findById(user_id) { +async function findById(user_id) { + const user = await db('users as u') + .select('u.user_id', 'u.username', 'r.role_name') + .join('roles as r', 'r.role_id', 'u.role_id') + .where('u.user_id', user_id) + + return user + /** You will need to join two tables. Resolves to the user with the given user_id. From 104f116f3dd97099b653fbbdf66cd7f7e577af09 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 20:30:26 -0500 Subject: [PATCH 04/10] validates role name --- api/auth/auth-middleware.js | 30 ++++++++++++++++++++---------- api/auth/auth-router.js | 4 ++-- api/secrets/index.js | 4 ++-- api/users/users-model.js | 12 ++++++------ index.js | 3 ++- package-lock.json | 14 ++++++++++++++ package.json | 3 ++- 7 files changed, 48 insertions(+), 22 deletions(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index a9e63f3c5..71b49e1fc 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -16,10 +16,10 @@ const restricted = (req, res, next) => { Put the decoded token in the req object, to make life easier for middlewares downstream! */ - next() -} + next(); +}; -const only = role_name => (req, res, next) => { +const only = (role_name) => (req, res, next) => { /* If the user does not provide a token in the Authorization header with a role_name inside its payload matching the role_name passed to this function as its argument: @@ -30,9 +30,8 @@ const only = role_name => (req, res, next) => { Pull the decoded token from the req object, to avoid verifying it again! */ - next() -} - + next(); +}; const checkUsernameExists = (req, res, next) => { /* @@ -42,10 +41,21 @@ const checkUsernameExists = (req, res, next) => { "message": "Invalid credentials" } */ -} - +}; const validateRoleName = (req, res, next) => { + const trimmedRole = req.body.role_name.trim(); + if (!trimmedRole) { + req.role_name = 'student' + next() + } else if (trimmedRole === 'adming'){ + next({ status: 422, message: 'Role name can not be admin'}) + } else if (trimmedRole.length > 32) { + next({ status: 422, message: 'Role name can not be longer than 32 chars'}) + } else { + req.role_name = trimmedRole + next() + } /* If the role_name in the body is valid, set req.role_name to be the trimmed string and proceed. @@ -64,11 +74,11 @@ const validateRoleName = (req, res, next) => { "message": "Role name can not be longer than 32 chars" } */ -} +}; module.exports = { restricted, checkUsernameExists, validateRoleName, only, -} +}; diff --git a/api/auth/auth-router.js b/api/auth/auth-router.js index c723c2da8..1d89f3415 100644 --- a/api/auth/auth-router.js +++ b/api/auth/auth-router.js @@ -1,5 +1,6 @@ const router = require("express").Router(); -const { checkUsernameExists, validateRoleName } = require('./auth-middleware'); +const bcrypt = require("bcryptjs"); +const { checkUsernameExists, validateRoleName } = require("./auth-middleware"); const { JWT_SECRET } = require("../secrets"); // use this secret! router.post("/register", validateRoleName, (req, res, next) => { @@ -16,7 +17,6 @@ router.post("/register", validateRoleName, (req, res, next) => { */ }); - router.post("/login", checkUsernameExists, (req, res, next) => { /** [POST] /api/auth/login { "username": "sue", "password": "1234" } diff --git a/api/secrets/index.js b/api/secrets/index.js index 1a125b81e..e9b4cbeac 100644 --- a/api/secrets/index.js +++ b/api/secrets/index.js @@ -7,5 +7,5 @@ developers cloning this repo won't be able to run the project as is. */ module.exports = { - -} + JWT_SECRET: process.env.JWT_SECRET || "shh", +}; diff --git a/api/users/users-model.js b/api/users/users-model.js index 3524a9d68..aa91b8707 100644 --- a/api/users/users-model.js +++ b/api/users/users-model.js @@ -49,12 +49,12 @@ async function findBy(filter) { } async function findById(user_id) { - const user = await db('users as u') - .select('u.user_id', 'u.username', 'r.role_name') - .join('roles as r', 'r.role_id', 'u.role_id') - .where('u.user_id', user_id) - - return user + const user = await db("users as u") + .select("u.user_id", "u.username", "r.role_name") + .join("roles as r", "r.role_id", "u.role_id") + .where("user_id", user_id); + + return user; /** You will need to join two tables. diff --git a/index.js b/index.js index 71f14885b..b96a10d8f 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ -const server = require('./api/server.js'); +require("dotenv").config(); +const server = require("./api/server.js"); const PORT = process.env.PORT || 9000; diff --git a/package-lock.json b/package-lock.json index cc7c65ff3..566eff1dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "bcryptjs": "^2.4.3", "cors": "^2.8.5", + "dotenv": "^10.0.0", "express": "^4.17.1", "helmet": "^4.6.0", "jsonwebtoken": "^8.5.1", @@ -2386,6 +2387,14 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, "node_modules/duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -9208,6 +9217,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", diff --git a/package.json b/package.json index 527c1ff6b..b6b426249 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "migrate": "knex migrate:latest", "rollback": "knex migrate:rollback", "seed": "knex seed:run", - "test": "cross-env NODE_ENV=testing jest --verbose --runInBand" + "test": "cross-env NODE_ENV=testing jest --watchAll --verbose --runInBand" }, "devDependencies": { "@types/jest": "^27.0.2", @@ -21,6 +21,7 @@ "dependencies": { "bcryptjs": "^2.4.3", "cors": "^2.8.5", + "dotenv": "^10.0.0", "express": "^4.17.1", "helmet": "^4.6.0", "jsonwebtoken": "^8.5.1", From 75f8346b701532d5d9610b8bf79b8dfbad368be9 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 20:41:18 -0500 Subject: [PATCH 05/10] registration endpoint working --- api/auth/auth-middleware.js | 4 ++-- api/auth/auth-router.js | 17 ++++++++++++++++- data/auth.db3 | Bin 32768 -> 32768 bytes 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index 71b49e1fc..ac14edb74 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -46,14 +46,14 @@ const checkUsernameExists = (req, res, next) => { const validateRoleName = (req, res, next) => { const trimmedRole = req.body.role_name.trim(); if (!trimmedRole) { - req.role_name = 'student' + req.body.role_name = 'student' next() } else if (trimmedRole === 'adming'){ next({ status: 422, message: 'Role name can not be admin'}) } else if (trimmedRole.length > 32) { next({ status: 422, message: 'Role name can not be longer than 32 chars'}) } else { - req.role_name = trimmedRole + req.body.role_name = trimmedRole next() } /* diff --git a/api/auth/auth-router.js b/api/auth/auth-router.js index 1d89f3415..95cc8f764 100644 --- a/api/auth/auth-router.js +++ b/api/auth/auth-router.js @@ -1,9 +1,24 @@ const router = require("express").Router(); const bcrypt = require("bcryptjs"); +const Users = require("./../users/users-model"); const { checkUsernameExists, validateRoleName } = require("./auth-middleware"); const { JWT_SECRET } = require("../secrets"); // use this secret! -router.post("/register", validateRoleName, (req, res, next) => { +router.post("/register", validateRoleName, async (req, res, next) => { + let user = req.body; + + const rounds = process.env.BCRYPT_ROUNDS || 8; + const hash = bcrypt.hashSync(user.password, rounds); + + user.password = hash; + + try { + const newUser = await Users.add(user); + res.status(201).json(newUser); + } catch (err) { + next(err); + } + /** [POST] /api/auth/register { "username": "anna", "password": "1234", "role_name": "angel" } diff --git a/data/auth.db3 b/data/auth.db3 index 568bc34c7877fd4d47b42a561434f8885c50ca00..1a0e7d8db2161a61c62c91ae66a8f8666a1ffa17 100644 GIT binary patch delta 256 zcmZo@U}|V!njp=XHBrWyF>7N&gFYk6=7;*q20Sc$w;A|%@)z-i?Kg zLAa5Xu{beT#VAq5z(OU|B)G&WvBWE>!l^vfDJvz}G|kOCH8e0UGB-RpB-uROH!929 zr`*uk+aofusNAgBrzF>z*@u~pK^|yMc4A3JYEfohD%3RRDg#SX*L?kuY(sO$e79UL zS5sG~(p;l7{Q`ft{2=i>|D-6>KquGqbeFQwvY?{!a^FIWLZ-=u`IC8A_<^qd$^V%D mHvh-X0tKh}RoR(^K`v$CWtKV`3w2g`II&bB%J1}Pb*GL zNl#QUN>nj4Q1N%FvUK$;FZ1#A&GbvmNscTu@+$NQL4B2L7M?AA#`r pW`Tm!{Hp1REI>(|`;~uuaVD%)*StrKwD8%)*>N5dgiUOOOBn From 89013f3161e3639782dd01b10efbecb30f0105e8 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 21:40:49 -0500 Subject: [PATCH 06/10] can check username exits and login --- api/auth/auth-middleware.js | 16 +++++++++++++++- api/auth/auth-router.js | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index ac14edb74..38eb58e64 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -1,4 +1,5 @@ const { JWT_SECRET } = require("../secrets"); // use this secret! +const Users = require('./../users/users-model'); const restricted = (req, res, next) => { /* @@ -33,7 +34,20 @@ const only = (role_name) => (req, res, next) => { next(); }; -const checkUsernameExists = (req, res, next) => { +const checkUsernameExists = async (req, res, next) => { +try{ + const { username } = req.body + const user = await Users.findBy({ username }) + if(user.length === 0){ + next({ status: 401, message: "Invalid credentials"}) + } else { + req.userFromDb = user[0] + next() + } +} catch(err){ + next(err) +} + /* If the username in req.body does NOT exist in the database status 401 diff --git a/api/auth/auth-router.js b/api/auth/auth-router.js index 95cc8f764..7e992079d 100644 --- a/api/auth/auth-router.js +++ b/api/auth/auth-router.js @@ -1,6 +1,7 @@ const router = require("express").Router(); const bcrypt = require("bcryptjs"); const Users = require("./../users/users-model"); +const jwt = require("jsonwebtoken"); const { checkUsernameExists, validateRoleName } = require("./auth-middleware"); const { JWT_SECRET } = require("../secrets"); // use this secret! @@ -33,6 +34,23 @@ router.post("/register", validateRoleName, async (req, res, next) => { }); router.post("/login", checkUsernameExists, (req, res, next) => { + const { username, password } = req.body; + const { userFromDb } = req; + + if (bcrypt.compareSync(password, userFromDb.password)) { + const payload = { + subject: userFromDb.user_id, + username: userFromDb.username, + role_name: userFromDb.role_name, + }; + const options = { + expiresIn: "1d", + }; + const token = jwt.sign(payload, JWT_SECRET, options); + res.status(200).json({ message: `${username} is back!`, token }); + } else { + next({ status: 401, message: "Invalid credentials" }); + } /** [POST] /api/auth/login { "username": "sue", "password": "1234" } From cc02e0eb28f24dc2d4f352fccb6a4a3334b61d6e Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 21:47:10 -0500 Subject: [PATCH 07/10] fixed role name validation --- api/auth/auth-middleware.js | 54 +++++++++++++++++++++--------------- api/auth/auth-router.js | 2 +- data/auth.db3 | Bin 32768 -> 32768 bytes 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index 38eb58e64..91e0bd2f6 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -1,5 +1,5 @@ const { JWT_SECRET } = require("../secrets"); // use this secret! -const Users = require('./../users/users-model'); +const Users = require("./../users/users-model"); const restricted = (req, res, next) => { /* @@ -35,19 +35,19 @@ const only = (role_name) => (req, res, next) => { }; const checkUsernameExists = async (req, res, next) => { -try{ - const { username } = req.body - const user = await Users.findBy({ username }) - if(user.length === 0){ - next({ status: 401, message: "Invalid credentials"}) - } else { - req.userFromDb = user[0] - next() + try { + const { username } = req.body; + const user = await Users.findBy({ username }); + if (user.length === 0) { + next({ status: 401, message: "Invalid credentials" }); + } else { + req.userFromDb = user[0]; + next(); + } + } catch (err) { + next(err); } -} catch(err){ - next(err) -} - + /* If the username in req.body does NOT exist in the database status 401 @@ -58,17 +58,25 @@ try{ }; const validateRoleName = (req, res, next) => { - const trimmedRole = req.body.role_name.trim(); - if (!trimmedRole) { - req.body.role_name = 'student' - next() - } else if (trimmedRole === 'adming'){ - next({ status: 422, message: 'Role name can not be admin'}) - } else if (trimmedRole.length > 32) { - next({ status: 422, message: 'Role name can not be longer than 32 chars'}) + if (req.body.role_name === undefined) { + req.body.role_name = "student"; + next(); } else { - req.body.role_name = trimmedRole - next() + const trimmedRole = req.body.role_name.trim(); + if (!trimmedRole) { + req.body.role_name = "student"; + next(); + } else if (trimmedRole === "admin") { + next({ status: 422, message: "Role name can not be admin" }); + } else if (trimmedRole.length > 32) { + next({ + status: 422, + message: "Role name can not be longer than 32 chars", + }); + } else { + req.body.role_name = trimmedRole; + next(); + } } /* If the role_name in the body is valid, set req.role_name to be the trimmed string and proceed. diff --git a/api/auth/auth-router.js b/api/auth/auth-router.js index 7e992079d..0cdb6b39d 100644 --- a/api/auth/auth-router.js +++ b/api/auth/auth-router.js @@ -15,7 +15,7 @@ router.post("/register", validateRoleName, async (req, res, next) => { try { const newUser = await Users.add(user); - res.status(201).json(newUser); + res.status(201).json(newUser[0]); } catch (err) { next(err); } diff --git a/data/auth.db3 b/data/auth.db3 index 1a0e7d8db2161a61c62c91ae66a8f8666a1ffa17..83bcfcd04e53ceac7790ea305589d31efb9cd005 100644 GIT binary patch delta 161 zcmZo@U}|V!njp=XJyFJ)F?(Y|gFYkc=7;*q1_G>nlNtDT@)z7N&gFYk6=7;*q1_CU6w;A|%@)zq$JBEswmaZugK3W zrQ9@=g@J+5(y)=0F+DLQF)gJyJuR^~W%KPkO-3FTexN-+`5*J&=Kr`^px`h+2S_fh LI5B1N?Rr%Jq`Wl1 From 5f2954f31d403c75f3727b279480e9a97f5600b0 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 22:07:55 -0500 Subject: [PATCH 08/10] restricted middleware set up --- api/auth/auth-middleware.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index 91e0bd2f6..5cb1f390d 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -1,7 +1,25 @@ +const jwt = require("jsonwebtoken"); const { JWT_SECRET } = require("../secrets"); // use this secret! const Users = require("./../users/users-model"); const restricted = (req, res, next) => { + const token = req.headers.authorization; + + if (!token) { + next({ status: 401, message: "Token required" }); + } else { + jwt.verify(token, JWT_SECRET, (err, decoded) => { + if (err) { + next({ + status: 401, + message: "Token invalid", + }); + } else { + req.decodedJwt = decoded; + next(); + } + }); + } /* If the user does not provide a token in the Authorization header: status 401 @@ -17,7 +35,6 @@ const restricted = (req, res, next) => { Put the decoded token in the req object, to make life easier for middlewares downstream! */ - next(); }; const only = (role_name) => (req, res, next) => { From 270ca3dc8ad3369b1f3623529c69f87cb531cfc4 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 9 Nov 2021 22:13:59 -0500 Subject: [PATCH 09/10] finished MVP --- api/auth/auth-middleware.js | 13 +++++++++++-- api/users/users-router.js | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index 5cb1f390d..eac2cf4e8 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -10,7 +10,7 @@ const restricted = (req, res, next) => { } else { jwt.verify(token, JWT_SECRET, (err, decoded) => { if (err) { - next({ + next({ status: 401, message: "Token invalid", }); @@ -38,6 +38,15 @@ const restricted = (req, res, next) => { }; const only = (role_name) => (req, res, next) => { + + if(req.decodedJwt.role_name !== role_name) { + next({ + status: 403, + message: "This is not for you" + }) + } else { + next() + } /* If the user does not provide a token in the Authorization header with a role_name inside its payload matching the role_name passed to this function as its argument: @@ -48,7 +57,7 @@ const only = (role_name) => (req, res, next) => { Pull the decoded token from the req object, to avoid verifying it again! */ - next(); + // next(); }; const checkUsernameExists = async (req, res, next) => { diff --git a/api/users/users-router.js b/api/users/users-router.js index 48baddc06..b293b9152 100644 --- a/api/users/users-router.js +++ b/api/users/users-router.js @@ -43,7 +43,7 @@ router.get("/", restricted, (req, res, next) => { // done for you router.get("/:user_id", restricted, only('admin'), (req, res, next) => { // done for you Users.findById(req.params.user_id) .then(user => { - res.json(user); + res.json(user[0]); }) .catch(next); }); From ce5861f1304c847ebd1871d182b80cb8c2b1976c Mon Sep 17 00:00:00 2001 From: Kat Date: Wed, 10 Nov 2021 11:46:21 -0500 Subject: [PATCH 10/10] cleaned up --- api/auth/auth-middleware.js | 101 +++++++++++++++++----------------- api/auth/auth-router.js | 37 ++++++------- api/secrets/index.js | 8 +-- api/users/users-model.js | 105 ++++++++++++++++++------------------ api/users/users-router.js | 38 +++++++------ 5 files changed, 151 insertions(+), 138 deletions(-) diff --git a/api/auth/auth-middleware.js b/api/auth/auth-middleware.js index eac2cf4e8..779f6b2df 100644 --- a/api/auth/auth-middleware.js +++ b/api/auth/auth-middleware.js @@ -1,5 +1,5 @@ const jwt = require("jsonwebtoken"); -const { JWT_SECRET } = require("../secrets"); // use this secret! +const { JWT_SECRET } = require("../secrets"); const Users = require("./../users/users-model"); const restricted = (req, res, next) => { @@ -10,6 +10,7 @@ const restricted = (req, res, next) => { } else { jwt.verify(token, JWT_SECRET, (err, decoded) => { if (err) { + delete req.decodedJwt; next({ status: 401, message: "Token invalid", @@ -20,44 +21,17 @@ const restricted = (req, res, next) => { } }); } - /* - If the user does not provide a token in the Authorization header: - status 401 - { - "message": "Token required" - } - - If the provided token does not verify: - status 401 - { - "message": "Token invalid" - } - - Put the decoded token in the req object, to make life easier for middlewares downstream! - */ }; const only = (role_name) => (req, res, next) => { - - if(req.decodedJwt.role_name !== role_name) { + if (req.decodedJwt.role_name !== role_name) { next({ status: 403, - message: "This is not for you" - }) + message: "This is not for you", + }); } else { - next() + next(); } - /* - If the user does not provide a token in the Authorization header with a role_name - inside its payload matching the role_name passed to this function as its argument: - status 403 - { - "message": "This is not for you" - } - - Pull the decoded token from the req object, to avoid verifying it again! - */ - // next(); }; const checkUsernameExists = async (req, res, next) => { @@ -73,14 +47,6 @@ const checkUsernameExists = async (req, res, next) => { } catch (err) { next(err); } - - /* - If the username in req.body does NOT exist in the database - status 401 - { - "message": "Invalid credentials" - } - */ }; const validateRoleName = (req, res, next) => { @@ -104,7 +70,52 @@ const validateRoleName = (req, res, next) => { next(); } } - /* +}; + +module.exports = { + restricted, + checkUsernameExists, + validateRoleName, + only, +}; + +/* RESTRICTED + If the user does not provide a token in the Authorization header: + status 401 + { + "message": "Token required" + } + + If the provided token does not verify: + status 401 + { + "message": "Token invalid" + } + + Put the decoded token in the req object, to make life easier for middlewares downstream! + */ + +/*ONLY + If the user does not provide a token in the Authorization header with a role_name + inside its payload matching the role_name passed to this function as its argument: + status 403 + { + "message": "This is not for you" + } + + Pull the decoded token from the req object, to avoid verifying it again! + */ +// next(); + +/* CHECK USERNAME EXISTS + If the username in req.body does NOT exist in the database + status 401 + { + "message": "Invalid credentials" + } + */ + +/* VALIDATE ROLE NAME If the role_name in the body is valid, set req.role_name to be the trimmed string and proceed. If role_name is missing from req.body, or if after trimming it is just an empty string, @@ -122,11 +133,3 @@ const validateRoleName = (req, res, next) => { "message": "Role name can not be longer than 32 chars" } */ -}; - -module.exports = { - restricted, - checkUsernameExists, - validateRoleName, - only, -}; diff --git a/api/auth/auth-router.js b/api/auth/auth-router.js index 0cdb6b39d..53b7a1187 100644 --- a/api/auth/auth-router.js +++ b/api/auth/auth-router.js @@ -3,7 +3,7 @@ const bcrypt = require("bcryptjs"); const Users = require("./../users/users-model"); const jwt = require("jsonwebtoken"); const { checkUsernameExists, validateRoleName } = require("./auth-middleware"); -const { JWT_SECRET } = require("../secrets"); // use this secret! +const { JWT_SECRET } = require("../secrets"); router.post("/register", validateRoleName, async (req, res, next) => { let user = req.body; @@ -15,22 +15,10 @@ router.post("/register", validateRoleName, async (req, res, next) => { try { const newUser = await Users.add(user); - res.status(201).json(newUser[0]); + res.status(201).json(newUser); } catch (err) { next(err); } - - /** - [POST] /api/auth/register { "username": "anna", "password": "1234", "role_name": "angel" } - - response: - status 201 - { - "user"_id: 3, - "username": "anna", - "role_name": "angel" - } - */ }); router.post("/login", checkUsernameExists, (req, res, next) => { @@ -51,7 +39,23 @@ router.post("/login", checkUsernameExists, (req, res, next) => { } else { next({ status: 401, message: "Invalid credentials" }); } - /** +}); + +module.exports = router; + +/** + [POST] /api/auth/register { "username": "anna", "password": "1234", "role_name": "angel" } + + response: + status 201 + { + "user"_id: 3, + "username": "anna", + "role_name": "angel" + } + */ + +/** [POST] /api/auth/login { "username": "sue", "password": "1234" } response: @@ -70,6 +74,3 @@ router.post("/login", checkUsernameExists, (req, res, next) => { "role_name": "admin" // the role of the authenticated user } */ -}); - -module.exports = router; diff --git a/api/secrets/index.js b/api/secrets/index.js index e9b4cbeac..155607a81 100644 --- a/api/secrets/index.js +++ b/api/secrets/index.js @@ -1,3 +1,8 @@ +module.exports = { + JWT_SECRET: process.env.JWT_SECRET || "shh", +}; + + /** Fix this module so other modules can require JWT_SECRET into them. Use the || operator to fall back to the string "shh" to handle the situation @@ -6,6 +11,3 @@ If no fallback is provided, TESTS WON'T WORK and other developers cloning this repo won't be able to run the project as is. */ -module.exports = { - JWT_SECRET: process.env.JWT_SECRET || "shh", -}; diff --git a/api/users/users-model.js b/api/users/users-model.js index aa91b8707..a38736ca6 100644 --- a/api/users/users-model.js +++ b/api/users/users-model.js @@ -6,7 +6,57 @@ async function find() { .join("roles as r", "r.role_id", "u.role_id"); return users; - /** +} + +async function findBy(filter) { + const user = await db("users as u") + .select("u.user_id", "u.username", "u.password", "r.role_name") + .join("roles as r", "r.role_id", "u.role_id") + .where(filter); + + return user; +} + +async function findById(user_id) { + const user = await db("users as u") + .select("u.user_id", "u.username", "r.role_name") + .join("roles as r", "r.role_id", "u.role_id") + .where("user_id", user_id); + + return user[0]; +} + +async function add({ username, password, role_name }) { + // done for you + let created_user_id; + await db.transaction(async (trx) => { + let role_id_to_use; + const [role] = await trx("roles").where("role_name", role_name); + if (role) { + role_id_to_use = role.role_id; + } else { + const [role_id] = await trx("roles").insert({ role_name: role_name }); + role_id_to_use = role_id; + } + const [user_id] = await trx("users").insert({ + username, + password, + role_id: role_id_to_use, + }); + created_user_id = user_id; + }); + + return findById(created_user_id); +} + +module.exports = { + add, + find, + findBy, + findById, +}; + +/** FIND You will need to join two tables. Resolves to an ARRAY with all users. @@ -23,17 +73,8 @@ async function find() { } ] */ -} - -async function findBy(filter) { - const user = await db("users as u") - .select("u.user_id", "u.username", "u.password", "r.role_name") - .join("roles as r", "r.role_id", "u.role_id") - .where(filter); - - return user; - /** +/** FINDBY You will need to join two tables. Resolves to an ARRAY with all users that match the filter condition. @@ -46,17 +87,8 @@ async function findBy(filter) { } ] */ -} - -async function findById(user_id) { - const user = await db("users as u") - .select("u.user_id", "u.username", "r.role_name") - .join("roles as r", "r.role_id", "u.role_id") - .where("user_id", user_id); - - return user; - /** +/** FINDBYID You will need to join two tables. Resolves to the user with the given user_id. @@ -66,9 +98,8 @@ async function findById(user_id) { "role_name": "instructor" } */ -} -/** +/** ADD Creating a user requires a single insert (into users) if the role record with the given role_name already exists in the db, or two inserts (into roles and then into users) if the given role_name does not exist yet. @@ -86,31 +117,3 @@ async function findById(user_id) { "role_name": "team lead" } */ -async function add({ username, password, role_name }) { - // done for you - let created_user_id; - await db.transaction(async (trx) => { - let role_id_to_use; - const [role] = await trx("roles").where("role_name", role_name); - if (role) { - role_id_to_use = role.role_id; - } else { - const [role_id] = await trx("roles").insert({ role_name: role_name }); - role_id_to_use = role_id; - } - const [user_id] = await trx("users").insert({ - username, - password, - role_id: role_id_to_use, - }); - created_user_id = user_id; - }); - return findById(created_user_id); -} - -module.exports = { - add, - find, - findBy, - findById, -}; diff --git a/api/users/users-router.js b/api/users/users-router.js index b293b9152..8fbe62867 100644 --- a/api/users/users-router.js +++ b/api/users/users-router.js @@ -2,6 +2,26 @@ const router = require("express").Router(); const Users = require("./users-model.js"); const { restricted, only } = require("../auth/auth-middleware.js"); + +router.get("/", restricted, (req, res, next) => { + Users.find() + .then((users) => { + res.json(users); + }) + .catch(next); +}); + + +router.get("/:user_id", restricted, only("admin"), (req, res, next) => { + Users.findById(req.params.user_id) + .then((user) => { + res.json(user); + }) + .catch(next); +}); + +module.exports = router; + /** [GET] /api/users @@ -17,15 +37,8 @@ const { restricted, only } = require("../auth/auth-middleware.js"); } ] */ -router.get("/", restricted, (req, res, next) => { // done for you - Users.find() - .then(users => { - res.json(users); - }) - .catch(next); -}); -/** + /** [GET] /api/users/:user_id This endpoint is RESTRICTED: only authenticated users with role 'admin' @@ -40,12 +53,3 @@ router.get("/", restricted, (req, res, next) => { // done for you } ] */ -router.get("/:user_id", restricted, only('admin'), (req, res, next) => { // done for you - Users.findById(req.params.user_id) - .then(user => { - res.json(user[0]); - }) - .catch(next); -}); - -module.exports = router;